bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/util/Windows_WMI_Metadata.linq (about) 1 <Query Kind="Program"> 2 <Reference><RuntimeDirectory>\System.Management.dll</Reference> 3 <Reference><RuntimeDirectory>\System.Configuration.Install.dll</Reference> 4 <Reference><RuntimeDirectory>\Microsoft.JScript.dll</Reference> 5 <Namespace>System.Management</Namespace> 6 </Query> 7 8 //LinqPad script used to codegen metadata for WMI classes 9 void Main() 10 { 11 //Follow steps 1-4 to generate the GO code from a wmi class 12 //See step 1 at bottom of page. 13 string strPrefix = "descWinSystem"; //Step 2: Set this to the prefix you want to use for metadata 14 string server = "localhost"; //Step 3: Change this to another server if you need specific WMI information 15 string WMIClass = "Win32_PerfRawData_PerfOS_System"; //Step 4: WMI class for which you want to find metadata 16 bool GenerateFromMSDNClass = true; //Set to true if using an MSDN class in step 1. Set to false if text is an existing Add/AddTS block of code. 17 18 //Load details about WMI Class and properties 19 var htWMIDetails = new Dictionary<string,WMIDetail>(StringComparer.InvariantCultureIgnoreCase); 20 ManagementScope s = new ManagementScope(string.Format("\\\\{0}\\root\\cimv2", server)); 21 ManagementPath p = new ManagementPath(WMIClass); 22 ObjectGetOptions o = new ObjectGetOptions(null, System.TimeSpan.MaxValue, true); 23 ManagementClass osClass = new ManagementClass(s, p, o); 24 osClass.Options.UseAmendedQualifiers = true; //Adds Description details (which are missing otherwise) 25 //osClass.Properties.Dump(); 26 foreach (PropertyData property in osClass.Properties) 27 { 28 WMIDetail d = WMIDetail.FromPropertyData(property); 29 //d.Dump(); 30 htWMIDetails.Add(property.Name, d); 31 } 32 //htWMIDetails.Values.Dump("WMI Details"); 33 if(string.IsNullOrWhiteSpace(text)){ 34 StringBuilder sbText = new StringBuilder(); 35 foreach(var key in htWMIDetails.Keys){ 36 sbText.AppendFormat("{0};\r\n",key); 37 } 38 text = sbText.ToString(); 39 } 40 41 //text.Dump("Input lines pre transform"); 42 var PropertiesUsed = new List<string>(); 43 var matches = new List<Match>(); 44 int countLines = -1; 45 using (StringReader sr = new StringReader(text)) { 46 string line; 47 while ((line = sr.ReadLine()) != null) { 48 countLines++; 49 if(GenerateFromMSDNClass){ 50 //Regex to parse metrics out of the class ___ : ____ found on MSDN pages 51 var m = Regex.Match(line, @"(?<wmiName>[^ ;\{\}]+);$", RegexOptions.Multiline); 52 if(m.Success){ 53 matches.Add(m); 54 PropertiesUsed.Add(m.Groups["wmiName"].Value); 55 } 56 } else { 57 //Regex to parse out the details from an Add or AddTS line in a *_windows.go. Change ""(?<metric>[^"",]*)"" to ""?(?<metric>[^"",]*)""? to capture osXXX based metrics 58 var m = Regex.Match(line, @"\s{0,4}Add\(&md, ""(?<metric>[^"",]*)"", v\.(?<wmiName>[a-zA-Z_]*)[^,]*, (nil|opentsdb.TagSet\{(?<tagset>[^}]*)\}), metadata\.(?<type>[^\,]*), metadata\.(?<units>[^\,]*), (""""|[a-zA-Z_]*)\)", RegexOptions.Multiline); //Get wmi details 59 if(m.Success){ 60 matches.Add(m); 61 //m.Groups.Dump(); 62 //m.Groups["tagset"].Value.Dump(); 63 var t = Regex.Match(m.Groups["tagset"].Value, @"'site': v.Name, '(?<tagkey>[^']*)': '(?<tagvalue>[^']*)'", RegexOptions.Singleline); //Get tag names 64 //t.Dump(); 65 if(t.Success){ //Use different identifier for lines with tags? 66 //result.Add(string.Format("{0}_{1}", m.Groups["wmiName"].Value,t.Groups["tagvalue"].Value)); 67 PropertiesUsed.Add(m.Groups["wmiName"].Value); 68 } else { 69 PropertiesUsed.Add(m.Groups["wmiName"].Value); 70 } 71 } 72 } 73 }//while 74 }//using 75 countLines.Dump("Total Lines pre-processing:"); 76 PropertiesUsed.Distinct().Count().Dump("Distinct WMI Properties detected:"); 77 //PropertiesUsed.Dump("WMI Properties used in the text block"); 78 79 80 if(GenerateFromMSDNClass){ 81 //Create lines for adding metric and for the GO struct 82 Console.WriteLine("//Metrics:"); 83 foreach(var m in matches){ 84 WMIDetail details; 85 if(htWMIDetails.TryGetValue(m.Groups["wmiName"].Value, out details)) { 86 Console.WriteLine("Add(&md, \"win.system.{0}\", v.{0}, tags, metadata.Counter, metadata.PerSecond, {1}{0})", details.Name,strPrefix); 87 } 88 } 89 } 90 91 //Generate const for metadata 92 var sb = new StringBuilder("Errors:\r\n"); 93 Console.WriteLine("\r\nconst ("); 94 foreach(var wmiproperty in PropertiesUsed){ 95 WMIDetail details; 96 if(htWMIDetails.TryGetValue(wmiproperty, out details)) { 97 Console.WriteLine(string.Format(" {2}{0} = \"{1}\"", details.Name,details.Description,strPrefix)); 98 } else { 99 sb.AppendLine(string.Format("Could not find WMIDetail for '{0}'. Make sure it matches the WMI Property below. (Case Sensitive)", wmiproperty)); 100 } 101 } 102 Console.WriteLine(")\r\n"); 103 if(sb.Length > 9){ 104 Console.WriteLine(sb.ToString()); 105 } 106 107 if(GenerateFromMSDNClass){ 108 Console.WriteLine("\r\ntype {0} struct {{", WMIClass); 109 foreach(var m in matches){ 110 WMIDetail details; 111 if(htWMIDetails.TryGetValue(m.Groups["wmiName"].Value, out details)) { 112 Console.WriteLine(" {0} {1}", details.Name, details.CIMTYPE); 113 } 114 } 115 Console.WriteLine("}\r\n"); 116 } else { 117 Console.WriteLine("\r\n//Insert metadata variable to Add/AddTS method call"); 118 foreach(var m in matches){ 119 var desc = string.Format("{1}{0}", m.Groups["wmiName"].Value,strPrefix); 120 var line = m.Value.Replace("\"\")",""+desc+")"); 121 line = line.Replace("metadata.Unknown", "metadata.Counter"); //Default to counter, must manually set gauge types. 122 Console.WriteLine(line); 123 } 124 } 125 126 Console.WriteLine("\r\n//WMI Counter Types"); 127 foreach(var m in matches){ 128 WMIDetail details; 129 if(htWMIDetails.TryGetValue(m.Groups["wmiName"].Value, out details)) { 130 Console.WriteLine("{0} {1}", details.CounterType, details.Name); 131 } else { 132 Console.WriteLine("No WMIDetails for {0}", m.Groups["wmiName"].Value); 133 } 134 } 135 136 htWMIDetails.Values.Dump("WMI Property Details"); 137 } 138 class WMIDetail { 139 public WMIDetail() 140 { 141 } 142 public WMIDetail(string name, string cimtype, string countertype, string description, string displayname) 143 { 144 this.Name = name; 145 this.CIMTYPE = cimtype; 146 this.CounterType = countertype; 147 this.Description = description; 148 this.DisplayName = displayname; 149 } 150 151 public static WMIDetail FromPropertyData(PropertyData property){ 152 var result = new WMIDetail(); 153 result.Name = property.Name; 154 foreach(System.Management.QualifierData item in property.Qualifiers){ 155 switch (item.Name) 156 { 157 case "CIMTYPE": 158 result.CIMTYPE = item.Value.ToString(); 159 break; 160 case "CounterType": 161 result.CounterType = item.Value.ToString(); 162 break; 163 case "Description": 164 result.Description = item.Value.ToString(); 165 break; 166 case "DisplayName": 167 result.DisplayName = item.Value.ToString(); 168 break; 169 } 170 } 171 return result; 172 } 173 174 public string Name { get; set; } 175 public string CIMTYPE { get; set; } 176 public string CounterType { get; set; } 177 public string Description { get; set; } 178 public string DisplayName { get; set; } 179 } 180 181 //Step 1: Paste MSDN class here. Remove any lines you don't want in your go struct. 182 //Step 1: Paste current block of GO "Add()" lines here. Then replace " with "" to fix escapping. 183 string text = @" 184 uint32 ExceptionDispatchesPerSec; 185 uint64 FileControlBytesPerSec; 186 uint32 FileControlOperationsPerSec; 187 uint32 FileDataOperationsPerSec; 188 uint64 FileReadBytesPerSec; 189 uint32 FileReadOperationsPerSec; 190 "; 191 //Step 1: Or use empty string for all properties 192 //string text = "";