浏览代码

Add prometheus listener

Nick Babcock 6 年之前
父节点
当前提交
6c98d669e2

+ 15 - 0
OhmGraphite.Test/ConfigTest.cs

@@ -54,5 +54,20 @@ namespace OhmGraphite.Test
             Assert.Equal("my_user", results.Influx.User);
             Assert.Equal("my_user", results.Influx.User);
             Assert.Equal("my_pass", results.Influx.Password);
             Assert.Equal("my_pass", results.Influx.Password);
         }
         }
+
+        [Fact]
+        public void CanParsePrometheusConfig()
+        {
+            var configMap = new ExeConfigurationFileMap { ExeConfigFilename = "prometheus.config" };
+            var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
+            var customConfig = new CustomConfig(config);
+            var results = MetricConfig.ParseAppSettings(customConfig);
+
+            Assert.Null(results.Graphite);
+            Assert.Null(results.Influx);
+            Assert.NotNull(results.Prometheus);
+            Assert.Equal(4446, results.Prometheus.Port);
+            Assert.Equal("127.0.0.1", results.Prometheus.Host);
+        }
     }
     }
 }
 }

+ 4 - 1
OhmGraphite.Test/OhmGraphite.Test.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 <Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFramework>net46</TargetFramework>
+    <TargetFramework>net461</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>
@@ -20,6 +20,9 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
+    <None Update="prometheus.config">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
     <None Update="influxtest.config">
     <None Update="influxtest.config">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
     </None>

+ 8 - 0
OhmGraphite.Test/prometheus.config

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+  <appSettings>
+    <add key="type" value="prometheus" />
+    <add key="prometheus_port" value="4446"/>
+    <add key="prometheus_host" value="127.0.0.1"/>
+  </appSettings>
+</configuration>

+ 8 - 0
OhmGraphite/IManage.cs

@@ -0,0 +1,8 @@
+namespace OhmGraphite
+{
+    interface IManage
+    {
+        void Start();
+        void Stop();
+    }
+}

+ 8 - 2
OhmGraphite/MetricConfig.cs

@@ -4,16 +4,18 @@ namespace OhmGraphite
 {
 {
     public class MetricConfig
     public class MetricConfig
     {
     {
-        public MetricConfig(TimeSpan interval, GraphiteConfig graphite, InfluxConfig influx)
+        public MetricConfig(TimeSpan interval, GraphiteConfig graphite, InfluxConfig influx, PrometheusConfig prometheus)
         {
         {
             Interval = interval;
             Interval = interval;
             Graphite = graphite;
             Graphite = graphite;
             Influx = influx;
             Influx = influx;
+            Prometheus = prometheus;
         }
         }
 
 
         public TimeSpan Interval { get; }
         public TimeSpan Interval { get; }
         public GraphiteConfig Graphite { get; }
         public GraphiteConfig Graphite { get; }
         public InfluxConfig Influx { get; }
         public InfluxConfig Influx { get; }
+        public PrometheusConfig Prometheus { get; }
 
 
         public static MetricConfig ParseAppSettings(IAppConfig config)
         public static MetricConfig ParseAppSettings(IAppConfig config)
         {
         {
@@ -27,6 +29,7 @@ namespace OhmGraphite
             var type = config["type"] ?? "graphite";
             var type = config["type"] ?? "graphite";
             GraphiteConfig gconfig = null;
             GraphiteConfig gconfig = null;
             InfluxConfig iconfig = null;
             InfluxConfig iconfig = null;
+            PrometheusConfig pconfig = null;
 
 
             switch (type.ToLowerInvariant())
             switch (type.ToLowerInvariant())
             {
             {
@@ -37,9 +40,12 @@ namespace OhmGraphite
                 case "influx":
                 case "influx":
                     iconfig = InfluxConfig.ParseAppSettings(config);
                     iconfig = InfluxConfig.ParseAppSettings(config);
                     break;
                     break;
+                case "prometheus":
+                    pconfig = PrometheusConfig.ParseAppSettings(config);
+                    break;
             }
             }
 
 
-            return new MetricConfig(interval, gconfig, iconfig);
+            return new MetricConfig(interval, gconfig, iconfig, pconfig);
         }
         }
     }
     }
 }
 }

+ 1 - 1
OhmGraphite/MetricTimer.cs

@@ -6,7 +6,7 @@ using NLog;
 
 
 namespace OhmGraphite
 namespace OhmGraphite
 {
 {
-    public class MetricTimer
+    public class MetricTimer : IManage
     {
     {
         private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
         private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
         private readonly SensorCollector _collector;
         private readonly SensorCollector _collector;

+ 5 - 4
OhmGraphite/OhmGraphite.csproj

@@ -2,7 +2,7 @@
 
 
   <PropertyGroup>
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net46</TargetFramework>
+    <TargetFramework>net461</TargetFramework>
     <PlatformTarget>AnyCPU</PlatformTarget>
     <PlatformTarget>AnyCPU</PlatformTarget>
     <Authors>Nick Babcock</Authors>
     <Authors>Nick Babcock</Authors>
 
 
@@ -31,6 +31,7 @@
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="ILRepack" Version="2.0.15" />
     <PackageReference Include="ILRepack" Version="2.0.15" />
     <PackageReference Include="NLog.Config" Version="4.5.6" />
     <PackageReference Include="NLog.Config" Version="4.5.6" />
+    <PackageReference Include="prometheus-net" Version="2.1.0" />
     <PackageReference Include="TopShelf" Version="4.0.4" />
     <PackageReference Include="TopShelf" Version="4.0.4" />
     <PackageReference Include="Topshelf.NLog" Version="4.0.4" />
     <PackageReference Include="Topshelf.NLog" Version="4.0.4" />
     <PackageReference Include="InfluxDB.LineProtocol" Version="1.1.0" />
     <PackageReference Include="InfluxDB.LineProtocol" Version="1.1.0" />
@@ -44,8 +45,8 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <Target Name="ILPack" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
   <Target Name="ILPack" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
-    <Exec Command="&quot;$(NuGetPackageRoot)ilrepack\2.0.15\tools\ILRepack.exe&quot; /out:$(BaseOutputPath)OhmGraphite.exe $(OutputPath)OhmGraphite.exe $(OutputPath)Topshelf.dll $(OutputPath)Topshelf.NLog.dll $(OutputPath)NLog.dll $(OutputPath)OpenHardwareMonitorLib.dll $(OutputPath)InfluxDB.LineProtocol.dll $(OutputPath)HidLibrary.dll" />
-    <Copy SourceFiles="$(OutputPath)NLog.config" DestinationFolder="$(BaseOutputPath)"/>
-    <Zip Files="$(BaseOutputPath)OhmGraphite.exe;$(BaseOutputPath)OhmGraphite.exe.config;$(BaseOutputPath)NLog.config" WorkingDirectory="$(BaseOutputPath)"  ZipFileName="$(BaseOutputPath)OhmGraphite-$(Major).$(Minor).$(Revision).zip" />
+    <Exec Command="&quot;$(NuGetPackageRoot)ilrepack\2.0.15\tools\ILRepack.exe&quot; /lib:$(OutputPath) /out:$(BaseOutputPath)OhmGraphite.exe $(OutputPath)OhmGraphite.exe $(OutputPath)Topshelf.dll $(OutputPath)Topshelf.NLog.dll $(OutputPath)NLog.dll $(OutputPath)OpenHardwareMonitorLib.dll $(OutputPath)InfluxDB.LineProtocol.dll $(OutputPath)HidLibrary.dll $(OutputPath)protobuf-net.dll $(OutputPath)Prometheus.NetStandard.dll" />
+    <Copy SourceFiles="$(OutputPath)NLog.config" DestinationFolder="$(BaseOutputPath)" />
+    <Zip Files="$(BaseOutputPath)OhmGraphite.exe;$(BaseOutputPath)OhmGraphite.exe.config;$(BaseOutputPath)NLog.config" WorkingDirectory="$(BaseOutputPath)" ZipFileName="$(BaseOutputPath)OhmGraphite-$(Major).$(Minor).$(Revision).zip" />
   </Target>
   </Target>
 </Project>
 </Project>

+ 36 - 23
OhmGraphite/Program.cs

@@ -1,6 +1,7 @@
 using System;
 using System;
 using NLog;
 using NLog;
 using OpenHardwareMonitor.Hardware;
 using OpenHardwareMonitor.Hardware;
+using Prometheus;
 using Topshelf;
 using Topshelf;
 
 
 namespace OhmGraphite
 namespace OhmGraphite
@@ -13,27 +14,8 @@ namespace OhmGraphite
         {
         {
             HostFactory.Run(x =>
             HostFactory.Run(x =>
             {
             {
-                x.Service<MetricTimer>(s =>
+                x.Service<IManage>(s =>
                 {
                 {
-                    // We need to know where the graphite server lives and how often
-                    // to poll the hardware
-                    var config = Logger.LogFunction("parse config", () => MetricConfig.ParseAppSettings(new AppConfigManager()));
-                    double seconds = config.Interval.TotalSeconds;
-                    IWriteMetrics writer;
-                    if (config.Graphite != null)
-                    {
-                        Logger.Info($"Graphite host: {config.Graphite.Host} port: {config.Graphite.Port} interval: {seconds} tags: {config.Graphite.Tags}");
-                        writer = new GraphiteWriter(config.Graphite.Host,
-                            config.Graphite.Port,
-                            Environment.MachineName,
-                            config.Graphite.Tags);
-                    }
-                    else
-                    {
-                        Logger.Info($"Influxdb address: {config.Influx.Address} db: {config.Influx.Db}");
-                        writer = new InfluxWriter(config.Influx, Environment.MachineName);
-                    }
-
                     // We'll want to capture all available hardware metrics
                     // We'll want to capture all available hardware metrics
                     // to send to graphite
                     // to send to graphite
                     var computer = new Computer
                     var computer = new Computer
@@ -48,9 +30,12 @@ namespace OhmGraphite
 
 
                     var collector = new SensorCollector(computer);
                     var collector = new SensorCollector(computer);
 
 
-                    s.ConstructUsing(name =>
-                        Logger.LogFunction("creating timer",
-                            () => new MetricTimer(config.Interval, collector, writer)));
+                    // We need to know where the graphite server lives and how often
+                    // to poll the hardware
+                    var config = Logger.LogFunction("parse config", () => MetricConfig.ParseAppSettings(new AppConfigManager()));
+                    var metricsManager = CreateManager(config, collector);
+
+                    s.ConstructUsing(name => metricsManager);
                     s.WhenStarted(tc => tc.Start());
                     s.WhenStarted(tc => tc.Start());
                     s.WhenStopped(tc => tc.Stop());
                     s.WhenStopped(tc => tc.Stop());
                 });
                 });
@@ -63,5 +48,33 @@ namespace OhmGraphite
                 x.OnException(ex => Logger.Error(ex, "OhmGraphite TopShelf encountered an error"));
                 x.OnException(ex => Logger.Error(ex, "OhmGraphite TopShelf encountered an error"));
             });
             });
         }
         }
+
+        private static IManage CreateManager(MetricConfig config, SensorCollector collector)
+        {
+            double seconds = config.Interval.TotalSeconds;
+            if (config.Graphite != null)
+            {
+                Logger.Info(
+                    $"Graphite host: {config.Graphite.Host} port: {config.Graphite.Port} interval: {seconds} tags: {config.Graphite.Tags}");
+                var writer = new GraphiteWriter(config.Graphite.Host,
+                    config.Graphite.Port,
+                    Environment.MachineName,
+                    config.Graphite.Tags);
+                return new MetricTimer(config.Interval, collector, writer);
+            }
+            else if (config.Prometheus != null)
+            {
+                Logger.Info($"Prometheus port: {config.Prometheus.Port}");
+                var prometheusCollection = new PrometheusCollection(collector, Environment.MachineName);
+                var server = new MetricServer(config.Prometheus.Host, config.Prometheus.Port);
+                return new PrometheusServer(server, collector, prometheusCollection);
+            }
+            else
+            {
+                Logger.Info($"Influxdb address: {config.Influx.Address} db: {config.Influx.Db}");
+                var writer = new InfluxWriter(config.Influx, Environment.MachineName);
+                return new MetricTimer(config.Interval, collector, writer);
+            }
+        }
     }
     }
 }
 }

+ 48 - 0
OhmGraphite/PrometheusCollection.cs

@@ -0,0 +1,48 @@
+using System;
+using NLog;
+using OpenHardwareMonitor.Hardware;
+using Prometheus;
+using Prometheus.Advanced;
+
+namespace OhmGraphite
+{
+    public class PrometheusCollection : IOnDemandCollector
+    {
+        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+        private readonly SensorCollector _collector;
+        private readonly string _localHost;
+        private MetricFactory _metrics;
+
+        public PrometheusCollection(SensorCollector collector, string localHost)
+        {
+            _collector = collector;
+            _localHost = localHost;
+        }
+
+        public void RegisterMetrics(ICollectorRegistry registry)
+        {
+            _metrics = Metrics.WithCustomRegistry(registry);
+        }
+
+        public void UpdateMetrics()
+        {
+            Logger.LogAction("prometheus update metrics", PollSensors);
+        }
+
+        private void PollSensors()
+        {
+            foreach (var sensor in _collector.ReadAllSensors())
+            {
+                _metrics.CreateGauge(
+                        sensor.Identifier.Substring(1).Replace('/', '_'),
+                        "Metric reported by open hardware sensor",
+                        "host", "app", "hardware", "hardware_type", "sensor", "sensor_index")
+                    .WithLabels(_localHost, "ohm", sensor.Hardware,
+                        Enum.GetName(typeof(HardwareType), sensor.HardwareType),
+                        sensor.Sensor,
+                        sensor.SensorIndex.ToString())
+                    .Set(sensor.Value);
+            }
+        }
+    }
+}

+ 26 - 0
OhmGraphite/PrometheusConfig.cs

@@ -0,0 +1,26 @@
+
+namespace OhmGraphite
+{
+    public class PrometheusConfig
+    {
+        public int Port { get; }
+        public string Host { get; }
+
+        public PrometheusConfig(int port, string host)
+        {
+            Port = port;
+            Host = host;
+        }
+
+        internal static PrometheusConfig ParseAppSettings(IAppConfig config)
+        {
+            string host = config["prometheus_host"] ?? "*";
+            if (!int.TryParse(config["prometheus_port"], out int port))
+            {
+                port = 4445;
+            }
+
+            return new PrometheusConfig(port, host);
+        }
+    }
+}

+ 41 - 0
OhmGraphite/PrometheusServer.cs

@@ -0,0 +1,41 @@
+using NLog;
+using Prometheus;
+using Prometheus.Advanced;
+
+namespace OhmGraphite
+{
+    public class PrometheusServer : IManage
+    {
+        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+        private readonly MetricServer _server;
+        private readonly SensorCollector _collector;
+        private readonly PrometheusCollection _prometheusCollection;
+
+        public PrometheusServer(MetricServer server, SensorCollector collector, PrometheusCollection prometheusCollection)
+        {
+            _server = server;
+            _collector = collector;
+            _prometheusCollection = prometheusCollection;
+        }
+
+        public void Start()
+        {
+            Logger.LogAction("starting prometheus server", () =>
+            {
+                DefaultCollectorRegistry.Instance.RegisterOnDemandCollectors(_prometheusCollection);
+                _collector.Open();
+                _server.Start();
+            });
+        }
+
+        public void Stop()
+        {
+            Logger.LogAction("stopping prometheus server", () =>
+            {
+                _collector.Close();
+                _server.Stop();
+            });
+        }
+    }
+}