├── doc ├── log.png ├── finish.png └── service.png ├── sample ├── Linux │ ├── writeflag │ ├── rawkvp │ ├── kvpio.py │ └── showkvp └── Windows │ └── showkvp.ps1 ├── LICENSE.md ├── src ├── Service │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── app.config │ ├── Program.cs │ ├── EnhacedMonitoringProvider.Designer.cs │ ├── EnhacedMonitoringProvider.cs │ ├── Service.csproj │ └── EnhacedMonitoringProvider.resx ├── EnhancedMonitoring │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Logging │ │ ├── LogWriter.cs │ │ ├── LogLevel.cs │ │ ├── EventLogWriter.cs │ │ ├── FileLogWriter.cs │ │ └── Logger.cs │ ├── Configuration │ │ ├── MgmtObjectType.cs │ │ ├── MgmtObjectReturnValueType.cs │ │ ├── WhereArgConfiguration.cs │ │ ├── KvpConfiguration.cs │ │ ├── PerfCounterConfiguration.cs │ │ ├── SupportedVMDetectorConfiguration.cs │ │ ├── MgmtObjectConfiguration.cs │ │ └── MonitorConfiguration.cs │ ├── WMIQueryHelper.cs │ ├── DataFormat │ │ ├── XmlDataFormatter.cs │ │ └── DataFormatHelper.cs │ ├── DataCollector │ │ ├── MgmtObject.cs │ │ ├── DynamicMemoryMgmtObject.cs │ │ └── QueryMgmtObject.cs │ ├── NamedArgumentHelper.cs │ ├── SupportedVMDetector.cs │ ├── EnhancedMonitoring.csproj │ ├── KeyValuePairWriter.cs │ └── MonitoringTask.cs ├── UnitTest │ ├── MonitorTaskTest.cs │ ├── TestToXmlExpectedOutput.xml │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── WMIQueryHelperTest.cs │ ├── SupportedVMDetectorTest.cs │ ├── DynamicMemoryMgmtObjectTest.cs │ ├── MonitorConfigurationTest.cs │ ├── DataPackingHelperTest.cs │ ├── SampleResult.xml │ ├── EventLogTest.cs │ ├── LoggerTest.cs │ ├── JSONHelper.cs │ ├── NamedArgumentHelperTest.cs │ ├── SampleMonitor.xml │ ├── FormatHelperTest.cs │ ├── KVPWriterTest.cs │ ├── MetricTest.cs │ ├── TestFileLogWriter.cs │ └── UnitTest.csproj └── EnhancedMonitoring.sln ├── SECURITY.md ├── .gitignore ├── packages └── MSI │ └── EnhancedMonitoring │ ├── Setup.wixproj │ └── Product.wxs └── README.md /doc/log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/enhanced-monitoring-service/HEAD/doc/log.png -------------------------------------------------------------------------------- /doc/finish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/enhanced-monitoring-service/HEAD/doc/finish.png -------------------------------------------------------------------------------- /doc/service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/enhanced-monitoring-service/HEAD/doc/service.png -------------------------------------------------------------------------------- /sample/Linux/writeflag: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | #Read kvp and display on screen 4 | # 5 | 6 | import io 7 | import kvpio 8 | 9 | if __name__ == "__main__": 10 | kvp = [0] * (512 + 2048) 11 | key = bytes("Enhanced_Monitoring_Supported") 12 | val = bytes("1") 13 | kvp[0: len(key)] = key[0 : len(key)] 14 | kvp[512 : 512 + len(val)] = val[0 : len(val)] 15 | b = bytearray(kvp) 16 | kvpio.write_bytes(1, b) 17 | -------------------------------------------------------------------------------- /sample/Linux/rawkvp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | #Read kvp and display on screen 4 | # 5 | 6 | import io 7 | import sys 8 | import kvpio 9 | 10 | if __name__ == '__main__': 11 | print_key = len(sys.argv) > 1 and sys.argv[1].lower() == 'key' 12 | for i in [0, 1, 2, 3, 4]: 13 | print "---------------------------------------------------------------------" 14 | print "Pool " + str(i) + ":" 15 | print "---------------------------------------------------------------------" 16 | data = kvpio.read_raw_kvp(i) 17 | for k in data: 18 | if not print_key: 19 | print str(k) + "=" + str(data[k]) 20 | else: 21 | print str(k) 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Microsoft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Service/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 |  -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 |  24 | -------------------------------------------------------------------------------- /src/Service/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Logging/LogWriter.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | 29 | namespace EnhancedMonitoring.Logging 30 | { 31 | public interface LogWriter 32 | { 33 | void Write(LogLevel level, String msg); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /sample/Linux/kvpio.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | #Read kvp and display on screen 4 | # 5 | 6 | import io 7 | 8 | def read_bytes(pool): 9 | filepath = "/var/lib/hyperv/.kvp_pool_" + str(pool) 10 | mode = 'r' 11 | c = None 12 | try: 13 | with open(filepath, mode) as F: 14 | c=F.read() 15 | F.close() 16 | except IOError, e: 17 | print e 18 | b = bytes(c) 19 | return b 20 | 21 | def bytes_to_str(b, start, end): 22 | buf = None 23 | for i in range(start, end): 24 | if ord(b[i]) == 0:#Found string end 25 | buf = bytearray(i - start) 26 | buf[:] = b[start : i] 27 | break 28 | if(buf): 29 | return buf.decode('utf-8') 30 | else: 31 | return None 32 | 33 | def read_raw_kvp(pool): 34 | b = read_bytes(pool) 35 | key_start = 0 36 | val_start = 512 37 | key_len = 512 38 | val_len = 2048 39 | step = key_len + val_len 40 | data={} 41 | while val_start < len(b): 42 | key = bytes_to_str(b, key_start, key_start + key_len) 43 | val = bytes_to_str(b, val_start, val_start + val_len) 44 | data[key] = val 45 | key_start += step 46 | val_start += step 47 | return data; 48 | 49 | def write_bytes(pool, b): 50 | filepath = "/var/lib/hyperv/.kvp_pool_" + str(pool) 51 | mode = 'wb' 52 | c = None 53 | try: 54 | with open(filepath, mode) as F: 55 | c=F.write(b) 56 | F.close() 57 | except IOError, e: 58 | print e 59 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Configuration/MgmtObjectType.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | 29 | namespace EnhancedMonitoring.Configuration 30 | { 31 | public enum MgmtObjectType 32 | { 33 | Query = 0, 34 | DynamicMemory = 1, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Configuration/MgmtObjectReturnValueType.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | 29 | namespace EnhancedMonitoring.Configuration 30 | { 31 | public enum MgmtObjectReturnValueType 32 | { 33 | Multiple = 0, 34 | Single 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Logging/LogLevel.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | 29 | namespace EnhancedMonitoring.Logging 30 | { 31 | public enum LogLevel 32 | { 33 | Verbose = -1, 34 | Info = 0, 35 | Warning = 1, 36 | Error = 2 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sample/Linux/showkvp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | #Read perf counters 4 | # 5 | 6 | import datetime 7 | import time 8 | import json 9 | import sys 10 | import base64 11 | from StringIO import StringIO 12 | import kvpio 13 | import xml.etree.ElementTree as ET 14 | 15 | def parseXML(s): 16 | xmldoc = ET.fromstring(s) 17 | return xmldoc 18 | 19 | def readDataPart(data, i): 20 | val = data.get('Enhanced_Monitoring_Metric_Data_Item_Part_' + str(i), None) 21 | return parseXML(val) 22 | 23 | def readPerfCounter(): 24 | data = kvpio.read_raw_kvp(0) 25 | dataStr = "" 26 | 27 | part_0 = readDataPart(data, 0) 28 | if not part_0: 29 | print "Data not found" 30 | return; 31 | ts = part_0.find('ts').text 32 | dataStr += part_0.find('data').text 33 | for i in range(1, int(part_0.find('all').text)): 34 | part_i = readDataPart(data, i) 35 | if ts != part_i.find('ts').text: 36 | print "Wrong timestamp:" + str(ts) + ", Part:" + str(i) 37 | dataStr += part_i.find('data').text 38 | 39 | dataStr = base64.b64decode(dataStr) 40 | 41 | print "------------------------------------------------------------------------" 42 | ts = float(ts) 43 | timestamp = datetime.datetime.fromtimestamp(ts/1000).strftime('%Y-%m-%d %H:%M:%S %z') 44 | print dataStr 45 | print timestamp 46 | 47 | if __name__ == "__main__": 48 | args = sys.argv[1:] 49 | loop = False 50 | 51 | if len(args) > 0 and args[0].lower() == 'loop': 52 | loop = True 53 | 54 | readPerfCounter() 55 | while loop: 56 | time.sleep(60) 57 | readPerfCounter() 58 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Configuration/WhereArgConfiguration.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | using System.Xml.Serialization; 29 | 30 | namespace EnhancedMonitoring.Configuration 31 | { 32 | 33 | [XmlRoot("Monitor")] 34 | public class WhereArgConfiguration 35 | { 36 | 37 | [XmlAttribute("Escape")] 38 | public Boolean Escape { get; set; } 39 | 40 | [XmlText] 41 | public String Name { get; set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Configuration/KvpConfiguration.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | using System.Xml.Serialization; 29 | 30 | namespace EnhancedMonitoring.Configuration 31 | { 32 | [XmlRoot("Kvp")] 33 | public class KvpConfiguration 34 | { 35 | [XmlElement("BatchMode")] 36 | public Boolean BatchMode { get; set; } 37 | 38 | [XmlElement("WriteInterval")] 39 | public Int32 WriteInterval { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Configuration/PerfCounterConfiguration.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | using System.Xml.Serialization; 29 | 30 | namespace EnhancedMonitoring.Configuration 31 | { 32 | [XmlRoot("Monitor")] 33 | public class PerfCounterConfiguration 34 | { 35 | [XmlElement("As")] 36 | public String As { get; set; } 37 | 38 | [XmlElement("Select")] 39 | public String Select { get; set; } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/Service/Program.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.ServiceProcess; 27 | using System.Text; 28 | using System.Threading.Tasks; 29 | 30 | namespace EnhancedMonitoring.Service 31 | { 32 | static class Program 33 | { 34 | /// 35 | /// The main entry point for the application. 36 | /// 37 | static void Main() 38 | { 39 | 40 | ServiceBase[] ServicesToRun; 41 | ServicesToRun = new ServiceBase[] 42 | { 43 | new EnhacedMonitoring() 44 | }; 45 | ServiceBase.Run(ServicesToRun); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/WMIQueryHelper.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | 29 | namespace EnhancedMonitoring 30 | { 31 | public class WMIQueryHelper 32 | { 33 | public static String EscapeLikeCondition(String condition) 34 | { 35 | if (!String.IsNullOrEmpty(condition)) 36 | { 37 | //Need to escape "[", "%", "_" 38 | condition = condition.Replace("[", "[[]"); 39 | condition = condition.Replace("%", "[%]"); 40 | condition = condition.Replace("_", "[_]"); 41 | 42 | //No need to escape "]", "^" 43 | } 44 | return condition; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /sample/Windows/showkvp.ps1: -------------------------------------------------------------------------------- 1 | 2 | param( 3 | [Parameter(Mandatory=$false)] 4 | [Switch]$loop=$true, 5 | ) 6 | 7 | 8 | Function Show-KVP 9 | { 10 | 11 | $path = 'HKLM:\SOFTWARE\Microsoft\Virtual Machine\External' 12 | $kvp = Get-Item -Path $path; 13 | if($kvp -eq $null) 14 | { 15 | Write-Error "Registry key not found:$path"; 16 | exit(-1); 17 | } 18 | $part_0 = $kvp.GetValue("Enhanced_Monitoring_Metric_Data_Item_Part_0"); 19 | 20 | if($part_0 -eq $null) 21 | { 22 | Write-Error "Performance data not found"; 23 | exit(-1); 24 | } 25 | $data_0 = $part_0 | ConvertFrom-Xml 26 | if($data_0 -eq $null) 27 | { 28 | Write-Error "Convert to Xml failed:$part_0"; 29 | exit(-1); 30 | } 31 | 32 | $dataStr = $data_0.data; 33 | $UtcTime = Get-Date -Date "1970-01-01 00:00:00Z" 34 | $timestamp = $UtcTime.AddMilliseconds($data_0.ts); 35 | 36 | for($i = 1; $i -lt $data_0.all; $i++) 37 | { 38 | $part_i = $kvp.GetValue("Enhanced_Monitoring_Metric_Data_Item_Part_" + $i); 39 | $data_i = $part_i | ConvertFrom-Xml 40 | if($data_i -eq $null) 41 | { 42 | Write-Error "Convert to xml failed:$part_i"; 43 | exit(-1); 44 | } 45 | 46 | $dataStr += $data_i.data 47 | } 48 | 49 | $dataStr = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($dataStr)) 50 | 51 | $data = ConvertFrom-Xml $dataStr 52 | 53 | if($selector -ne $null -and $selector -ne '') 54 | { 55 | $data = $data | Select -ExpandProperty $selector 56 | } 57 | 58 | Write-Host "-------------------------------------------------------------------------------------------"; 59 | Write-Host $data 60 | Write-Host $timestamp.ToString("yyyy/MM/dd HH:mm:ss zzz") 61 | } 62 | 63 | 64 | Show-KVP 65 | while($loop -eq $true) 66 | { 67 | Write-Host "Waiting..." -nonewline 68 | for($i=60; $i -gt 0; $i--) 69 | { 70 | Write-Host "`rWaiting $i..." -nonewline 71 | Start-Sleep -s 1 72 | } 73 | Write-Host "`r" -nonewline 74 | Show-KVP 75 | } -------------------------------------------------------------------------------- /src/UnitTest/MonitorTaskTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using Microsoft.VisualStudio.TestTools.UnitTesting; 25 | using EnhancedMonitoring.Configuration; 26 | using EnhancedMonitoring; 27 | using EnhancedMonitoring.Logging; 28 | 29 | namespace UnitTest 30 | { 31 | [TestClass] 32 | public class MonitorTaskTest 33 | { 34 | [TestMethod] 35 | public void TestMonitorTask() 36 | { 37 | var watcher = System.Diagnostics.Stopwatch.StartNew(); 38 | MonitorConfiguration conf = MonitorConfiguration.Load(@"..\..\..\EnhancedMonitoring\Configuration\EnhancedMonitoringProviderConfig.xml"); 39 | conf.LogFilePath = @"C:\ProgramData\Enhanced Monitoring\log\monitor.log"; 40 | conf.LogLevel = "Verbose"; 41 | Logger.Init(conf); 42 | MonitoringTask task = MonitoringTask.CreateInstance(conf as MonitorConfiguration); 43 | task.Run(); 44 | Console.WriteLine(String.Format("Elapsed: {0}ms", watcher.ElapsedMilliseconds)); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Configuration/SupportedVMDetectorConfiguration.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | using System.Xml.Serialization; 29 | 30 | namespace EnhancedMonitoring.Configuration 31 | { 32 | [XmlRoot("SupportedVMDetector")] 33 | public class SupportedVMDetectorConfiguration 34 | { 35 | [XmlElement("GuestDataItemKey")] 36 | public String GuestDataItemKey { get; set; } 37 | 38 | [XmlArray("VirtualMachineProperties")] 39 | [XmlArrayItem("VirtualMachineProperties")] 40 | public VirtualMachineProperties VirtualMachineProperties { get; set; } 41 | } 42 | 43 | public class VirtualMachineProperties : List 44 | { 45 | 46 | } 47 | 48 | [XmlRoot("VirtualMachineProperty")] 49 | public class VirtualMachineProperty 50 | { 51 | [XmlElement("Select")] 52 | public String Select { get; set; } 53 | 54 | [XmlElement("As")] 55 | public String As { get; set; } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/DataFormat/XmlDataFormatter.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | 29 | namespace EnhancedMonitoring.DataFormat 30 | { 31 | public class XmlDataFormatter 32 | { 33 | protected const Int32 DEFAULT_VALUE_LENGTH = 800; 34 | 35 | private Configuration.MonitorConfiguration conf; 36 | 37 | public XmlDataFormatter(Configuration.MonitorConfiguration monitorConfiguration) 38 | { 39 | this.conf = monitorConfiguration; 40 | } 41 | 42 | public IDictionary ToXml(IDictionary data) 43 | { 44 | var dataStr = DataFormatHelper.ToXml(data); 45 | dataStr = DataFormatHelper.Base64Encode(dataStr); 46 | var dataChunks = DataFormatHelper.PackString(dataStr, this.conf.MaxValueLength <= 0 ? DEFAULT_VALUE_LENGTH : this.conf.MaxValueLength); 47 | var packedData = DataFormatHelper.ToChunk(this.conf.DataItemKeyPrefix, dataChunks, DataFormatHelper.ToXml); 48 | return packedData; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/UnitTest/TestToXmlExpectedOutput.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | Dictionary(JSON object) to Xml Test 26 | 27 | Case1: String as Field 28 | Case2: String Array as Field 29 | Case3: Dictionary as Field 30 | Case4: Object Array as Field 31 | Case5: Null 32 | 33 | 34 | Key name as XElement name 35 | String content as XElement content 36 | Each element becomes a child XElement with name 'Item' 37 | Dictionary becomes a child XElement 38 | 39 | 1. Each element in the array is a dictionary 40 | 2. The 1st dictionary itself contains an array field 41 | 3. The 2nd dictionary itself contains a dictionary 42 | 43 | Output 'null' 44 | 45 | 46 | 47 | 48 | Element 1 49 | Element 1 50 | 51 | 52 | 53 | 54 | ObjectValue 55 | 56 | 57 | 58 | null 59 | 60 | -------------------------------------------------------------------------------- /src/Service/EnhacedMonitoringProvider.Designer.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | namespace EnhancedMonitoring.Service 24 | { 25 | partial class EnhacedMonitoring 26 | { 27 | /// 28 | /// Required designer variable. 29 | /// 30 | private System.ComponentModel.IContainer components = null; 31 | 32 | /// 33 | /// Clean up any resources being used. 34 | /// 35 | /// true if managed resources should be disposed; otherwise, false. 36 | protected override void Dispose(bool disposing) 37 | { 38 | if (disposing && (components != null)) 39 | { 40 | components.Dispose(); 41 | } 42 | base.Dispose(disposing); 43 | } 44 | 45 | #region Component Designer generated code 46 | 47 | /// 48 | /// Required method for Designer support - do not modify 49 | /// the contents of this method with the code editor. 50 | /// 51 | private void InitializeComponent() 52 | { 53 | // 54 | // EnhacedMonitoring 55 | // 56 | this.ServiceName = "Enhanced Monitoring Provider Service"; 57 | 58 | } 59 | 60 | #endregion 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/DataCollector/MgmtObject.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Configuration; 24 | using System; 25 | using System.Collections.Generic; 26 | using System.Linq; 27 | using System.Management; 28 | using System.Text; 29 | using System.Threading.Tasks; 30 | 31 | namespace EnhancedMonitoring.DataCollector 32 | { 33 | public abstract class MgmtObject 34 | { 35 | 36 | public static MgmtObject CreateInstance(MgmtObjectConfiguration conf) 37 | { 38 | if(conf == null) 39 | { 40 | throw new ArgumentNullException("conf"); 41 | } 42 | 43 | if(conf.Type == MgmtObjectType.DynamicMemory) 44 | { 45 | return new DynamicMemoryMgmtObject(conf); 46 | } 47 | return new QueryMgmtObject(conf); 48 | } 49 | 50 | protected MgmtObjectConfiguration conf; 51 | 52 | protected MgmtObject(MgmtObjectConfiguration conf) 53 | { 54 | this.conf = conf; 55 | } 56 | 57 | public abstract Object CollectData(IDictionary args); 58 | 59 | public abstract String KeyName { get; } 60 | 61 | public bool SuppressError 62 | { 63 | get 64 | { 65 | return this.conf.SuppressError; 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/UnitTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System.Reflection; 24 | using System.Runtime.CompilerServices; 25 | using System.Runtime.InteropServices; 26 | 27 | // General Information about an assembly is controlled through the following 28 | // set of attributes. Change these attribute values to modify the information 29 | // associated with an assembly. 30 | [assembly: AssemblyTitle("UnitTest")] 31 | [assembly: AssemblyDescription("")] 32 | [assembly: AssemblyConfiguration("")] 33 | [assembly: AssemblyCompany("")] 34 | [assembly: AssemblyProduct("UnitTest")] 35 | [assembly: AssemblyCopyright("Copyright © 2014")] 36 | [assembly: AssemblyTrademark("")] 37 | [assembly: AssemblyCulture("")] 38 | 39 | // Setting ComVisible to false makes the types in this assembly not visible 40 | // to COM components. If you need to access a type in this assembly from 41 | // COM, set the ComVisible attribute to true on that type. 42 | [assembly: ComVisible(false)] 43 | 44 | // The following GUID is for the ID of the typelib if this project is exposed to COM 45 | [assembly: Guid("5a308b21-7d9c-49d0-a903-88001f52deac")] 46 | 47 | // Version information for an assembly consists of the following four values: 48 | // 49 | // Major Version 50 | // Minor Version 51 | // Build Number 52 | // Revision 53 | // 54 | // You can specify all the values or you can default the Build and Revision Numbers 55 | // by using the '*' as shown below: 56 | // [assembly: AssemblyVersion("1.0.*")] 57 | [assembly: AssemblyVersion("1.0.0.0")] 58 | [assembly: AssemblyFileVersion("1.0.0.0")] 59 | -------------------------------------------------------------------------------- /src/UnitTest/WMIQueryHelperTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Text; 25 | using System.Collections.Generic; 26 | using Microsoft.VisualStudio.TestTools.UnitTesting; 27 | using EnhancedMonitoring; 28 | 29 | namespace UnitTest 30 | { 31 | [TestClass] 32 | public class WMIQueryHelperTest 33 | { 34 | 35 | [TestMethod] 36 | public void TestEscapeQuery() 37 | { 38 | var condition = WMIQueryHelper.EscapeLikeCondition(@"["); 39 | Assert.AreEqual(@"[[]", condition); 40 | condition = WMIQueryHelper.EscapeLikeCondition(@"_"); 41 | Assert.AreEqual(@"[_]", condition); 42 | condition = WMIQueryHelper.EscapeLikeCondition(@"%"); 43 | Assert.AreEqual(@"[%]", condition); 44 | 45 | condition = WMIQueryHelper.EscapeLikeCondition(@"^"); 46 | Assert.AreEqual(@"^", condition); 47 | condition = WMIQueryHelper.EscapeLikeCondition(@"]"); 48 | Assert.AreEqual(@"]", condition); 49 | 50 | condition = WMIQueryHelper.EscapeLikeCondition(@"[[[][]]]"); 51 | Assert.AreEqual(@"[[][[][[]][[]]]]", condition); 52 | 53 | condition = WMIQueryHelper.EscapeLikeCondition(@"[_]"); 54 | Assert.AreEqual(@"[[][_]]", condition); 55 | 56 | condition = WMIQueryHelper.EscapeLikeCondition(@""); 57 | Assert.AreEqual(@"", condition); 58 | 59 | condition = WMIQueryHelper.EscapeLikeCondition(null); 60 | Assert.AreEqual(null, condition); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Configuration/MgmtObjectConfiguration.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | using System.Xml.Serialization; 29 | 30 | namespace EnhancedMonitoring.Configuration 31 | { 32 | [XmlRoot("MgmtObject")] 33 | public class MgmtObjectConfiguration 34 | { 35 | [XmlAttribute("Type")] 36 | public MgmtObjectType Type { get; set; } 37 | 38 | [XmlAttribute("SuppressError")] 39 | public Boolean SuppressError { get; set; } 40 | 41 | [XmlAttribute("ReturnValue")] 42 | public MgmtObjectReturnValueType ReturnValueType { get; set; } 43 | 44 | [XmlElement("Namespace")] 45 | public String Namespace { get; set; } 46 | 47 | [XmlElement("From")] 48 | public String From { get; set; } 49 | 50 | [XmlElement("As")] 51 | public String As { get; set; } 52 | 53 | [XmlElement("Where")] 54 | public String Where { get; set; } 55 | 56 | [XmlArray("WhereArgs")] 57 | [XmlArrayItem("WhereArg")] 58 | public WhereArgList WhereArgs { get; set; } 59 | 60 | [XmlArray("PerfCounters")] 61 | [XmlArrayItem("PerfCounter")] 62 | public PerfCounterConfigurationList PerfCounters { get; set; } 63 | 64 | } 65 | 66 | public class WhereArgList : List 67 | { 68 | 69 | } 70 | 71 | public class PerfCounterConfigurationList : List 72 | { 73 | 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/UnitTest/SupportedVMDetectorTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Linq; 25 | using Microsoft.VisualStudio.TestTools.UnitTesting; 26 | using EnhancedMonitoring; 27 | using EnhancedMonitoring.Configuration; 28 | using System.Collections.Generic; 29 | 30 | namespace UnitTest 31 | { 32 | [TestClass] 33 | public class SupportedVMDetectorTest 34 | { 35 | /// 36 | /// This test requires the host has at least one virtual machine to pass. 37 | /// 38 | [TestMethod] 39 | public void TestDetectSupportedVM() 40 | { 41 | DetectSupportedVM(); 42 | } 43 | 44 | public IDictionary DetectSupportedVM() 45 | { 46 | var detector = SupportedVMDetector.CreateInstance(new SupportedVMDetectorConfiguration() 47 | { 48 | GuestDataItemKey = "Enhanced_Monitoring_Supported", 49 | }); 50 | 51 | var watcher = System.Diagnostics.Stopwatch.StartNew(); 52 | var vms = detector.GetSupportedVM(); 53 | Console.WriteLine(String.Format("Elapsed: {0}ms\t Detect supported VM", watcher.ElapsedMilliseconds)); 54 | 55 | Assert.IsNotNull(vms); 56 | Assert.AreNotEqual(0, vms.Count); 57 | 58 | var vm = vms.FirstOrDefault(); 59 | Assert.IsNotNull(vm); 60 | Assert.IsNotNull(vm["VirtualMachineName"]); 61 | Assert.IsNotNull(vm["VirtualMachineElementName"]); 62 | Assert.IsNotNull(vm["VirtualMachinePath"]); 63 | Console.WriteLine("Found: " + vm["VirtualMachineElementName"]); 64 | return vm; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/UnitTest/DynamicMemoryMgmtObjectTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using Microsoft.VisualStudio.TestTools.UnitTesting; 25 | using EnhancedMonitoring.Configuration; 26 | using EnhancedMonitoring.DataCollector; 27 | using EnhancedMonitoring; 28 | using System.Collections.Generic; 29 | using System.Management; 30 | using System.Linq; 31 | 32 | namespace UnitTest 33 | { 34 | /// 35 | /// Summary description for DynamicMemoryMgmtObjectTest 36 | /// 37 | [TestClass] 38 | public class DynamicMemoryMgmtObjectTest 39 | { 40 | 41 | [TestMethod] 42 | public MgmtObject TestDynamicMemoryMgmtObject() 43 | { 44 | MgmtObjectConfiguration conf = new MgmtObjectConfiguration() 45 | { 46 | Type = MgmtObjectType.DynamicMemory, 47 | }; 48 | 49 | var mgmtObj = MgmtObject.CreateInstance(conf); 50 | Assert.IsNotNull(mgmtObj); 51 | Assert.IsTrue(mgmtObj is DynamicMemoryMgmtObject); 52 | return mgmtObj; 53 | } 54 | 55 | [TestMethod] 56 | public void TestDynamicMemoryMgmtObjectCollectData() 57 | { 58 | var mgmtObj = TestDynamicMemoryMgmtObject(); 59 | var vmArgs = new SupportedVMDetectorTest().DetectSupportedVM(); 60 | var data = mgmtObj.CollectData(vmArgs); 61 | 62 | Assert.IsNotNull(data); 63 | var dynamicMemoryData = (data as Dictionary); 64 | Assert.IsNotNull(dynamicMemoryData); 65 | Assert.IsNotNull(dynamicMemoryData[DynamicMemoryMgmtObject.KeyName_MemoryUsage]); 66 | Assert.IsNotNull(dynamicMemoryData[DynamicMemoryMgmtObject.KeyName_MemoryAvailable]); 67 | Assert.IsNotNull(dynamicMemoryData[DynamicMemoryMgmtObject.KeyName_AvailableMemoryBuffer]); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTest", "UnitTest\UnitTest.csproj", "{0B568E5B-3796-47CC-B934-C4684CBE241C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Service", "Service\Service.csproj", "{ED1F3B96-683F-4D16-B4F9-06765E3697C1}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnhancedMonitoring", "EnhancedMonitoring\EnhancedMonitoring.csproj", "{7EACC378-2947-4F2E-AB0F-EB57BE7D3680}" 11 | EndProject 12 | Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "..\packages\MSI\EnhancedMonitoring\Setup.wixproj", "{A6AA397B-1031-4FBF-9A8A-B50EE7318EC6}" 13 | ProjectSection(ProjectDependencies) = postProject 14 | {7EACC378-2947-4F2E-AB0F-EB57BE7D3680} = {7EACC378-2947-4F2E-AB0F-EB57BE7D3680} 15 | {ED1F3B96-683F-4D16-B4F9-06765E3697C1} = {ED1F3B96-683F-4D16-B4F9-06765E3697C1} 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|x64 = Debug|x64 21 | DebugAndRelease|x64 = DebugAndRelease|x64 22 | Release|x64 = Release|x64 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {0B568E5B-3796-47CC-B934-C4684CBE241C}.Debug|x64.ActiveCfg = Debug|Any CPU 26 | {0B568E5B-3796-47CC-B934-C4684CBE241C}.Debug|x64.Build.0 = Debug|Any CPU 27 | {0B568E5B-3796-47CC-B934-C4684CBE241C}.DebugAndRelease|x64.ActiveCfg = DebugAndRelease|Any CPU 28 | {0B568E5B-3796-47CC-B934-C4684CBE241C}.Release|x64.ActiveCfg = Release|Any CPU 29 | {ED1F3B96-683F-4D16-B4F9-06765E3697C1}.Debug|x64.ActiveCfg = Debug|x64 30 | {ED1F3B96-683F-4D16-B4F9-06765E3697C1}.Debug|x64.Build.0 = Debug|x64 31 | {ED1F3B96-683F-4D16-B4F9-06765E3697C1}.DebugAndRelease|x64.ActiveCfg = DebugAndRelease|x64 32 | {ED1F3B96-683F-4D16-B4F9-06765E3697C1}.DebugAndRelease|x64.Build.0 = DebugAndRelease|x64 33 | {ED1F3B96-683F-4D16-B4F9-06765E3697C1}.Release|x64.ActiveCfg = Release|x64 34 | {ED1F3B96-683F-4D16-B4F9-06765E3697C1}.Release|x64.Build.0 = Release|x64 35 | {7EACC378-2947-4F2E-AB0F-EB57BE7D3680}.Debug|x64.ActiveCfg = Debug|x64 36 | {7EACC378-2947-4F2E-AB0F-EB57BE7D3680}.Debug|x64.Build.0 = Debug|x64 37 | {7EACC378-2947-4F2E-AB0F-EB57BE7D3680}.DebugAndRelease|x64.ActiveCfg = DebugAndRelease|x64 38 | {7EACC378-2947-4F2E-AB0F-EB57BE7D3680}.DebugAndRelease|x64.Build.0 = DebugAndRelease|x64 39 | {7EACC378-2947-4F2E-AB0F-EB57BE7D3680}.Release|x64.ActiveCfg = Release|x64 40 | {7EACC378-2947-4F2E-AB0F-EB57BE7D3680}.Release|x64.Build.0 = Release|x64 41 | {A6AA397B-1031-4FBF-9A8A-B50EE7318EC6}.Debug|x64.ActiveCfg = Debug|x64 42 | {A6AA397B-1031-4FBF-9A8A-B50EE7318EC6}.Debug|x64.Build.0 = Debug|x64 43 | {A6AA397B-1031-4FBF-9A8A-B50EE7318EC6}.DebugAndRelease|x64.ActiveCfg = DebugAndRelease|x86 44 | {A6AA397B-1031-4FBF-9A8A-B50EE7318EC6}.Release|x64.ActiveCfg = Release|x86 45 | EndGlobalSection 46 | GlobalSection(SolutionProperties) = preSolution 47 | HideSolutionNode = FALSE 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /src/UnitTest/MonitorConfigurationTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Linq; 25 | using Microsoft.VisualStudio.TestTools.UnitTesting; 26 | using EnhancedMonitoring.Configuration; 27 | 28 | namespace UnitTest 29 | { 30 | [TestClass] 31 | public class MonitorConfigurationTest 32 | { 33 | [TestMethod] 34 | public void TestLoadConfiguration() 35 | { 36 | var conf = MonitorConfiguration.Load(@"..\..\SampleMonitor.xml"); 37 | 38 | Assert.IsNotNull(conf); 39 | Assert.IsNotNull(conf.Version); 40 | Console.WriteLine(conf.Version); 41 | Assert.AreEqual(60, conf.RefreshRate); 42 | Assert.AreEqual(700, conf.MaxValueLength); 43 | Assert.IsNotNull(conf.Kvp); 44 | Assert.AreEqual(200, conf.Kvp.WriteInterval); 45 | Assert.IsTrue(conf.Kvp.BatchMode); 46 | 47 | Assert.IsNotNull(conf.SupportedVMDetector); 48 | Assert.IsNotNull(conf.SupportedVMDetector.GuestDataItemKey); 49 | 50 | Assert.IsNotNull(conf.MgmtObjects); 51 | var mgmtObj = conf.MgmtObjects.FirstOrDefault(); 52 | Assert.IsNotNull(mgmtObj); 53 | Assert.IsTrue(mgmtObj.SuppressError); 54 | Assert.IsNotNull(mgmtObj.Namespace); 55 | Assert.IsNotNull(mgmtObj.Where); 56 | Assert.IsNotNull(mgmtObj.From); 57 | Assert.IsNotNull(mgmtObj.WhereArgs); 58 | Assert.IsTrue(mgmtObj.WhereArgs.FirstOrDefault().Escape); 59 | Assert.IsNotNull(mgmtObj.WhereArgs.FirstOrDefault()); 60 | 61 | Assert.IsNotNull(mgmtObj.PerfCounters); 62 | var counter = mgmtObj.PerfCounters.FirstOrDefault(); 63 | Assert.IsNotNull(counter); 64 | Assert.IsNotNull(counter.Select); 65 | Assert.IsNotNull(counter.As); 66 | 67 | var dynamicMemMgmtObj = conf.MgmtObjects.Where(m => m.Type == MgmtObjectType.DynamicMemory).FirstOrDefault(); 68 | Assert.IsNotNull(dynamicMemMgmtObj); 69 | Assert.AreEqual(MgmtObjectReturnValueType.Single, dynamicMemMgmtObj.ReturnValueType); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/UnitTest/DataPackingHelperTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using Microsoft.VisualStudio.TestTools.UnitTesting; 25 | using EnhancedMonitoring.DataFormat; 26 | using System.Collections.Generic; 27 | 28 | namespace UnitTest 29 | { 30 | [TestClass] 31 | public class DataPackingHelperTest 32 | { 33 | [TestMethod] 34 | public void TestPackString() 35 | { 36 | { 37 | var rawStr = "aaaa"; 38 | var result = DataFormatHelper.PackString(rawStr, 1); 39 | Assert.IsNotNull(result); 40 | Assert.AreEqual(4, result.Count); 41 | } 42 | 43 | { 44 | var rawStr = "aaaa"; 45 | var result = DataFormatHelper.PackString(rawStr, 3); 46 | Assert.IsNotNull(result); 47 | Assert.AreEqual(2, result.Count); 48 | } 49 | 50 | { 51 | var rawStr = "aaaa"; 52 | var result = DataFormatHelper.PackString(rawStr, 5); 53 | Assert.IsNotNull(result); 54 | Assert.AreEqual(1, result.Count); 55 | } 56 | } 57 | 58 | [TestMethod] 59 | public void TestPackData() 60 | { 61 | var data = new Dictionary() 62 | { 63 | {"MaxClockFrequency", 100000}, 64 | {"AvailableMemeory", 1024}, 65 | }; 66 | foreach (var kvp in data) 67 | { 68 | Console.WriteLine(kvp); 69 | } 70 | var dataStr = DataFormatHelper.ToXml(data); 71 | Console.WriteLine(dataStr); 72 | 73 | dataStr = DataFormatHelper.Base64Encode(dataStr); 74 | Console.WriteLine(dataStr); 75 | 76 | var dataChunks = DataFormatHelper.PackString(dataStr, 50); 77 | 78 | var packedData = DataFormatHelper.ToChunk("Part_", dataChunks, DataFormatHelper.ToXml); 79 | foreach(var kvp in packedData) 80 | { 81 | Console.WriteLine(kvp); 82 | } 83 | 84 | Assert.AreEqual(3, packedData.Count); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Configuration/MonitorConfiguration.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.IO; 26 | using System.Linq; 27 | using System.Text; 28 | using System.Threading.Tasks; 29 | using System.Xml.Serialization; 30 | 31 | namespace EnhancedMonitoring.Configuration 32 | { 33 | [XmlRoot("Monitor")] 34 | public class MonitorConfiguration 35 | { 36 | [XmlElement("RefreshRate")] 37 | public Int64 RefreshRate { get; set; } 38 | 39 | [XmlElement("Version")] 40 | public String Version { get; set; } 41 | 42 | [XmlElement("MaxValueLength")] 43 | public Int32 MaxValueLength { get; set; } 44 | 45 | [XmlElement("Kvp")] 46 | public KvpConfiguration Kvp { get; set; } 47 | 48 | [XmlElement("LogLevel")] 49 | public String LogLevel { get; set; } 50 | 51 | [XmlElement("LogFilePath")] 52 | public String LogFilePath { get; set; } 53 | 54 | [XmlElement("MaxLogRetain")] 55 | public Int32 MaxLogRetention { get; set; } 56 | 57 | [XmlElement("LogFileSize")] 58 | public Int64 LogFileSize { get; set; } 59 | 60 | public Double EventLogInterval { get; set; } 61 | 62 | [XmlElement("DataItemKeyPrefix")] 63 | public string DataItemKeyPrefix { get; set; } 64 | 65 | [XmlElement("SupportedVMDetector")] 66 | public SupportedVMDetectorConfiguration SupportedVMDetector { get; set; } 67 | 68 | [XmlArray("MgmtObjects")] 69 | [XmlArrayItem("MgmtObject")] 70 | public MgmtObjectConfigurationList MgmtObjects { get; set; } 71 | 72 | public static MonitorConfiguration Load(String path) 73 | { 74 | XmlSerializer serializer = new XmlSerializer(typeof(MonitorConfiguration)); 75 | using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 76 | { 77 | var conf = serializer.Deserialize(fs); 78 | return (MonitorConfiguration)conf; 79 | } 80 | } 81 | } 82 | 83 | public class VirtualMachineList : List 84 | { 85 | 86 | } 87 | 88 | public class MgmtObjectConfigurationList : List 89 | { 90 | 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Rr]eleases/ 14 | x64/ 15 | build/ 16 | bld/ 17 | [Bb]in/ 18 | [Oo]bj/ 19 | 20 | # Roslyn cache directories 21 | *.ide/ 22 | 23 | # MSTest test Results 24 | [Tt]est[Rr]esult*/ 25 | [Bb]uild[Ll]og.* 26 | 27 | #NUNIT 28 | *.VisualState.xml 29 | TestResult.xml 30 | 31 | # Build Results of an ATL Project 32 | [Dd]ebugPS/ 33 | [Rr]eleasePS/ 34 | dlldata.c 35 | 36 | *_i.c 37 | *_p.c 38 | *_i.h 39 | *.ilk 40 | *.meta 41 | *.obj 42 | *.pch 43 | *.pdb 44 | *.pgc 45 | *.pgd 46 | *.rsp 47 | *.sbr 48 | *.tlb 49 | *.tli 50 | *.tlh 51 | *.tmp 52 | *.tmp_proj 53 | *.log 54 | *.vspscc 55 | *.vssscc 56 | .builds 57 | *.pidb 58 | *.svclog 59 | *.scc 60 | 61 | # Chutzpah Test files 62 | _Chutzpah* 63 | 64 | # Visual C++ cache files 65 | ipch/ 66 | *.aps 67 | *.ncb 68 | *.opensdf 69 | *.sdf 70 | *.cachefile 71 | 72 | # Visual Studio profiler 73 | *.psess 74 | *.vsp 75 | *.vspx 76 | 77 | # TFS 2012 Local Workspace 78 | $tf/ 79 | 80 | # Guidance Automation Toolkit 81 | *.gpState 82 | 83 | # ReSharper is a .NET coding add-in 84 | _ReSharper*/ 85 | *.[Rr]e[Ss]harper 86 | *.DotSettings.user 87 | 88 | # JustCode is a .NET coding addin-in 89 | .JustCode 90 | 91 | # TeamCity is a build add-in 92 | _TeamCity* 93 | 94 | # DotCover is a Code Coverage Tool 95 | *.dotCover 96 | 97 | # NCrunch 98 | _NCrunch_* 99 | .*crunch*.local.xml 100 | 101 | # MightyMoose 102 | *.mm.* 103 | AutoTest.Net/ 104 | 105 | # Web workbench (sass) 106 | .sass-cache/ 107 | 108 | # Installshield output folder 109 | [Ee]xpress/ 110 | 111 | # DocProject is a documentation generator add-in 112 | DocProject/buildhelp/ 113 | DocProject/Help/*.HxT 114 | DocProject/Help/*.HxC 115 | DocProject/Help/*.hhc 116 | DocProject/Help/*.hhk 117 | DocProject/Help/*.hhp 118 | DocProject/Help/Html2 119 | DocProject/Help/html 120 | 121 | # Click-Once directory 122 | publish/ 123 | 124 | # Publish Web Output 125 | *.[Pp]ublish.xml 126 | *.azurePubxml 127 | ## TODO: Comment the next line if you want to checkin your 128 | ## web deploy settings but do note that will include unencrypted 129 | ## passwords 130 | *.pubxml 131 | 132 | # Enable "build/" folder in the NuGet Packages folder since 133 | # NuGet packages use it for MSBuild targets. 134 | # This line needs to be after the ignore of the build folder 135 | # (and the packages folder if the line above has been uncommented) 136 | !packages/build/ 137 | 138 | # Windows Azure Build Output 139 | csx/ 140 | *.build.csdef 141 | 142 | # Windows Store app package directory 143 | AppPackages/ 144 | 145 | # Others 146 | sql/ 147 | *.Cache 148 | ClientBin/ 149 | [Ss]tyle[Cc]op.* 150 | ~$* 151 | *~ 152 | *.dbmdl 153 | *.dbproj.schemaview 154 | *.pfx 155 | *.publishsettings 156 | node_modules/ 157 | 158 | # RIA/Silverlight projects 159 | Generated_Code/ 160 | 161 | # Backup & report files from converting an old project file 162 | # to a newer Visual Studio version. Backup files are not needed, 163 | # because we have git ;-) 164 | _UpgradeReport_Files/ 165 | Backup*/ 166 | UpgradeLog*.XML 167 | UpgradeLog*.htm 168 | 169 | # SQL Server files 170 | *.mdf 171 | *.ldf 172 | 173 | # Business Intelligence projects 174 | *.rdl.data 175 | *.bim.layout 176 | *.bim_*.settings 177 | 178 | # Microsoft Fakes 179 | FakesAssemblies/ 180 | 181 | #Source Depo 182 | build*.prf 183 | build*.trc 184 | build*.err 185 | sources 186 | sources.dep 187 | dirs 188 | project.mk -------------------------------------------------------------------------------- /src/EnhancedMonitoring/NamedArgumentHelper.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Configuration; 24 | using System; 25 | using System.Collections.Generic; 26 | using System.Linq; 27 | using System.Text; 28 | using System.Threading.Tasks; 29 | 30 | namespace EnhancedMonitoring 31 | { 32 | public static class NamedArgumentHelper 33 | { 34 | public static String Resolve(String str, IList whereArgs, IDictionary args) 35 | { 36 | if (String.IsNullOrEmpty(str)) 37 | { 38 | return str; 39 | } 40 | 41 | if(whereArgs == null || whereArgs.Count == 0) 42 | { 43 | try 44 | { 45 | return String.Format(str, new Object[0]); 46 | } 47 | catch(FormatException e) 48 | { 49 | throw new ArgumentException(String.Format("format={0}, args=NullOrEmpty", str), e); 50 | } 51 | } 52 | 53 | if(args == null && whereArgs != null && whereArgs.Count > 0) 54 | { 55 | throw new ArgumentException(String.Format("Can't resolve argument: format={0}, args={1}", str, String.Join(",", whereArgs.Select(a => a.Name)))); 56 | } 57 | 58 | Object[] argsVal = new Object[args.Count]; 59 | 60 | for (int i = 0; i < whereArgs.Count; i++) 61 | { 62 | var whereArg = whereArgs[i]; 63 | if (args.ContainsKey(whereArg.Name)) 64 | { 65 | argsVal[i] = args[whereArg.Name]; 66 | if(whereArg.Escape && argsVal[i] != null) 67 | { 68 | argsVal[i] = WMIQueryHelper.EscapeLikeCondition(argsVal[i].ToString()); 69 | } 70 | } 71 | else 72 | { 73 | throw new ArgumentException(String.Format("Can't resolve argument format={0}, args={1}", str, whereArgs[i].Name)); 74 | } 75 | } 76 | 77 | try 78 | { 79 | return String.Format(str, argsVal); 80 | } 81 | catch(FormatException e) 82 | { 83 | throw new ArgumentException(String.Format("Can't resolve argument: format={0}, args={1}", str, String.Join(",", whereArgs)), e); 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/UnitTest/SampleResult.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 331819225422 5 | 4627899239734 6 | 2294591080835 7 | 3312782 8 | 9 | 10 | 11 | 12 | 5956484 13 | 51824588 14 | 2294591203786 15 | 3312782 16 | 17 | 18 | 5436843 19 | 48668457 20 | 2294591203786 21 | 3312782 22 | 23 | 24 | 7695515 25 | 63962088 26 | 2294591203786 27 | 3312782 28 | 29 | 30 | 14605031 31 | 72549008 32 | 2294591203786 33 | 3312782 34 | 35 | 36 | 37 | 38 | Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz 39 | 3392 40 | 4 41 | 8 42 | 43 | 44 | 45 | 46 | 2031 47 | 0 48 | 49 | 50 | 51 | 52 | 4294967296 53 | 54 | 55 | 4294967296 56 | 57 | 58 | 59 | 60 | 11640 61 | 62 | 63 | 64 | 65 | 1526 66 | 67 | 68 | 69 | 70 | 6.3.9600 71 | null 72 | Microsoft Windows 8.1 Enterprise 73 | 74 | 75 | 76 | 77 | 96BFA00A-46E3-4F7E-9169-6F39485BAC52 78 | 79 | 80 | 81 | 82 | 4 83 | 0 84 | 100000 85 | 86 | 87 | 88 | 89 | 512 90 | 1048576 91 | true 92 | 20 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Logging/EventLogWriter.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Diagnostics; 26 | using System.Linq; 27 | using System.Text; 28 | using System.Threading.Tasks; 29 | 30 | namespace EnhancedMonitoring.Logging 31 | { 32 | public class EventLogWriter : LogWriter 33 | { 34 | public const String LogName = "Enhanced Monitoring"; 35 | public const String Source = "Enhanced Monitoring Provider Service"; 36 | public const String EventLogMsgFormat = "There are {0} error(s), {1} warning(s) during the last {2} minute(s). " 37 | + "For more information please view the log file, \"{3}\"."; 38 | public const double DefaultLogInterval = 60; 39 | 40 | private int warningCount; 41 | private int errorCount; 42 | private DateTime lastFlush = DateTime.Now; 43 | private double flushIntervalInMinutes; 44 | private String logFilePath; 45 | 46 | public EventLogWriter(Configuration.MonitorConfiguration conf) 47 | { 48 | this.logFilePath = conf.LogFilePath; 49 | this.flushIntervalInMinutes = conf.EventLogInterval <= 0 ? DefaultLogInterval : conf.EventLogInterval; 50 | } 51 | 52 | public void Write(LogLevel level, String msg) 53 | { 54 | switch(level) 55 | { 56 | case LogLevel.Warning: 57 | warningCount++; 58 | break; 59 | case LogLevel.Error: 60 | errorCount++; 61 | break; 62 | default: 63 | break; 64 | } 65 | if(errorCount > 0 || warningCount > 0) 66 | { 67 | DateTime now = DateTime.Now; 68 | if (now.Subtract(this.lastFlush).TotalMinutes > this.flushIntervalInMinutes) 69 | { 70 | WriteEventLog(); 71 | this.lastFlush = now; 72 | errorCount = 0; 73 | warningCount = 0; 74 | } 75 | } 76 | } 77 | 78 | protected virtual void WriteEventLog() 79 | { 80 | String msg = String.Format(EventLogMsgFormat, errorCount, warningCount, 81 | this.flushIntervalInMinutes, this.logFilePath); 82 | using (EventLog log = new EventLog(EventLogWriter.LogName)) 83 | { 84 | log.Source = EventLogWriter.Source; 85 | log.WriteEntry(msg, this.errorCount > 0 ? EventLogEntryType.Error : EventLogEntryType.Warning); 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Service/EnhacedMonitoringProvider.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Configuration; 24 | using EnhancedMonitoring.Logging; 25 | using System; 26 | using System.Collections.Generic; 27 | using System.ComponentModel; 28 | using System.Data; 29 | using System.Diagnostics; 30 | using System.Linq; 31 | using System.ServiceProcess; 32 | using System.Text; 33 | using System.Threading; 34 | using System.Threading.Tasks; 35 | 36 | namespace EnhancedMonitoring.Service 37 | { 38 | public partial class EnhacedMonitoring : ServiceBase 39 | { 40 | private const Int64 MIN_REFRESH_RATE = 60; //Default minimal refresh rate is 60 seconds 41 | 42 | public EnhacedMonitoring() 43 | { 44 | InitializeComponent(); 45 | } 46 | 47 | protected override void OnStart(string[] args) 48 | { 49 | var configFilePath = String.Format(@"{0}\{1}\{2}", 50 | System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData), 51 | "Enhanced Monitoring", "EnhancedMonitoringProviderConfig.xml"); 52 | 53 | var defaultLogPath = String.Format(@"{0}\{1}\{2}\{3}", 54 | System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData), 55 | "Enhanced Monitoring", "log", "monitor.log"); 56 | 57 | MonitorConfiguration conf = MonitorConfiguration.Load(configFilePath); 58 | conf.LogFilePath = conf.LogFilePath ?? defaultLogPath; 59 | Logger.Init(conf); 60 | timer = new Timer(_ => this.RunMonitoringTask(conf), null, 0, Timeout.Infinite); 61 | 62 | Logger.Info("Monitoring service started"); 63 | } 64 | 65 | private Timer timer; 66 | 67 | private void RunMonitoringTask(MonitorConfiguration conf) 68 | { 69 | Logger.Info("Start monitoring task"); 70 | DateTime start = DateTime.Now; 71 | MonitoringTask task = MonitoringTask.CreateInstance(conf); 72 | task.Run(); 73 | Logger.Info("Monitoring task finished"); 74 | TimeSpan elapsed = DateTime.Now.Subtract(start); 75 | //Substract elapsed time to get the task running exaclty aliging to refresh rate. 76 | long interval = Math.Max(conf.RefreshRate, MIN_REFRESH_RATE) * 1000; 77 | long timeToWait = interval - (long)elapsed.TotalMilliseconds % interval; 78 | //Trigger next task 79 | timer.Change(timeToWait, Timeout.Infinite); 80 | } 81 | 82 | protected override void OnStop() 83 | { 84 | if(this.timer != null) 85 | { 86 | this.timer.Dispose(); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/UnitTest/EventLogTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using Microsoft.VisualStudio.TestTools.UnitTesting; 25 | using System.Diagnostics; 26 | using EnhancedMonitoring.Logging; 27 | using System.Threading; 28 | using EnhancedMonitoring.Configuration; 29 | 30 | namespace UnitTest 31 | { 32 | [TestClass] 33 | public class EventLogTest 34 | { 35 | public void TestCreateEventLogSource() 36 | { 37 | EventLog.CreateEventSource(new EventSourceCreationData(EventLogWriter.Source, EventLogWriter.LogName) 38 | { 39 | MachineName = System.Environment.MachineName 40 | }); 41 | } 42 | 43 | public void TestRemoveEventLogSource() 44 | { 45 | EventLog.DeleteEventSource(EventLogWriter.Source); 46 | } 47 | 48 | //[TestMethod] 49 | public void TestEventLogSource() 50 | { 51 | Assert.IsTrue(EventLog.Exists(EventLogWriter.LogName)); 52 | //Assert.IsTrue(EventLog.SourceExists(EventLogWriter.Source)); 53 | 54 | using (EventLog log = new EventLog()) 55 | { 56 | log.Log = EventLogWriter.LogName; 57 | log.Source = EventLogWriter.Source; 58 | log.MachineName = System.Environment.MachineName; 59 | log.WriteEntry("Test", EventLogEntryType.Warning); 60 | } 61 | } 62 | 63 | [TestMethod] 64 | public void TestEventLogFlushInterval() 65 | { 66 | var writer = new ShimEventLogWriter(new MonitorConfiguration() 67 | { 68 | EventLogInterval = 100.0 / 60000 //100ms 69 | }); 70 | 71 | //Try to refresh timestamp for last flush. 72 | //A flush will be triggered if required. 73 | //And the timestamp will be reset to NOW 74 | writer.Write(LogLevel.Error, ""); 75 | 76 | //Clear flushed flag and write a log record. 77 | writer.Flushed = false; 78 | writer.Write(LogLevel.Info, ""); 79 | Assert.IsFalse(writer.Flushed); 80 | 81 | //Clear flushed flag and wait for 120ms 82 | writer.Flushed = false; 83 | Thread.Sleep(120); 84 | 85 | //Trigger a flush and check the flag. 86 | writer.Write(LogLevel.Info, ""); 87 | Assert.IsTrue(writer.Flushed); 88 | } 89 | } 90 | 91 | class ShimEventLogWriter:EventLogWriter 92 | { 93 | 94 | public ShimEventLogWriter(MonitorConfiguration conf) : base(conf) { } 95 | 96 | public bool Flushed { get; set; } 97 | protected override void WriteEventLog() 98 | { 99 | this.Flushed = true; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/UnitTest/LoggerTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Logging; 24 | using EnhancedMonitoring.Configuration; 25 | using System; 26 | using System.Text; 27 | using System.Collections.Generic; 28 | using Microsoft.VisualStudio.TestTools.UnitTesting; 29 | 30 | namespace UnitTest 31 | { 32 | /// 33 | /// Summary description for LoggerTest 34 | /// 35 | [TestClass] 36 | public class LoggerTest 37 | { 38 | [TestMethod] 39 | public void TestLog() 40 | { 41 | var conf = new MonitorConfiguration() 42 | { 43 | LogLevel = "Info" 44 | }; 45 | var logWriter = new TestLogWriter(); 46 | Logger.Init(conf, new LogWriter[] { logWriter }); 47 | 48 | Logger.Verbose("Trival"); 49 | Assert.IsNull(logWriter.Msg); 50 | 51 | Logger.Info("Formated information: {0}", "Nothing"); 52 | Assert.IsTrue(logWriter.Msg.Contains("Formated information")); 53 | Assert.AreEqual(LogLevel.Info, logWriter.Level); 54 | Console.WriteLine(logWriter.Msg); 55 | 56 | try 57 | { 58 | RaiseException(); 59 | } 60 | catch(Exception e) 61 | { 62 | Logger.Error(e); 63 | //Check call stack is logged. 64 | Assert.IsTrue(logWriter.Msg.Contains("at UnitTest.LoggerTest.TestLog()")); 65 | Console.WriteLine(logWriter.Msg); 66 | } 67 | } 68 | 69 | [TestMethod] 70 | public void TestLogLevelConfigure() 71 | { 72 | var conf = new MonitorConfiguration() 73 | { 74 | LogLevel = "Infoasdfasdf" 75 | }; 76 | var logWriter = new TestLogWriter(); 77 | Logger.Init(conf, new LogWriter[] { logWriter }); 78 | Logger.Info("Test"); 79 | Assert.AreEqual(LogLevel.Info, logWriter.Level); 80 | } 81 | 82 | [TestMethod] 83 | public void TestZeroLogWriter() 84 | { 85 | var conf = new MonitorConfiguration() 86 | { 87 | LogLevel = "Infoasdfasdf" 88 | }; 89 | 90 | Logger.Init(conf, new LogWriter[0]); 91 | Logger.Info("Test"); 92 | } 93 | 94 | private void RaiseException() 95 | { 96 | throw new NotImplementedException(); 97 | } 98 | } 99 | 100 | class TestLogWriter : LogWriter 101 | { 102 | public LogLevel Level { get; set; } 103 | public String Msg { get; set; } 104 | 105 | public void Write(LogLevel level, String msg) 106 | { 107 | this.Level = level; 108 | this.Msg = msg; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/UnitTest/JSONHelper.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.Linq; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | 29 | namespace UnitTest 30 | { 31 | 32 | class JsonHelper 33 | { 34 | private const string INDENT_STRING = " "; 35 | public static string FormatJson(string str) 36 | { 37 | var indent = 0; 38 | var quoted = false; 39 | var sb = new StringBuilder(); 40 | for (var i = 0; i < str.Length; i++) 41 | { 42 | var ch = str[i]; 43 | switch (ch) 44 | { 45 | case '{': 46 | case '[': 47 | sb.Append(ch); 48 | if (!quoted) 49 | { 50 | sb.AppendLine(); 51 | Enumerable.Range(0, ++indent).ForEach(item => sb.Append(INDENT_STRING)); 52 | } 53 | break; 54 | case '}': 55 | case ']': 56 | if (!quoted) 57 | { 58 | sb.AppendLine(); 59 | Enumerable.Range(0, --indent).ForEach(item => sb.Append(INDENT_STRING)); 60 | } 61 | sb.Append(ch); 62 | break; 63 | case '"': 64 | sb.Append(ch); 65 | bool escaped = false; 66 | var index = i; 67 | while (index > 0 && str[--index] == '\\') 68 | escaped = !escaped; 69 | if (!escaped) 70 | quoted = !quoted; 71 | break; 72 | case ',': 73 | sb.Append(ch); 74 | if (!quoted) 75 | { 76 | sb.AppendLine(); 77 | Enumerable.Range(0, indent).ForEach(item => sb.Append(INDENT_STRING)); 78 | } 79 | break; 80 | case ':': 81 | sb.Append(ch); 82 | if (!quoted) 83 | sb.Append(" "); 84 | break; 85 | default: 86 | sb.Append(ch); 87 | break; 88 | } 89 | } 90 | return sb.ToString(); 91 | } 92 | } 93 | 94 | static class Extensions 95 | { 96 | public static void ForEach(this IEnumerable ie, Action action) 97 | { 98 | foreach (var i in ie) 99 | { 100 | action(i); 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Logging/FileLogWriter.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections.Generic; 25 | using System.IO; 26 | using System.Linq; 27 | using System.Text; 28 | using System.Threading; 29 | using System.Threading.Tasks; 30 | 31 | namespace EnhancedMonitoring.Logging 32 | { 33 | public class FileLogWriter : LogWriter 34 | { 35 | public const Int64 DefaultLogFileSize = 4 * 1024 * 1024; 36 | public const Int32 DefaultLogRetention = 10; 37 | 38 | private String filePath; 39 | private Int64 logFileSize; 40 | private Int32 maxLogRetention; 41 | private Object writeLock = new Object(); 42 | 43 | public FileLogWriter(Configuration.MonitorConfiguration conf) 44 | { 45 | this.filePath = conf.LogFilePath; 46 | this.logFileSize = conf.LogFileSize <= 0 ? DefaultLogFileSize : conf.LogFileSize; 47 | this.maxLogRetention = conf.MaxLogRetention <= 0 ? DefaultLogRetention : conf.MaxLogRetention; 48 | Directory.CreateDirectory(Path.GetDirectoryName(this.filePath)); 49 | } 50 | 51 | public void Write(LogLevel level, String msg) 52 | { 53 | lock(writeLock) 54 | { 55 | FileInfo file = new FileInfo(this.filePath); 56 | if (file.Exists && file.Length > this.logFileSize) 57 | { 58 | RotateLogFile(); 59 | } 60 | File.AppendAllLines(this.filePath, new String[] { msg }, Encoding.UTF8); 61 | } 62 | } 63 | 64 | /// 65 | /// 66 | /// Rotate the old log to another file. The rule is: 67 | /// 1. log -> log.0 68 | /// 2. log.$(i) -> log.$(i + 1) 69 | /// 3. IF i + 1 == LogRetention: delete log.$(i) 70 | /// 71 | /// 72 | protected void RotateLogFile() 73 | { 74 | int index = 0; 75 | String rotateFilePath = GetRotateFilePath(index); 76 | while(File.Exists(rotateFilePath)) 77 | { 78 | //Reaches retention limit, delete the oldest log 79 | if (index == this.maxLogRetention - 1) 80 | { 81 | File.Delete(rotateFilePath); 82 | break; 83 | } 84 | index++; 85 | rotateFilePath = GetRotateFilePath(index); 86 | } 87 | 88 | for(int i = index; i > 0; i--) 89 | { 90 | String src = GetRotateFilePath(i - 1); 91 | String dest = GetRotateFilePath(i); 92 | File.Move(src, dest); 93 | } 94 | rotateFilePath = String.Format("{0}.{1}", this.filePath, 0); 95 | File.Move(this.filePath, rotateFilePath); 96 | } 97 | 98 | private String GetRotateFilePath(int index) 99 | { 100 | return String.Format("{0}.{1}", this.filePath, index); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/UnitTest/NamedArgumentHelperTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using Microsoft.VisualStudio.TestTools.UnitTesting; 25 | using System.Collections.Generic; 26 | using EnhancedMonitoring; 27 | using EnhancedMonitoring.Configuration; 28 | 29 | namespace UnitTest 30 | { 31 | [TestClass] 32 | public class NamedArgumentHelperTest 33 | { 34 | [TestMethod] 35 | public void TestResolveNamedArgument() 36 | { 37 | var str = "MaxClockSpeed_{0}_{1}"; 38 | var expected = "MaxClockSpeed_ubuntu_0"; 39 | var argsName = new List(){ 40 | new WhereArgConfiguration(){ Name ="VirtualMachine"}, 41 | new WhereArgConfiguration(){Name = "ProcessorId" } 42 | }; 43 | var args = new Dictionary() 44 | { 45 | {"VirtualMachine", "ubuntu"}, 46 | {"ProcessorId", 0} 47 | }; 48 | 49 | Assert.AreEqual(expected, NamedArgumentHelper.Resolve(str, argsName, args)); 50 | } 51 | 52 | [TestMethod] 53 | public void TestResolveNamedArgumentNagativeCase() 54 | { 55 | var str = "MaxClockSpeed_{0}_{1}"; 56 | var argsName = new List(){ 57 | new WhereArgConfiguration(){ Name ="VirtualMachine"}, 58 | new WhereArgConfiguration(){Name = "ProcessorId" } 59 | }; 60 | var args = new Dictionary(){ {"VirtualMachine", "ubuntu"}}; 61 | 62 | //Argument name is null 63 | try 64 | { 65 | NamedArgumentHelper.Resolve(str, null, args); 66 | Assert.Fail("FormatException is expected"); 67 | } 68 | catch (ArgumentException e) 69 | { 70 | Console.WriteLine(e); 71 | } 72 | 73 | //Argument names are less than cells 74 | try 75 | { 76 | NamedArgumentHelper.Resolve(str, new List() { 77 | new WhereArgConfiguration(){Name = "VirtualMachine"} }, args); 78 | Assert.Fail("FormatException is expected"); 79 | } 80 | catch (ArgumentException e) 81 | { 82 | Console.WriteLine(e); 83 | } 84 | 85 | //Name argument map is null 86 | try 87 | { 88 | NamedArgumentHelper.Resolve(str, argsName, null); 89 | Assert.Fail("ArgumentException is expected"); 90 | } 91 | catch (ArgumentException e) 92 | { 93 | Console.WriteLine(e); 94 | } 95 | 96 | //Named argument not found 97 | try 98 | { 99 | NamedArgumentHelper.Resolve(str, argsName, args); 100 | Assert.Fail("ArgumentException is expected"); 101 | } 102 | catch (ArgumentException e) 103 | { 104 | Console.WriteLine(e); 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/SupportedVMDetector.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Configuration; 24 | using EnhancedMonitoring.Logging; 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using System.Management; 29 | using System.Text; 30 | using System.Threading.Tasks; 31 | using System.Xml; 32 | 33 | namespace EnhancedMonitoring 34 | { 35 | public class SupportedVMDetector 36 | { 37 | protected const String WMI_Namespace = @"root\virtualization\v2"; 38 | protected const String WMI_Class_Msvm_ComputerSystem = @"Msvm_ComputerSystem"; 39 | protected const String WMI_Class_Msvm_KvpExchangeComponent = @"Msvm_KvpExchangeComponent"; 40 | 41 | public static SupportedVMDetector CreateInstance(SupportedVMDetectorConfiguration conf) 42 | { 43 | return new SupportedVMDetector(conf); 44 | } 45 | 46 | private String SupportedVMKey; 47 | public SupportedVMDetector(SupportedVMDetectorConfiguration conf) 48 | { 49 | this.SupportedVMKey = conf.GuestDataItemKey; 50 | } 51 | 52 | public IList> GetSupportedVM() 53 | { 54 | using (var vms = WMIHelper.QueryInstacnes(WMI_Namespace, WMI_Class_Msvm_ComputerSystem, "EnabledState = 2 and Caption='Virtual Machine'")) 55 | { 56 | var tasks = new List>>(); 57 | foreach(var vm in vms.Cast()) 58 | { 59 | tasks.Add(Task.Run>(() => 60 | { 61 | var objs = vm.GetRelated(WMI_Class_Msvm_KvpExchangeComponent); 62 | foreach (var obj in objs) 63 | { 64 | var kvps = obj.Properties["GuestExchangeItems"].Value as String[]; 65 | 66 | if (kvps.Any(kvp => kvp.IndexOf(this.SupportedVMKey) >= 0)) 67 | { 68 | var vmdata = new Dictionary(); 69 | vmdata.Add("VirtualMachineName", vm.Properties["Name"].Value); 70 | vmdata.Add("VirtualMachineElementName", vm.Properties["ElementName"].Value); 71 | vmdata.Add("VirtualMachinePath", vm.Path); 72 | vmdata.Add("GuestExchangeItems", kvps); 73 | return vmdata; 74 | } 75 | } 76 | return null; 77 | })); 78 | } 79 | try 80 | { 81 | var task = Task.WhenAll>(tasks); 82 | task.Wait(); 83 | return task.Result.Where(x => x != null).ToList(); 84 | } 85 | catch(AggregateException e) 86 | { 87 | foreach(var inner in e.InnerExceptions) 88 | { 89 | Logger.Error(inner); 90 | throw inner; 91 | } 92 | throw; 93 | } 94 | } 95 | } 96 | 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/UnitTest/SampleMonitor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 27 | 28 | 29 | 30 | 31 | 60 32 | 33 | 34 | 1.0.0 35 | 36 | 37 | Enhanced_Monitoring_Metric_Data_Item_Part_ 38 | 39 | 40 | 700 41 | 42 | 43 | 44 | 10 45 | 46 | 47 | 48 | 4194304 49 | 50 | 51 | c:\ProgramData\Enhanced Monitoring\log 52 | 53 | 54 | true 55 | 200 56 | 57 | 58 | 59 | 60 | 61 | 62 | Enhanced_Monitoring_Supported 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | VirtualMachineStatus 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | root\cimv2 85 | 86 | 87 | 88 | WIN32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor 89 | 90 | 91 | 92 | Name like "%%{0}%%" 93 | 94 | 95 | 96 | 97 | 98 | VirtualMachineElementName 99 | 100 | 101 | 102 | 103 | 104 | 105 | VirtualProcessor_PercentHypervisorRuntime 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /src/UnitTest/FormatHelperTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using Microsoft.VisualStudio.TestTools.UnitTesting; 25 | using System.Collections.Generic; 26 | using EnhancedMonitoring.DataFormat; 27 | using System.Runtime.Serialization; 28 | 29 | namespace UnitTest 30 | { 31 | [TestClass] 32 | public class FormatHelperTest 33 | { 34 | [TestMethod] 35 | public void TestToXml() 36 | { 37 | String expected = System.IO.File.ReadAllText(@"..\..\TestToXmlExpectedOutput.xml"); 38 | var data = new Dictionary(); 39 | data.Add("Name", "Dictionary(JSON object) to Xml Test"); 40 | data.Add("TestCases", new String[] 41 | { 42 | "Case1: String as Field", 43 | "Case2: String Array as Field", 44 | "Case3: Dictionary as Field", 45 | "Case4: Object Array as Field", 46 | "Case5: Null" 47 | }); 48 | data.Add("ExpectedBehavior", new Dictionary() { 49 | {"ForAll", "Key name as XElement name "}, 50 | {"Case1", "String content as XElement content"}, 51 | {"Case2", "Each element becomes a child XElement with name 'Item'"}, 52 | {"Case3", "Dictionary becomes a child XElement"}, 53 | {"Case4", new String[] 54 | { 55 | "1. Each element in the array is a dictionary", 56 | "2. The 1st dictionary itself contains an array field", 57 | "3. The 2nd dictionary itself contains a dictionary" 58 | } 59 | }, 60 | {"Case5", "Output 'null'"} 61 | }); 62 | data.Add("ObjectArray", new Dictionary[] { 63 | new Dictionary() 64 | { 65 | {"ArrayObject", new String[]{"Element 1", "Element 1"}} 66 | }, 67 | new Dictionary() 68 | { 69 | { 70 | "DictionaryObject", new Dictionary() 71 | { 72 | {"ObjectField", "ObjectValue"} 73 | } 74 | } 75 | }, 76 | }); 77 | data.Add("HandleNull", null); 78 | 79 | var xmlStr = DataFormatHelper.ToXml(data); 80 | Console.WriteLine(xmlStr); 81 | Assert.AreEqual(expected, xmlStr); 82 | } 83 | 84 | [TestMethod] 85 | public void TestToXmlNegative() 86 | { 87 | var data = new Dictionary(); 88 | data.Add("", null); 89 | try 90 | { 91 | DataFormatHelper.ToXml(data); 92 | } 93 | catch (ArgumentException e) 94 | { 95 | Assert.AreEqual("Node name can't be null or empty.", e.Message); 96 | } 97 | 98 | data.Clear(); 99 | data.Add("Node Name with Space", "Space will be replaced with _"); 100 | var xmlStr = DataFormatHelper.ToXml(data); 101 | String expected = 102 | @" 103 | Space will be replaced with _ 104 | "; 105 | Assert.AreEqual(expected, xmlStr); 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /packages/MSI/EnhancedMonitoring/Setup.wixproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x64 6 | 3.8 7 | a6aa397b-1031-4fbf-9a8a-b50ee7318ec6 8 | 2.0 9 | Debug.EnhancedMonitoring 10 | Package 11 | $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets 12 | $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets 13 | 14 | 15 | bin\$(Configuration)\ 16 | obj\$(Configuration)\ 17 | Debug 18 | 19 | 20 | bin\$(Configuration)\ 21 | obj\$(Configuration)\ 22 | 23 | 24 | Debug 25 | bin\$(Platform)\$(Configuration)\ 26 | obj\$(Platform)\$(Configuration)\ 27 | 28 | 29 | bin\$(Platform)\$(Configuration)\ 30 | obj\$(Platform)\$(Configuration)\ 31 | 32 | 33 | bin\$(Platform)\$(Configuration)\ 34 | obj\$(Platform)\$(Configuration)\ 35 | 36 | 37 | Debug 38 | bin\$(Platform)\$(Configuration)\ 39 | obj\$(Platform)\$(Configuration)\ 40 | 41 | 42 | bin\$(Platform)\$(Configuration)\ 43 | obj\$(Platform)\$(Configuration)\ 44 | 45 | 46 | Debug 47 | bin\$(Platform)\$(Configuration)\ 48 | obj\$(Platform)\$(Configuration)\ 49 | 50 | 51 | 52 | $(WixExtDir)\WixUIExtension.dll 53 | WixUIExtension 54 | 55 | 56 | $(WixExtDir)\WixUtilExtension.dll 57 | WixUtilExtension 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | EnhancedMonitoring 66 | {7eacc378-2947-4f2e-ab0f-eb57be7d3680} 67 | True 68 | True 69 | Binaries;Content;Satellites 70 | INSTALLFOLDER 71 | 72 | 73 | Service 74 | {ed1f3b96-683f-4d16-b4f9-06765e3697c1} 75 | True 76 | True 77 | Binaries;Content;Satellites 78 | INSTALLFOLDER 79 | 80 | 81 | 82 | 90 | -------------------------------------------------------------------------------- /src/UnitTest/KVPWriterTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Linq; 25 | using Microsoft.VisualStudio.TestTools.UnitTesting; 26 | using System.Collections.Generic; 27 | using EnhancedMonitoring; 28 | using System.Management; 29 | using EnhancedMonitoring.Configuration; 30 | 31 | namespace UnitTest 32 | { 33 | [TestClass] 34 | public class KVPWriterTest 35 | { 36 | 37 | private const String testKey = "TestKVPWriterKey1"; 38 | private const String testKey2 = "TestKVPWriterKey2"; 39 | 40 | //[TestMethod] 41 | public void TestOverloadKVP() 42 | { 43 | var vm = WMIHelper.QueryFirstInstacne(@"root\virtualization\v2", "Msvm_ComputerSystem ", "enabledstate = 2 and caption = 'Virtual Machine'"); 44 | Assert.IsNotNull(vm); 45 | 46 | var writer = KeyValuePairWriter.CreateInstance(new KvpConfiguration()); 47 | var data = new Dictionary(); 48 | 49 | var chars = new char[1000]; 50 | for(int i = 0; i < chars.Length; i++) 51 | { 52 | chars[i] = 'a'; 53 | } 54 | var val = new String(chars); 55 | for (int i = 0; i < 1000; i++ ) 56 | { 57 | data.Clear(); 58 | for (int j = 0; j < 10; j++) 59 | { 60 | data.Add(String.Format("TestKVP_{0}", j), val); 61 | } 62 | 63 | var args = new Dictionary() { 64 | {"VirtualMachinePath", vm.Path.ToString()}, 65 | {"VirtualMachineName", vm.Properties["Name"].Value}, 66 | }; 67 | 68 | writer.Remove(args, data); 69 | writer.Write(args, data); 70 | } 71 | vm.Dispose(); 72 | } 73 | 74 | [TestMethod] 75 | public void TestWriteKVP() 76 | { 77 | 78 | var vm = WMIHelper.QueryFirstInstacne(@"root\virtualization\v2", "Msvm_ComputerSystem ", "enabledstate = 2 and caption = 'Virtual Machine'"); 79 | Assert.IsNotNull(vm); 80 | 81 | var writer = KeyValuePairWriter.CreateInstance(new KvpConfiguration()); 82 | var data = new Dictionary(); 83 | data.Add(testKey, DateTime.Now.ToString()); 84 | data.Add(testKey2, DateTime.Now.ToString()); 85 | 86 | var args = new Dictionary() { 87 | {"VirtualMachinePath", vm.Path.ToString()}, 88 | {"VirtualMachineName", vm.Properties["Name"].Value}, 89 | }; 90 | 91 | writer.Remove(args, data); 92 | writer.Write(args, data); 93 | 94 | vm.Dispose(); 95 | } 96 | 97 | //Uncomment the following line to cleanup kvp 98 | //[TestMethod] 99 | public void CleanupKVP() 100 | { 101 | using (var vm = WMIHelper.QueryFirstInstacne(@"root\virtualization\v2", "Msvm_ComputerSystem ", "enabledstate = 2 and caption = 'Virtual Machine'")) 102 | { 103 | Assert.IsNotNull(vm); 104 | Console.WriteLine("Clean up kvp for: " + vm.Properties["ElementName"].Value); 105 | var writer = KeyValuePairWriter.CreateInstance(new KvpConfiguration()); 106 | 107 | var NULL = new Object(); 108 | 109 | var data = new Dictionary(); 110 | data.Add(testKey, NULL); 111 | data.Add(testKey2, NULL); 112 | 113 | var args = new Dictionary() 114 | { 115 | {"VirtualMachinePath", vm.Path.ToString()}, 116 | {"VirtualMachineName", vm.Properties["Name"].Value}, 117 | }; 118 | 119 | writer.Remove(args, data); 120 | 121 | data.Clear(); 122 | for (int i = 0; i < 50; i++) 123 | { 124 | data.Add("Enhanced_Monitoring_Metric_Data_Item_Part_" + i, NULL); 125 | } 126 | writer.Remove(args, data); 127 | } 128 | 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/Logging/Logger.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Configuration; 24 | using System; 25 | using System.Collections.Generic; 26 | using System.Diagnostics; 27 | using System.Linq; 28 | using System.Text; 29 | using System.Threading.Tasks; 30 | 31 | namespace EnhancedMonitoring.Logging 32 | { 33 | public class Logger 34 | { 35 | private static Object instanceLock = new Object(); 36 | private static Logger instance = null; 37 | private const String DateFormat = "yyyy-MM-dd hh:mm:ss.fff"; 38 | public static Logger Instance 39 | { 40 | get 41 | { 42 | lock(instanceLock) 43 | { 44 | if (instance == null) 45 | { 46 | throw new NullReferenceException("Log hasn't been initialized"); 47 | } 48 | } 49 | return instance; 50 | } 51 | } 52 | 53 | public static void Init(MonitorConfiguration conf) 54 | { 55 | Init(conf, new LogWriter[] 56 | { 57 | new FileLogWriter(conf), 58 | new EventLogWriter(conf) 59 | }); 60 | } 61 | 62 | public static void Init(MonitorConfiguration conf, IList writers) 63 | { 64 | lock (instanceLock) 65 | { 66 | if (instance == null) 67 | { 68 | instance = new Logger(conf); 69 | instance.AddWriters(writers); 70 | } 71 | } 72 | } 73 | 74 | public static void Verbose(String format, params Object[] args) 75 | { 76 | Logger.Instance.Log(LogLevel.Verbose, format, args); 77 | } 78 | 79 | public static void Verbose(Exception e) 80 | { 81 | Verbose(ExceptionToString(e)); 82 | } 83 | 84 | public static void Info(String format, params Object[] args) 85 | { 86 | Logger.Instance.Log(LogLevel.Info, format, args); 87 | } 88 | 89 | public static void Info(Exception e) 90 | { 91 | Info(ExceptionToString(e)); 92 | } 93 | 94 | public static void Warn(String format, params Object[] args) 95 | { 96 | Logger.Instance.Log(LogLevel.Warning, format, args); 97 | } 98 | 99 | public static void Warn(Exception e) 100 | { 101 | Warn(ExceptionToString(e)); 102 | } 103 | 104 | public static void Error(String format, params Object[] args) 105 | { 106 | Logger.Instance.Log(LogLevel.Error, format, args); 107 | } 108 | 109 | public static void Error(Exception e) 110 | { 111 | Error(ExceptionToString(e)); 112 | } 113 | 114 | private static String ExceptionToString(Exception e) 115 | { 116 | return String.Format("{0}\n{1}", e, e.StackTrace); 117 | } 118 | 119 | private LogLevel logLevel = LogLevel.Info; 120 | private List writers = new List(); 121 | 122 | private Logger(MonitorConfiguration conf) 123 | { 124 | Enum.TryParse(conf.LogLevel, out this.logLevel); 125 | } 126 | 127 | public void AddWriters(IList writers) 128 | { 129 | this.writers.AddRange(writers); 130 | } 131 | 132 | public void Log(LogLevel level, String format, params Object[] args) 133 | { 134 | if(level < logLevel) 135 | { 136 | return; 137 | } 138 | 139 | String logMsg = format; 140 | if(args != null && args.Count() != 0) 141 | { 142 | logMsg = String.Format(format, args); 143 | } 144 | 145 | String date = DateTime.Now.ToString(DateFormat); 146 | String msg = String.Format("{0} {1}\t{2}", date, level.ToString().ToUpper(), logMsg); 147 | foreach(var writer in writers) 148 | { 149 | writer.Write(level, msg); 150 | } 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/Service/Service.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {ED1F3B96-683F-4D16-B4F9-06765E3697C1} 8 | WinExe 9 | Properties 10 | EnhancedMonitoringProvider.Service 11 | EnhancedMonitoringProvider.Service 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | true 36 | bin\DebugAndRelease\ 37 | DEBUG;TRACE 38 | full 39 | AnyCPU 40 | prompt 41 | MinimumRecommendedRules.ruleset 42 | true 43 | 44 | 45 | true 46 | bin\x64\Debug\ 47 | DEBUG;TRACE 48 | full 49 | x64 50 | prompt 51 | MinimumRecommendedRules.ruleset 52 | true 53 | 54 | 55 | bin\x64\Release\ 56 | TRACE 57 | true 58 | pdbonly 59 | x64 60 | prompt 61 | MinimumRecommendedRules.ruleset 62 | true 63 | 64 | 65 | true 66 | bin\x64\DebugAndRelease\ 67 | DEBUG;TRACE 68 | full 69 | x64 70 | prompt 71 | MinimumRecommendedRules.ruleset 72 | true 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | Component 87 | 88 | 89 | EnhacedMonitoringProvider.cs 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | EnhacedMonitoringProvider.cs 100 | 101 | 102 | 103 | 104 | {7eacc378-2947-4f2e-ab0f-eb57be7d3680} 105 | EnhancedMonitoring 106 | 107 | 108 | 109 | 116 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/DataCollector/DynamicMemoryMgmtObject.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Configuration; 24 | using System; 25 | using System.Collections.Generic; 26 | using System.Linq; 27 | using System.Management; 28 | using System.Text; 29 | 30 | namespace EnhancedMonitoring.DataCollector 31 | { 32 | public class DynamicMemoryMgmtObject : MgmtObject 33 | { 34 | public const String WMI_Namespace = @"root\virtualization\v2"; 35 | public const String WMI_Class_Msvm_ComputerSystem = @"Msvm_ComputerSystem"; 36 | public const String WMI_Class_Msvm_VirtualSystemManagementService = @"Msvm_VirtualSystemManagementService"; 37 | public const String WMI_Class_Msvm_VirtualSystemSettingData = @"Msvm_VirtualSystemSettingData"; 38 | public const String WMI_Method_GetSummaryInformation = @"GetSummaryInformation"; 39 | 40 | public const UInt32 RequestedInformation_MemoryUsage = 103; 41 | public const String KeyName_MemoryUsage = "MemoryUsage"; 42 | public const UInt32 RequestedInformation_MemoryAvailable = 112; 43 | public const String KeyName_MemoryAvailable = "MemoryAvailable"; 44 | public const UInt32 RequestedInformation_AvaiableMemoryBuffer = 113; 45 | public const String KeyName_AvailableMemoryBuffer = "AvailableMemoryBuffer"; 46 | 47 | 48 | public DynamicMemoryMgmtObject(MgmtObjectConfiguration conf) : base(conf) 49 | { 50 | } 51 | 52 | public override Object CollectData(IDictionary args) 53 | { 54 | using (var vmMgmt = WMIHelper.GetFirstInstance(WMI_Namespace, WMI_Class_Msvm_VirtualSystemManagementService)) 55 | using (var vm = WMIHelper.QueryFirstInstacne(WMI_Namespace, WMI_Class_Msvm_ComputerSystem, 56 | String.Format("Name='{0}'", args["VirtualMachineName"]))) 57 | using (var vmSettings = vm.GetRelated(WMI_Class_Msvm_VirtualSystemSettingData)) 58 | using (var inParams = vmMgmt.GetMethodParameters(WMI_Method_GetSummaryInformation)) 59 | { 60 | String[] settingDataPath = new String[vmSettings.Count]; 61 | int i = 0; 62 | foreach (ManagementObject vmSetting in vmSettings) 63 | { 64 | settingDataPath[i++] = vmSetting.Path.Path; 65 | break; 66 | } 67 | var data = new Dictionary() 68 | { 69 | {KeyName_MemoryUsage, null}, 70 | {KeyName_MemoryAvailable, null}, 71 | {KeyName_AvailableMemoryBuffer, null}, 72 | }; 73 | 74 | if (settingDataPath.Length != 0) 75 | { 76 | inParams["SettingData"] = settingDataPath; 77 | inParams["RequestedInformation"] = new UInt32[] 78 | { 79 | RequestedInformation_MemoryUsage, 80 | RequestedInformation_MemoryAvailable, 81 | RequestedInformation_AvaiableMemoryBuffer 82 | }; 83 | 84 | var outParams = vmMgmt.InvokeMethod(WMI_Method_GetSummaryInformation, inParams, null); 85 | if ((UInt32)outParams["ReturnValue"] == 0)//Completed 86 | { 87 | var summaryInfoList = (ManagementBaseObject[])outParams["SummaryInformation"]; 88 | var summaryInfo = summaryInfoList.FirstOrDefault(); 89 | data[KeyName_MemoryUsage] = summaryInfo[KeyName_MemoryUsage]; 90 | data[KeyName_MemoryAvailable] = summaryInfo[KeyName_MemoryAvailable]; 91 | data[KeyName_AvailableMemoryBuffer] = summaryInfo[KeyName_AvailableMemoryBuffer]; 92 | } 93 | else 94 | { 95 | throw new ManagementException(String.Format("Method {0} returns error:{1}", WMI_Method_GetSummaryInformation, 96 | (UInt32)outParams["ReturnValue"])); 97 | } 98 | } 99 | return data; 100 | } 101 | } 102 | 103 | public override String KeyName 104 | { 105 | get 106 | { 107 | return this.conf.As ?? "DynamicMemory"; 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/UnitTest/MetricTest.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Linq; 25 | using Microsoft.VisualStudio.TestTools.UnitTesting; 26 | using EnhancedMonitoring.Configuration; 27 | using EnhancedMonitoring.DataFormat; 28 | using EnhancedMonitoring.DataCollector; 29 | using EnhancedMonitoring; 30 | using System.Collections.Generic; 31 | 32 | namespace UnitTest 33 | { 34 | [TestClass] 35 | public class MetricTest 36 | { 37 | [TestMethod] 38 | public void TestMetricJSON() 39 | { 40 | MonitorConfiguration conf = MonitorConfiguration.Load(@"..\..\..\EnhancedMonitoring\Configuration\EnhancedMonitoringProviderConfig.xml"); 41 | List mgmtObjects = new List(); 42 | foreach (var mgmtObjConf in conf.MgmtObjects) 43 | { 44 | mgmtObjects.Add(MgmtObject.CreateInstance(mgmtObjConf)); 45 | } 46 | 47 | Assert.AreNotEqual(0, mgmtObjects.Count); 48 | 49 | 50 | var data = new Dictionary(); 51 | var vms = SupportedVMDetector.CreateInstance(conf.SupportedVMDetector).GetSupportedVM(); 52 | Assert.AreNotEqual(0, vms.Count); 53 | 54 | var vm = vms.FirstOrDefault(); 55 | 56 | var args = new Dictionary(vm); 57 | 58 | foreach (var mgmtObj in mgmtObjects) 59 | { 60 | var watch = System.Diagnostics.Stopwatch.StartNew(); 61 | try 62 | { 63 | data.Add(mgmtObj.KeyName, mgmtObj.CollectData(args)); 64 | } 65 | catch (Exception e) 66 | { 67 | if (!mgmtObj.SuppressError) 68 | { 69 | Console.WriteLine(e); 70 | Console.WriteLine(e.StackTrace); 71 | Assert.Fail(e.Message); 72 | } 73 | data.Add(mgmtObj.KeyName, null); 74 | } 75 | Console.WriteLine(String.Format("{0}\t{1}", watch.ElapsedMilliseconds, mgmtObj.KeyName)); 76 | } 77 | 78 | Assert.IsNotNull(data); 79 | Assert.AreNotEqual(0, data.Count); 80 | 81 | var xmlStr = DataFormatHelper.ToXml(data); 82 | Console.WriteLine(xmlStr); 83 | 84 | //var jsonStr = DataFormatHelper.ToJSON(data); 85 | 86 | //var encodedStr = DataFormatHelper.Base64Encode(jsonStr); 87 | 88 | //var dataChunks = DataFormatHelper.PackString(jsonStr, 900); 89 | 90 | //var packedData = DataFormatHelper.ToChunk("", dataChunks); 91 | 92 | //var encodedDataChunks = DataFormatHelper.PackString(encodedStr, 900); 93 | 94 | //var encodedPackedData = DataFormatHelper.ToChunk("", encodedDataChunks); 95 | 96 | //Console.WriteLine(JsonHelper.FormatJson(jsonStr)); 97 | //Console.WriteLine(String.Format("Original JSON string length: {0}", jsonStr.Length)); 98 | //Console.WriteLine(String.Format("Encoded JSON string length: {0}", encodedStr.Length)); 99 | //Console.WriteLine(String.Format("Packed JSON string length: {0}", packedData.Select(d => d.Value.ToString().Length).Sum())); 100 | //Console.WriteLine(String.Format("Packed encoded JSON string length: {0}", encodedPackedData.Select(d => d.Value.ToString().Length).Sum())); 101 | 102 | } 103 | 104 | //[TestMethod] 105 | public void TestWMIPerformanceCache() 106 | { 107 | Console.WriteLine("First time query"); 108 | TestMetricJSON(); 109 | System.Threading.Thread.Sleep(60 * 1000); 110 | Console.WriteLine("----------------------------------------------------------------------"); 111 | Console.WriteLine("Second time query, after 60seconds"); 112 | TestMetricJSON(); 113 | } 114 | 115 | //[TestMethod] 116 | public void TestWMIPerformanceMultiple() 117 | { 118 | for(int i= 0; i < 10; i++) 119 | { 120 | var watch = System.Diagnostics.Stopwatch.StartNew(); 121 | TestMetricJSON(); 122 | Console.WriteLine(String.Format("Elapsed: {0}ms \t Total", watch.ElapsedMilliseconds)); 123 | Console.WriteLine("----------------------------------------------------------------------"); 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/EnhancedMonitoring.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7EACC378-2947-4F2E-AB0F-EB57BE7D3680} 8 | Library 9 | Properties 10 | EnhancedMonitoring 11 | EnhancedMonitoring 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | true 34 | bin\DebugAndRelease\ 35 | DEBUG;TRACE 36 | full 37 | AnyCPU 38 | prompt 39 | MinimumRecommendedRules.ruleset 40 | 41 | 42 | true 43 | bin\x64\Debug\ 44 | DEBUG;TRACE 45 | full 46 | x64 47 | prompt 48 | MinimumRecommendedRules.ruleset 49 | 50 | 51 | bin\x64\Release\ 52 | TRACE 53 | true 54 | pdbonly 55 | x64 56 | prompt 57 | MinimumRecommendedRules.ruleset 58 | 59 | 60 | true 61 | bin\x64\DebugAndRelease\ 62 | DEBUG;TRACE 63 | full 64 | x64 65 | prompt 66 | MinimumRecommendedRules.ruleset 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | Designer 111 | 112 | 113 | 114 | 121 | -------------------------------------------------------------------------------- /src/Service/EnhacedMonitoringProvider.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | False 122 | 123 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/DataFormat/DataFormatHelper.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Collections; 25 | using System.Collections.Generic; 26 | using System.IO; 27 | using System.Linq; 28 | using System.Runtime.Serialization; 29 | using System.Text; 30 | using System.Threading.Tasks; 31 | using System.Web.Script.Serialization; 32 | using System.Xml; 33 | using System.Xml.Linq; 34 | 35 | namespace EnhancedMonitoring.DataFormat 36 | { 37 | public static class DataFormatHelper 38 | { 39 | 40 | public const String ChunkCountKey = "all"; 41 | public const String ChunkKey = "data"; 42 | public const String TimestampKey = "ts"; 43 | 44 | public static String ToJSON(IDictionary data) 45 | { 46 | JavaScriptSerializer jsSerializer = new JavaScriptSerializer(); 47 | String jsonStr = jsSerializer.Serialize(data); 48 | return jsonStr; 49 | } 50 | 51 | public static String ToXml(IDictionary data) 52 | { 53 | return DictionaryToXElement("Data", data).ToString(); 54 | } 55 | 56 | private static XElement DictionaryToXElement(String nodeName, IDictionary data) 57 | { 58 | nodeName = NormalizeNodeName(nodeName); 59 | XElement node = new XElement(nodeName); 60 | foreach (var entry in data) 61 | { 62 | node.Add(ObjectToXElement(entry.Key, entry.Value)); 63 | } 64 | return node; 65 | } 66 | 67 | private static XElement ObjectToXElement(String nodeName, Object nodeContent) 68 | { 69 | nodeName = NormalizeNodeName(nodeName); 70 | if (nodeContent is IList) 71 | { 72 | return ListToXElement(nodeName, nodeContent as IList); 73 | } 74 | else if (nodeContent is IDictionary) 75 | { 76 | return DictionaryToXElement(nodeName, nodeContent as IDictionary); 77 | } 78 | else if(nodeContent == null) 79 | { 80 | return new XElement(nodeName, "null"); 81 | } 82 | else 83 | { 84 | return new XElement(nodeName, nodeContent); 85 | } 86 | } 87 | 88 | private static XElement ListToXElement(String nodeName, IList list) 89 | { 90 | nodeName = NormalizeNodeName(nodeName); 91 | XElement node = new XElement(nodeName); 92 | node.SetAttributeValue("Type", "List"); 93 | foreach(var elem in list) 94 | { 95 | node.Add(ObjectToXElement("Item", elem)); 96 | } 97 | return node; 98 | } 99 | private static string NormalizeNodeName(string nodeName) 100 | { 101 | if (String.IsNullOrEmpty(nodeName)) 102 | { 103 | throw new ArgumentException("Node name can't be null or empty."); 104 | } 105 | return nodeName.Trim().Replace(' ', '_'); 106 | } 107 | 108 | public static String Base64Encode(String str) 109 | { 110 | var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(str); 111 | String encoded = System.Convert.ToBase64String(plainTextBytes); 112 | return encoded; 113 | } 114 | 115 | public static IList PackString(String str, int blockLength) 116 | { 117 | var packed = new List(); 118 | var textBytes = System.Text.Encoding.UTF8.GetBytes(str); 119 | 120 | int i = 0; 121 | while (i < textBytes.Length) 122 | { 123 | packed.Add(System.Text.Encoding.UTF8.GetString(textBytes, i, Math.Min(blockLength, textBytes.Length - i))); 124 | i += blockLength; 125 | } 126 | return packed; 127 | } 128 | 129 | public static IDictionary ToChunk(String keyPrefix, IList dataChunks, 130 | Func, String> baseFormater) 131 | { 132 | var packedData = new Dictionary(); 133 | 134 | var timestamp = GetCurrentTime(); 135 | 136 | for (int i = 0; i < dataChunks.Count; i++) 137 | { 138 | var dataChunk = new Dictionary(); 139 | dataChunk.Add(TimestampKey, timestamp); 140 | dataChunk.Add(ChunkCountKey, dataChunks.Count); 141 | dataChunk.Add(ChunkKey, dataChunks[i]); 142 | 143 | packedData.Add(String.Format("{0}{1}", keyPrefix, i), baseFormater(dataChunk)); 144 | } 145 | 146 | return packedData; 147 | } 148 | 149 | public static double GetCurrentTime() 150 | { 151 | //To UNIX like timestamp. Milliseconds since 1970/1/1 00:00:00 UTC 152 | return DateTime.UtcNow 153 | .Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)) 154 | .TotalMilliseconds; 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/UnitTest/TestFileLogWriter.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using System; 24 | using System.Text; 25 | using System.Collections.Generic; 26 | using Microsoft.VisualStudio.TestTools.UnitTesting; 27 | using EnhancedMonitoring.Configuration; 28 | using EnhancedMonitoring.Logging; 29 | using System.IO; 30 | using System.Threading.Tasks; 31 | using System.Diagnostics; 32 | 33 | namespace UnitTest 34 | { 35 | /// 36 | /// Summary description for TestFileLogWriter 37 | /// 38 | [TestClass] 39 | public class TestFileLogWriter 40 | { 41 | 42 | [TestMethod] 43 | public void TestWriteToLogFile() 44 | { 45 | var tmpFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData) 46 | + @"\" + Guid.NewGuid().ToString(); 47 | 48 | var conf = new MonitorConfiguration() 49 | { 50 | LogLevel = "Info", 51 | LogFilePath = tmpFolder + @"\test.log" 52 | }; 53 | 54 | var logWriter = new FileLogWriter(conf); 55 | 56 | String logContent = Guid.NewGuid().ToString(); 57 | logWriter.Write(LogLevel.Info, logContent); 58 | 59 | Assert.IsTrue(File.Exists(conf.LogFilePath)); 60 | String log = File.ReadAllText(conf.LogFilePath); 61 | Assert.IsTrue(log.Contains(logContent)); 62 | 63 | Directory.Delete(tmpFolder, true); 64 | } 65 | 66 | [TestMethod] 67 | public void TestMultithreadWriteToLogFile() 68 | { 69 | var tmpFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData) 70 | + @"\" + Guid.NewGuid().ToString(); 71 | 72 | var conf = new MonitorConfiguration() 73 | { 74 | LogLevel = "Info", 75 | LogFilePath = tmpFolder + @"\test.log" 76 | }; 77 | 78 | var logWriter = new FileLogWriter(conf); 79 | 80 | Task[] tasks = new Task[100]; 81 | for(int i = 0; i < tasks.Length; i++) 82 | { 83 | tasks[i] = Task.Run(() => 84 | { 85 | Console.WriteLine(Process.GetCurrentProcess().Threads.Count); 86 | String logContent = Guid.NewGuid().ToString(); 87 | logWriter.Write(LogLevel.Info, logContent); 88 | 89 | }); 90 | } 91 | Task.WaitAll(tasks); 92 | Directory.Delete(tmpFolder, true); 93 | } 94 | 95 | [TestMethod] 96 | public void TestRotateLog() 97 | { 98 | var tmpFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData) 99 | + @"\" + Guid.NewGuid().ToString(); 100 | 101 | Console.WriteLine(tmpFolder); 102 | Directory.CreateDirectory(tmpFolder); 103 | var conf = new MonitorConfiguration() 104 | { 105 | LogLevel = "Info", 106 | LogFilePath = tmpFolder + @"\test.log", 107 | LogFileSize = 1, 108 | MaxLogRetention = 2 109 | }; 110 | 111 | var logWriter = new FileLogWriter(conf); 112 | 113 | String[] logContent = new String[4] 114 | { 115 | "Test 0","Test 1","Test 2","Test 3", 116 | }; 117 | 118 | //echo "Test 0" > test.log 119 | logWriter.Write(LogLevel.Info, logContent[0]); 120 | //mv test.log test.log.0 121 | //echo "Test 1" > test.log 122 | logWriter.Write(LogLevel.Info, logContent[1]); 123 | 124 | Assert.IsTrue(File.Exists(conf.LogFilePath)); 125 | String log = File.ReadAllText(conf.LogFilePath); 126 | Assert.IsTrue(log.Contains(logContent[1])); 127 | 128 | Assert.IsTrue(File.Exists(conf.LogFilePath + @".0")); 129 | log = File.ReadAllText(conf.LogFilePath + @".0"); 130 | Assert.IsTrue(log.Contains(logContent[0])); 131 | 132 | //mv test.log.0 test.log.1 133 | //mv test.log test.log.0 134 | //echo "Test 2" > test.log 135 | logWriter.Write(LogLevel.Info, logContent[2]); 136 | 137 | //rm test.log.1 138 | //mv test.log.0 test.log.1 139 | //mv test.log test.log.0 140 | //echo "Test 3" test.log 141 | logWriter.Write(LogLevel.Info, logContent[3]); 142 | 143 | Assert.IsTrue(File.Exists(conf.LogFilePath + @".0")); 144 | Assert.IsTrue(File.Exists(conf.LogFilePath + @".1")); 145 | Assert.IsFalse(File.Exists(conf.LogFilePath + @".2")); 146 | 147 | log = File.ReadAllText(conf.LogFilePath); 148 | Assert.IsTrue(log.Contains(logContent[3])); 149 | 150 | 151 | log = File.ReadAllText(conf.LogFilePath + @".1"); 152 | Assert.IsTrue(log.Contains(logContent[1])); 153 | 154 | Directory.Delete(tmpFolder, true); 155 | } 156 | 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/UnitTest/UnitTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {0B568E5B-3796-47CC-B934-C4684CBE241C} 7 | Library 8 | Properties 9 | UnitTest 10 | UnitTest 11 | v4.5 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | x64 29 | 30 | 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | true 40 | bin\DebugAndRelease\ 41 | DEBUG;TRACE 42 | full 43 | AnyCPU 44 | prompt 45 | MinimumRecommendedRules.ruleset 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Designer 89 | 90 | 91 | 92 | 93 | 94 | {7eacc378-2947-4f2e-ab0f-eb57be7d3680} 95 | EnhancedMonitoring 96 | 97 | 98 | 99 | 100 | 101 | 102 | False 103 | 104 | 105 | False 106 | 107 | 108 | False 109 | 110 | 111 | False 112 | 113 | 114 | 115 | 116 | 117 | 118 | 125 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/KeyValuePairWriter.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Configuration; 24 | using System; 25 | using System.Collections.Generic; 26 | using System.Linq; 27 | using System.Management; 28 | using System.Text; 29 | using System.Threading.Tasks; 30 | 31 | namespace EnhancedMonitoring 32 | { 33 | public class KeyValuePairWriter : IDisposable 34 | { 35 | protected const String WMI_Namespace = @"root\virtualization\v2"; 36 | protected const String WMI_Class_Msvm_ComputerSystem = @"Msvm_ComputerSystem"; 37 | protected const String WMI_Class_Msvm_VirtualSystemManagementService = @"Msvm_VirtualSystemManagementService"; 38 | protected const String WMI_Class_Msvm_KvpExchangeDataItem = @"Msvm_KvpExchangeDataItem"; 39 | protected const Int32 DEFAULT_WRITE_INTERVAL = 100; 40 | 41 | public static KeyValuePairWriter CreateInstance(KvpConfiguration conf) 42 | { 43 | return new KeyValuePairWriter(conf); 44 | } 45 | 46 | private bool batchMode = false; 47 | private Int32 writeInterval = DEFAULT_WRITE_INTERVAL; 48 | 49 | protected KeyValuePairWriter(KvpConfiguration conf) 50 | { 51 | if(conf != null) 52 | { 53 | this.batchMode = conf.BatchMode; 54 | this.writeInterval = conf.WriteInterval <= 0 ? DEFAULT_WRITE_INTERVAL : conf.WriteInterval; 55 | } 56 | } 57 | 58 | public void Remove(IDictionary args, IDictionary data) 59 | { 60 | InvokeKvpOperation(args, data, "RemoveKvpItems"); 61 | } 62 | 63 | public void Write(IDictionary args, IDictionary data) 64 | { 65 | InvokeKvpOperation(args, data, "AddKvpItems"); 66 | } 67 | 68 | protected void InvokeKvpOperation(IDictionary args, IDictionary data, String operationName) 69 | { 70 | if (args == null) 71 | { 72 | throw new ArgumentNullException("args"); 73 | } 74 | 75 | if (data == null) 76 | { 77 | throw new ArgumentNullException("data"); 78 | } 79 | 80 | if (data.Count() == 0) 81 | { 82 | return; 83 | } 84 | 85 | var kvpItems = ToKvpItems(data); 86 | using (var vmMgmt = WMIHelper.GetFirstInstance(WMI_Namespace, WMI_Class_Msvm_VirtualSystemManagementService)) 87 | using (var vm = WMIHelper.QueryFirstInstacne(WMI_Namespace, WMI_Class_Msvm_ComputerSystem, String.Format("Name='{0}'", args["VirtualMachineName"]))) 88 | { 89 | if(batchMode) 90 | { 91 | InvokeKvpOperation(vmMgmt, vm, operationName, kvpItems); 92 | } 93 | else 94 | { 95 | foreach (var kvpItem in kvpItems) 96 | { 97 | InvokeKvpOperation(vmMgmt, vm, operationName, new String[] { kvpItem }); 98 | } 99 | } 100 | 101 | } 102 | } 103 | 104 | protected void InvokeKvpOperation(ManagementObject vmMgmt, ManagementObject vm, String operationName, String[] kvpItems) 105 | { 106 | using (var inParams = vmMgmt.GetMethodParameters(operationName)) 107 | { 108 | inParams["DataItems"] = kvpItems; 109 | inParams["TargetSystem"] = vm; 110 | 111 | using (var outParams = vmMgmt.InvokeMethod(operationName, inParams, null)) 112 | { 113 | //Delay a small mount of time to avoid overwhelm the KVP VSC in the guest. 114 | Task.Delay(this.writeInterval); 115 | WMIHelper.WaitForAsyncJob(outParams, WMI_Namespace); 116 | } 117 | } 118 | } 119 | 120 | protected static String ToKvpItem(KeyValuePair kvp) 121 | { 122 | using (var kvpItem = WMIHelper.CreateInstance(WMI_Namespace, WMI_Class_Msvm_KvpExchangeDataItem)) 123 | { 124 | kvpItem["Name"] = kvp.Key; 125 | kvpItem["Data"] = kvp.Value; 126 | kvpItem["Source"] = 0; 127 | return ((ManagementBaseObject)kvpItem).GetText(TextFormat.CimDtd20); 128 | } 129 | } 130 | 131 | protected static String[] ToKvpItems(IDictionary data) 132 | { 133 | var dataItems = data.Select((kvp) => 134 | { 135 | return ToKvpItem(kvp); 136 | }).ToArray(); 137 | return dataItems; 138 | } 139 | 140 | #region IDisposable 141 | bool disposed = false; 142 | 143 | public void Dispose() 144 | { 145 | // Dispose of unmanaged resources. 146 | Dispose(true); 147 | // Suppress finalization. 148 | GC.SuppressFinalize(this); 149 | } 150 | // Protected implementation of Dispose pattern. 151 | protected virtual void Dispose(bool disposing) 152 | { 153 | if (disposed) 154 | return; 155 | 156 | if (disposing) 157 | { 158 | 159 | } 160 | 161 | disposed = true; 162 | } 163 | #endregion 164 | 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/DataCollector/QueryMgmtObject.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Configuration; 24 | using EnhancedMonitoring.Logging; 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Linq; 28 | using System.Management; 29 | using System.Text; 30 | using System.Threading.Tasks; 31 | 32 | namespace EnhancedMonitoring.DataCollector 33 | { 34 | public class QueryMgmtObject : MgmtObject 35 | { 36 | 37 | private String[] selectedProperties; 38 | 39 | internal QueryMgmtObject(MgmtObjectConfiguration conf) : base(conf) 40 | { 41 | //If specific perf count is given, instead of "*", which means select all, 42 | // we should construct an array of selected properties and parse it through WQL query to improve performance 43 | if (this.conf.PerfCounters != null && this.conf.PerfCounters.Count != 0 44 | && !this.conf.PerfCounters.Any(counter => !String.IsNullOrEmpty(counter.Select) && counter.Select.Equals("*"))) 45 | { 46 | //The properties start with "_" needs to be handled specially. 47 | //Like "_Path", it is not in Properties set, which is by the design of .net's WMI libary. 48 | this.selectedProperties = this.conf.PerfCounters 49 | .Select(counter => counter.Select).Where(p => !String.IsNullOrEmpty(p) && !p.StartsWith("_")).ToArray(); 50 | } 51 | } 52 | 53 | /// 54 | /// 55 | /// 56 | /// Named arguments used in "Where" field of WQL query 57 | /// 58 | public override Object CollectData(IDictionary args) 59 | { 60 | if(args == null) 61 | { 62 | throw new ArgumentNullException("args"); 63 | } 64 | 65 | if (this.conf.PerfCounters == null) 66 | { 67 | return null; 68 | } 69 | 70 | String condition = String.Empty; 71 | 72 | condition = NamedArgumentHelper.Resolve(this.conf.Where, this.conf.WhereArgs, args); 73 | 74 | if (this.conf.PerfCounters == null || this.conf.PerfCounters.Count == 0) 75 | { 76 | return null; 77 | } 78 | 79 | using (var result = WMIHelper.QueryInstacnes(this.conf.Namespace, this.conf.From, condition, this.selectedProperties)) 80 | { 81 | var mgmtObjs = result.Cast(); 82 | if(this.conf.ReturnValueType == MgmtObjectReturnValueType.Single) 83 | { 84 | var mgmtObj = mgmtObjs.FirstOrDefault(); 85 | return SelectPerfCounter(mgmtObj, args); 86 | } 87 | else 88 | { 89 | var list = new List(); 90 | foreach (var mgmtObj in mgmtObjs) 91 | { 92 | list.Add(SelectPerfCounter(mgmtObj, args)); 93 | } 94 | return list; 95 | } 96 | 97 | } 98 | } 99 | 100 | private IDictionary SelectPerfCounter(ManagementObject mgmtObj, IDictionary args) 101 | { 102 | IDictionary data = new Dictionary(); 103 | 104 | this.conf.PerfCounters.ForEach(counter => 105 | { 106 | if (counter.Select.Equals("*")) 107 | { 108 | foreach (var prop in mgmtObj.Properties) 109 | { 110 | var key = prop.Name; 111 | var val = prop.Value; 112 | if (data.ContainsKey(key)) 113 | { 114 | throw new ArgumentException(String.Format("Metric:'{0}' already exists", key)); 115 | } 116 | else 117 | { 118 | data.Add(key, val); 119 | } 120 | } 121 | } 122 | else if (counter.Select.Equals("_Path")) 123 | { 124 | var key = counter.As ?? "Path"; 125 | var val = mgmtObj.Path; 126 | if (data.ContainsKey(key)) 127 | { 128 | throw new ArgumentException(String.Format("Metric:'{0}' already exists", key)); 129 | } 130 | else 131 | { 132 | data.Add(key, val); 133 | } 134 | } 135 | else 136 | { 137 | try 138 | { 139 | var property = mgmtObj.Properties[counter.Select.Trim()]; 140 | var key = counter.As ?? property.Name; 141 | var val = property.Value; 142 | if (data.ContainsKey(key)) 143 | { 144 | throw new ArgumentException(String.Format("Metric:'{0}' already exists", key)); 145 | } 146 | else 147 | { 148 | data.Add(key, val); 149 | } 150 | } 151 | catch (ManagementException e) 152 | { 153 | throw new ManagementException(String.Format("Property:'{0}' not found", counter.Select), e); 154 | } 155 | } 156 | }); 157 | return data; 158 | } 159 | 160 | public override String KeyName 161 | { 162 | get 163 | { 164 | return this.conf.From ?? this.conf.As; 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #How to install and configure the Enhanced Monitoring Service on Windows Server 2012 R2 Hyper-V 2 | 3 | The Enhanced Monitoring Service is a Windows service at the Hyper-V parent partition which makes enhanced configuration and performance information for a virtual machine accessible from within the virtual machine. This information might be related to the parent partition as well as to the virtual machine. 4 | The data exchange channel used between the parent partition and its virtual machines relies on the [KVP data exchange machanism](https://technet.microsoft.com/en-us/library/dn798297.aspx). This mechanism is implemented as a read-only interface between parent partition and its virtual machines, so that no changes on the parent partition can be triggered by the virtual machine through that interface. 5 | 6 | ##Prerequisites 7 | 8 | You use Windows Server 2012 R2 Hyper-V. 9 | 10 | ##Enable the Enhanced Monitoring 11 | 12 | To enable the Enhanced Monitoring for a virtual machine, you have to: 13 | 14 | * Enable the Hyper-V parent partition to provide Enhanced Monitoring data to the virtual machine 15 | 16 | * Enable the virtual machine to receive Enhanced Monitoring data 17 | 18 | By the two-step approach during enablement of the Enhanced Monitoring, you have full control on which virtual machines you enable the Enhanced Monitoring data. If you want to disallow a certain virtual machine to view Enhanced Monitoring data, don't enable the activation parameter on virtual machine level so that no monitoring data are collected. 19 | 20 | ### On the Hyper-V parent partition: Install the Enhanced Monitoring Service 21 | 22 | To install the Enhanced Monitoring Service, execute the following steps on the Hyper-V parent partition: 23 | 24 | 1. Download the installation package [EnhancedMonitoring.msi](https://github.com/OSTC/enhanced-monitoring-service/releases/download/v1.1/EnhancedMonitoring.msi). 25 | 26 | 3. Execute the installation package to install the Enhanced Monitoring Service. 27 | 28 | ![](doc/finish.png) 29 | 30 | 3. After the installation, confirm that the Windows service "Enhanced Monitoring Provider Service" is running, and that its Startup Type is set to "Automatic (Delayed Start)". 31 | 32 | ![](doc/service.png) 33 | 34 | ###On the Virtual Machine: Activate the Enhanced Monitoring 35 | 36 | Activate the Enhanced Monitoring on the virtual machine by setting the key-value-pair ```Enhanced_Monitoring_Supported=1```. Only if this key-value-pair is set inside the virtual machine, the Enhanced Monitoring Service will populate the KVP data exchange channel with monitoring data for this virtual machine. 37 | 38 | To set the key-value-pair inside the virtual machine, proceed as follows: 39 | * **Guest OS Linux**: 40 | 41 | Write the key-value-pair ```Enhanced_Monitoring_Supported=1``` to the file ```/var/lib/hyperv/.kvp_pool_1```. 42 | 43 | * **Guest OS Windows**: 44 | 45 | Open the Windows registry and change to the registry key ```HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Virtual Machine\Guest```. 46 | 47 | Create a ```REG_DWORD``` value with the name ```Enhanced_Monitoring_Supported``` and set its value to 1. 48 | 49 | Note: Make sure that the virtual machines to monitor have different names and that the virtual machine name does not contain one of the following characters: 50 | ```( ) * / # "``` 51 | This limitation is introduced by Hyper-V. 52 | 53 | ##How to Configure and Access the Enhanced Monitoring Data 54 | 55 | ###How to Access Enhanced Monitoring Data on the Virtual Machine 56 | 57 | If you have configured the virtual machine to receive monitoring data by adding the key-value-pair described above, the parent partition will provide enhanced monitoring information to the guest VM through the KVP channel. 58 | The enhanced monitoring data is provided as follows: 59 | * **Guest OS Linux**: 60 | 61 | In a Linux VM the monitoring data is part of the tree ```/var/lib/hyperv/.kvp_pool_0```. 62 | 63 | * **Guest OS Windows**: 64 | 65 | In a Windows VM, the data is provided under the registry key ```HKEY_LOCAL_MACHINE \SOFTWARE\Microsoft\Virtual Machine\External```. 66 | 67 | The performance data is base64-encoded and split into multiple parts to follow the length limitation of the KVP channel. 68 | For sample code on how to parse the data within the virtual machine, check the following [sample](/sample). 69 | 70 | ###How to Configure the Enhanced Monitoring Service 71 | 72 | The Enhanced Monitoring Service collects by default the information which is part of its configuration file 73 | ```C:\ProgramData\Enhanced Monitoring\EnhancedMonitoringProviderConfig.xml```. 74 | 75 | Microsoft advises to leave the configuration file unchanged. However, you could add further information to be collected by the service to this configuration file or you might want to increase the log level of the Enhanced Monitoring Service for troubleshooting purposes. 76 | 77 | **Note**: Any modification to the configuration file will only take effect after you restart the Windows service ‘Enhanced Monitoring Provider Service’. 78 | 79 | ###How to Configure the Refresh Interval of the Enhanced Monitoring Data 80 | 81 | By default, the Enhanced Monitoring Service updates the monitoring data for its virtual machines within a refresh interval of 60 seconds. 82 | 83 | However, if you have a large number of guest VMs (more than 40) running on the same parent partition, the KVP mechanism might need too much time to collect and provision the required data to its virtual machines. 84 | In this case, increase the refresh interval of the Enhanced Monitoring Service to 120 seconds by setting the value for parameter "RefreshRate" in the configuration file to 120. 85 | ``` 86 | 87 | 88 | 120 89 | ``` 90 | To adapt the configuration file of the Enhanced Monitoring Service, proceed as described in section ‘How to Configure the Enhanced Monitoring Service’. 91 | 92 | ###How to Increase the WMI quota 93 | 94 | The Enhanced Monitoring Service relies on the WMI Provider Service to monitor the performance and resource status of the parent partition. However, the WMI Provider Service has a resource limitation for threads, memory, etc. If you have a large number of virtual machines (more than 40), you need to increase the WMI quota, and otherwise you let it unchanged. Likewise, if you have other workloads that might use the WMI Provider Service running on the same host, you also need to increase the quota. 95 | To increase the WMI quota, follow [How to Increase WMI quota](http://blogs.technet.com/b/askperf/archive/2008/09/16/memory-and-handle-quotas-in-the-wmi-provider-service.aspx). 96 | 97 | ##Troubleshoot the Enhanced Monitoring 98 | 99 | ###Check the Enhanced Monitoring Service logs 100 | 101 | 102 | The Enhanced Monitoring Service writes information during runtime and collection of the monitoring data to the directory tree ```C:\ProgramData\Enhanced Monitoring\log```. In case of any issues during collection of the enhanced monitoring data, check the content of this directory tree on your Hyper-V parent partition. 103 | 104 | ![](doc/log.png) 105 | 106 | If you cannot find log entries related to your issues, you might temporarily increase the log level of the Enhanced Monitoring service by setting the parameter LogLevel to ```Verbose```. 107 | ``` 108 | 109 | Verbose 110 | ``` 111 | Proceed as described in section ‘How to Configure the Enhanced Monitoring Service’. 112 | 113 | 114 | -------------------------------------------------------------------------------- /src/EnhancedMonitoring/MonitoringTask.cs: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright 2015 Microsoft Corporation 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | // 23 | using EnhancedMonitoring.Configuration; 24 | using EnhancedMonitoring.DataFormat; 25 | using EnhancedMonitoring.DataCollector; 26 | using EnhancedMonitoring.Logging; 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Linq; 30 | using System.Management; 31 | using System.Text; 32 | using System.Threading.Tasks; 33 | 34 | namespace EnhancedMonitoring 35 | { 36 | public class MonitoringTask 37 | { 38 | public const String VersionKey = "Version"; 39 | 40 | public static MonitoringTask CreateInstance(MonitorConfiguration conf) 41 | { 42 | if (conf == null) 43 | { 44 | throw new ArgumentNullException("conf"); 45 | } 46 | 47 | var instance = new MonitoringTask(conf); 48 | return instance; 49 | } 50 | 51 | protected List mgmtObjects = new List(); 52 | protected MonitorConfiguration conf; 53 | 54 | protected MonitoringTask(MonitorConfiguration conf) 55 | { 56 | this.conf = conf; 57 | foreach (var mgmtObjConf in conf.MgmtObjects) 58 | { 59 | mgmtObjects.Add(MgmtObject.CreateInstance(mgmtObjConf)); 60 | } 61 | } 62 | 63 | public void Run() 64 | { 65 | var vms = GetSupportedVM(); 66 | if (vms == null || vms.Count == 0) 67 | { 68 | Logger.Info("No supported VM found."); 69 | return; 70 | } 71 | 72 | Logger.Info("Detected {0} supported VMs", vms.Count); 73 | 74 | List tasks = new List(); 75 | foreach (var vm in vms) 76 | { 77 | tasks.Add(Task.Run(() => 78 | { 79 | var data = CollectDataForVM(vm); 80 | var packedData = new XmlDataFormatter(this.conf).ToXml(data); 81 | WriteKVPToVM(vm, packedData); 82 | })); 83 | } 84 | try 85 | { 86 | Task.WaitAll(tasks.ToArray()); 87 | } 88 | catch (AggregateException e) 89 | { 90 | foreach (var inner in e.InnerExceptions) 91 | { 92 | Logger.Error(inner); 93 | throw inner; 94 | } 95 | } 96 | } 97 | 98 | private void WriteKVPToVM(IDictionary vm, IDictionary packedData) 99 | { 100 | 101 | Logger.Info(String.Format("Write {0} kvps to VM {1}", packedData.Count, vm["VirtualMachineElementName"])); 102 | using (KeyValuePairWriter writer = KeyValuePairWriter.CreateInstance(this.conf.Kvp)) 103 | { 104 | try 105 | { 106 | writer.Remove(vm, packedData); 107 | writer.Write(vm, packedData); 108 | } 109 | catch (InvalidOperationException e) 110 | { 111 | Logger.Info("Couldn't write KVP to VM {0}. The VM has been shutdown or removed.", 112 | vm["VirtualMachineElementName"]); 113 | Logger.Verbose(e); 114 | } 115 | catch (ManagementException e) 116 | { 117 | Logger.Error(e); 118 | } 119 | catch (NotImplementedException e) 120 | { 121 | Logger.Info("Couldn't write KVP to VM {0}. The VM has been shutdown or removed.", 122 | vm["VirtualMachineElementName"]); 123 | Logger.Verbose(e); 124 | } 125 | } 126 | } 127 | 128 | private Dictionary CollectDataForVM(IDictionary vm) 129 | { 130 | var data = new Dictionary(); 131 | 132 | //Add pre-defined argument, VirtualMachine 133 | var args = new Dictionary(vm); 134 | 135 | foreach (var mgmtObj in this.mgmtObjects) 136 | { 137 | 138 | data.Add(mgmtObj.KeyName, null); 139 | try 140 | { 141 | data[mgmtObj.KeyName] = mgmtObj.CollectData(args); 142 | } 143 | catch (InvalidOperationException e) 144 | { 145 | if (!mgmtObj.SuppressError) 146 | { 147 | Logger.Verbose(e); 148 | } 149 | } 150 | catch (ManagementException e) 151 | { 152 | if (!mgmtObj.SuppressError) 153 | { 154 | Logger.Error(e); 155 | } 156 | } 157 | catch (ArgumentException e) 158 | { 159 | if (!mgmtObj.SuppressError) 160 | { 161 | Logger.Error(e); 162 | } 163 | } 164 | catch (NotImplementedException e) 165 | { 166 | if (!mgmtObj.SuppressError) 167 | { 168 | Logger.Verbose(e); 169 | } 170 | } 171 | } 172 | 173 | data.Add(VersionKey, this.conf.Version); 174 | return data; 175 | } 176 | 177 | private IList> GetSupportedVM() 178 | { 179 | 180 | IList> vms = null; 181 | try 182 | { 183 | vms = SupportedVMDetector.CreateInstance(this.conf.SupportedVMDetector).GetSupportedVM(); 184 | } 185 | catch (InvalidOperationException e) 186 | { 187 | Logger.Verbose(e); 188 | } 189 | catch (ManagementException e) 190 | { 191 | Logger.Error(e); 192 | } 193 | catch (NotImplementedException e) 194 | { 195 | Logger.Verbose(e); 196 | } 197 | return vms; 198 | } 199 | 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /packages/MSI/EnhancedMonitoring/Product.wxs: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Privileged 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | 84 | 86 | 87 | 99 | 100 | 101 | 102 | 103 | 104 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 1 141 | 142 | 1 143 | 144 | 1 145 | 146 | 1 147 | 148 | 1 149 | 1 150 | 1 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 160 | 161 | 162 | 163 | (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL") 164 | 165 | 166 | 167 | 168 | 169 | 170 | --------------------------------------------------------------------------------