Browse Source

Extract graphite writing to separate class

Nick Babcock 7 năm trước cách đây
mục cha
commit
f7550933f7

+ 2 - 2
OhmGraphite.Test/FormatMetricsTest.cs

@@ -12,7 +12,7 @@ namespace OhmGraphite.Test
         {
             var epoch = new DateTimeOffset(new DateTime(2001, 1, 13), TimeSpan.Zero).ToUnixTimeSeconds();
             var sensor = new Sensor("my.cpu.identifier", "voltage", 1.06f);
-            string actual = MetricTimer.FormatGraphiteData("MY-PC", epoch, sensor);
+            string actual = GraphiteWriter.FormatGraphiteData("MY-PC", epoch, sensor);
             Assert.Equal("ohm.MY-PC.my.cpu.identifier.voltage 1.06 979344000", actual);
         }
 
@@ -27,7 +27,7 @@ namespace OhmGraphite.Test
 
                 var epoch = new DateTimeOffset(new DateTime(2001, 1, 13), TimeSpan.Zero).ToUnixTimeSeconds();
                 var sensor = new Sensor("my.cpu.identifier", "voltage", 1.06f);
-                string actual = MetricTimer.FormatGraphiteData("MY-PC", epoch, sensor);
+                string actual = GraphiteWriter.FormatGraphiteData("MY-PC", epoch, sensor);
                 Assert.Equal("ohm.MY-PC.my.cpu.identifier.voltage 1.06 979344000", actual);
             }
             finally

+ 62 - 0
OhmGraphite/GraphiteWriter.cs

@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Sockets;
+using static System.FormattableString;
+
+namespace OhmGraphite
+{
+    public class GraphiteWriter
+    {
+        private readonly string _remoteHost;
+        private readonly int _remotePort;
+        private readonly string _localHost;
+
+        public GraphiteWriter(string remoteHost, int remotePort)
+        {
+            _remoteHost = remoteHost;
+            _remotePort = remotePort;
+            _localHost = Environment.MachineName;
+        }
+
+        public void ReportMetrics(DateTime reportTime, IEnumerable<Sensor> sensors)
+        {
+            // We don't want to transmit metrics across multiple seconds as they
+            // are being retrieved so calculate the timestamp of the signaled event
+            // only once.
+            var epoch = new DateTimeOffset(reportTime).ToUnixTimeSeconds();
+            using (var client = new TcpClient(_remoteHost, _remotePort))
+            using (var networkStream = client.GetStream())
+            using (var writer = new StreamWriter(networkStream))
+            {
+                foreach (var sensor in sensors)
+                {
+                    var data = Normalize(sensor);
+
+                    // Graphite API wants <metric> <value> <timestamp>. We prefix the metric
+                    // with `ohm` as to not overwrite potentially existing metrics
+                    writer.WriteLine(FormatGraphiteData(_localHost, epoch, data));
+                }
+            }
+        }
+
+        private static Sensor Normalize(Sensor sensor)
+        {
+            // Take the sensor's identifier (eg. /nvidiagpu/0/load/0)
+            // and tranform into nvidiagpu.0.load.<name> where <name>
+            // is the name of the sensor lowercased with spaces removed.
+            // A name like "GPU Core" is turned into "gpucore". Also
+            // since some names are like "cpucore#2", turn them into
+            // separate metrics by replacing "#" with "."
+            var identifier = sensor.Identifier.Replace('/', '.').Substring(1);
+            identifier = identifier.Remove(identifier.LastIndexOf('.'));
+            var name = sensor.Name.ToLower().Replace(" ", null).Replace('#', '.');
+            return new Sensor(identifier, name, sensor.Value);
+        }
+
+        public static string FormatGraphiteData(string host, long epoch, Sensor data)
+        {
+            return Invariant($"ohm.{host}.{data.Identifier}.{data.Name} {data.Value} {epoch:d}");
+        }
+    }
+}

+ 14 - 65
OhmGraphite/MetricTimer.cs

@@ -1,12 +1,8 @@
 using System;
-using System.Collections.Generic;
 using System.Diagnostics;
-using System.IO;
-using System.Net.Sockets;
+using System.Linq;
 using System.Timers;
 using NLog;
-using OpenHardwareMonitor.Hardware;
-using static System.FormattableString;
 
 namespace OhmGraphite
 {
@@ -14,18 +10,16 @@ namespace OhmGraphite
     {
         private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
 
-        private readonly int _graphitePort;
-        private readonly string _graphiteHost;
         private readonly Timer _timer;
         private readonly SensorCollector _collector;
+        private readonly GraphiteWriter _writer;
 
-        public MetricTimer(MetricConfig config, SensorCollector collector)
+        public MetricTimer(TimeSpan interval, SensorCollector collector, GraphiteWriter writer)
         {
-            _graphitePort = config.Port;
-            _graphiteHost = config.Host;
-            _timer = new Timer(config.Interval.TotalMilliseconds) { AutoReset = true };
+            _timer = new Timer(interval.TotalMilliseconds) { AutoReset = true };
             _timer.Elapsed += ReportMetrics;
             _collector = collector;
+            _writer = writer;
         }
 
         public void Start()
@@ -51,65 +45,20 @@ namespace OhmGraphite
             Logger.Debug("Starting to report metrics");
             try
             {
-                // We don't want to transmit metrics across multiple seconds as they
-                // are being retrieved so calculate the timestamp of the signaled event
-                // only once.
-                long epoch = new DateTimeOffset(e.SignalTime).ToUnixTimeSeconds();
-                string host = Environment.MachineName;
-                SendMetrics(host, epoch);
+                // Every 5 seconds (or superceding interval) we connect to graphite
+                // and poll the hardware. It may be inefficient to open a new connection
+                // every 5 seconds, and there are ways to optimize this, but opening a
+                // new connection is the easiest way to ensure that previous failures
+                // don't affect future results
+                var stopwatch = Stopwatch.StartNew();
+                var sensors = _collector.ReadAllSensors().ToList();
+                _writer.ReportMetrics(e.SignalTime, sensors);
+                Logger.Info($"Sent {sensors.Count} metrics in {stopwatch.Elapsed.TotalMilliseconds}ms");
             }
             catch (Exception ex)
             {
                 Logger.Error(ex, "Unable to send metrics");
             }
         }
-
-        private void SendMetrics(string host, long epoch)
-        {
-            int sensorCount = 0;
-
-            // Every 5 seconds (or superceding interval) we connect to graphite
-            // and poll the hardware. It may be inefficient to open a new connection
-            // every 5 seconds, and there are ways to optimize this, but opening a
-            // new connection is the easiest way to ensure that previous failures
-            // don't affect future results
-            var stopwatch = Stopwatch.StartNew();
-            using (var client = new TcpClient(_graphiteHost, _graphitePort))
-            using (var networkStream = client.GetStream())
-            using (var writer = new StreamWriter(networkStream))
-            {
-                foreach (var sensor in _collector.ReadAllSensors())
-                {
-                    var data = Normalize(sensor);
-
-                    // Graphite API wants <metric> <value> <timestamp>. We prefix the metric
-                    // with `ohm` as to not overwrite potentially existing metrics
-                    writer.WriteLine(FormatGraphiteData(host, epoch, data));
-
-                    sensorCount++;
-                }
-            }
-
-            Logger.Info($"Sent {sensorCount} metrics in {stopwatch.Elapsed.TotalMilliseconds}ms");
-        }
-
-        public static string FormatGraphiteData(string host, long epoch, Sensor data)
-        {
-            return Invariant($"ohm.{host}.{data.Identifier}.{data.Name} {data.Value} {epoch:d}");
-        }
-
-        private static Sensor Normalize(Sensor sensor)
-        {
-            // Take the sensor's identifier (eg. /nvidiagpu/0/load/0)
-            // and tranform into nvidiagpu.0.load.<name> where <name>
-            // is the name of the sensor lowercased with spaces removed.
-            // A name like "GPU Core" is turned into "gpucore". Also
-            // since some names are like "cpucore#2", turn them into
-            // separate metrics by replacing "#" with "."
-            var identifier = sensor.Identifier.Replace('/', '.').Substring(1);
-            identifier = identifier.Remove(identifier.LastIndexOf('.'));
-            var name = sensor.Name.ToLower().Replace(" ", null).Replace('#', '.');
-            return new Sensor(identifier, name, sensor.Value);
-        }
     }
 }

+ 2 - 1
OhmGraphite/Program.cs

@@ -32,8 +32,9 @@ namespace OhmGraphite
                     };
 
                     var collector = new SensorCollector(computer);
+                    var writer = new GraphiteWriter(config.Host, config.Port);
 
-                    s.ConstructUsing(name => Logger.LogFunction("creating timer", () => new MetricTimer(config, collector)));
+                    s.ConstructUsing(name => Logger.LogFunction("creating timer", () => new MetricTimer(config.Interval, collector, writer)));
                     s.WhenStarted(tc => tc.Start());
                     s.WhenStopped(tc => tc.Stop());
                 });