Просмотр исходного кода

Start of timescale implementation

Nick Babcock 6 лет назад
Родитель
Сommit
891f4e50c1

+ 9 - 2
OhmGraphite/MetricConfig.cs

@@ -4,18 +4,20 @@ namespace OhmGraphite
 {
     public class MetricConfig
     {
-        public MetricConfig(TimeSpan interval, GraphiteConfig graphite, InfluxConfig influx, PrometheusConfig prometheus)
+        public MetricConfig(TimeSpan interval, GraphiteConfig graphite, InfluxConfig influx, PrometheusConfig prometheus, string timescale)
         {
             Interval = interval;
             Graphite = graphite;
             Influx = influx;
             Prometheus = prometheus;
+            Timescale = timescale;
         }
 
         public TimeSpan Interval { get; }
         public GraphiteConfig Graphite { get; }
         public InfluxConfig Influx { get; }
         public PrometheusConfig Prometheus { get; }
+        public string Timescale { get; }
 
         public static MetricConfig ParseAppSettings(IAppConfig config)
         {
@@ -30,6 +32,7 @@ namespace OhmGraphite
             GraphiteConfig gconfig = null;
             InfluxConfig iconfig = null;
             PrometheusConfig pconfig = null;
+            string timescale = null;
 
             switch (type.ToLowerInvariant())
             {
@@ -43,9 +46,13 @@ namespace OhmGraphite
                 case "prometheus":
                     pconfig = PrometheusConfig.ParseAppSettings(config);
                     break;
+                case "timescale":
+                case "timescaledb":
+                    timescale = config["timescale_connection"];
+                    break;
             }
 
-            return new MetricConfig(interval, gconfig, iconfig, pconfig);
+            return new MetricConfig(interval, gconfig, iconfig, pconfig, timescale);
         }
     }
 }

+ 1 - 0
OhmGraphite/OhmGraphite.csproj

@@ -29,6 +29,7 @@
   <ItemGroup>
     <PackageReference Include="ILRepack" Version="2.0.15" />
     <PackageReference Include="NLog.Config" Version="4.5.6" />
+    <PackageReference Include="Npgsql" Version="4.0.2" />
     <PackageReference Include="prometheus-net" Version="2.1.0" />
     <PackageReference Include="TopShelf" Version="4.0.4" />
     <PackageReference Include="Topshelf.NLog" Version="4.0.4" />

+ 5 - 0
OhmGraphite/Program.cs

@@ -69,6 +69,11 @@ namespace OhmGraphite
                 var server = new MetricServer(config.Prometheus.Host, config.Prometheus.Port);
                 return new PrometheusServer(server, collector, prometheusCollection);
             }
+            else if (config.Timescale != null)
+            {
+                var writer = new TimescaleWriter(config.Timescale, Environment.MachineName);
+                return new MetricTimer(config.Interval, collector, writer);
+            }
             else
             {
                 Logger.Info($"Influxdb address: {config.Influx.Address} db: {config.Influx.Db}");

+ 92 - 0
OhmGraphite/TimescaleWriter.cs

@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using NLog;
+using Npgsql;
+using NpgsqlTypes;
+using OpenHardwareMonitor.Hardware;
+
+namespace OhmGraphite
+{
+    class TimescaleWriter : IWriteMetrics
+    {
+        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+        private readonly string _connStr;
+        private readonly string _localHost;
+        private NpgsqlConnection _conn;
+        private bool _failure = true;
+
+        public TimescaleWriter(string connStr, string localHost)
+        {
+            _connStr = connStr;
+            _localHost = localHost;
+            _conn = new NpgsqlConnection(_connStr);
+        }
+
+        public async Task ReportMetrics(DateTime reportTime, IEnumerable<ReportedValue> sensors)
+        {
+            try
+            {
+                if (_failure)
+                {
+                    _conn.Close();
+                    _conn = new NpgsqlConnection(_connStr);
+                    Logger.Debug("New timescale connection");
+                    await _conn.OpenAsync();
+
+                    using (var cmd = new NpgsqlCommand(
+                        "CREATE TABLE IF NOT EXISTS ohm_stats (\r\n  time TIMESTAMPTZ NOT NULL,\r\n  host TEXT,\r\n  hardware TEXT,\r\n  hardware_type TEXT,\r\n  identifier TEXT,\r\n  sensor TEXT,\r\n  sensor_type TEXT,\r\n  sensor_index INT,\r\n  value REAL\r\n);\r\n\r\nSELECT create_hypertable(\'ohm_stats\', \'time\', if_not_exists => TRUE);",
+                        _conn))
+                    {
+                        await cmd.ExecuteNonQueryAsync();
+                    }
+                }
+
+                using (var cmd = new NpgsqlCommand(
+                    "INSERT INTO ohm_stats " +
+                    "(time, host, hardware, hardware_type, identifier, sensor, sensor_index, value) VALUES " +
+                    "(@time, @host, @hardware, @hardware_type, @identifier, @sensor, @sensor_index, @value)",
+                    _conn))
+                {
+                    // Note that all parameters must be set before calling Prepare()
+                    // they are part of the information transmitted to PostgreSQL
+                    // and used to effectively plan the statement. You must also set
+                    // the DbType or NpgsqlDbType on your parameters to unambiguously
+                    // specify the data type (setting the value isn't support)
+                    cmd.Parameters.Add("time", NpgsqlDbType.TimestampTz);
+                    cmd.Parameters.Add("host", NpgsqlDbType.Text);
+                    cmd.Parameters.Add("hardware", NpgsqlDbType.Text);
+                    cmd.Parameters.Add("hardware_type", NpgsqlDbType.Text);
+                    cmd.Parameters.Add("identifier", NpgsqlDbType.Text);
+                    cmd.Parameters.Add("sensor", NpgsqlDbType.Text);
+                    cmd.Parameters.Add("value", NpgsqlDbType.Real);
+                    cmd.Parameters.Add("sensor_index", NpgsqlDbType.Integer);
+
+                    await cmd.PrepareAsync();
+
+                    foreach (var sensor in sensors)
+                    {
+                        cmd.Parameters["time"].Value = reportTime;
+                        cmd.Parameters["host"].Value = _localHost;
+                        cmd.Parameters["hardware"].Value = sensor.Hardware;
+                        cmd.Parameters["hardware_type"].Value = Enum.GetName(typeof(HardwareType), sensor.HardwareType);
+                        cmd.Parameters["identifier"].Value = sensor.Identifier;
+                        cmd.Parameters["sensor"].Value = sensor.Sensor;
+                        cmd.Parameters["value"].Value = sensor.Value;
+                        cmd.Parameters["sensor_index"].Value = sensor.SensorIndex;
+
+                        await cmd.ExecuteNonQueryAsync();
+                    }
+                }
+
+                _failure = false;
+            }
+            catch (Exception)
+            {
+                _failure = true;
+                throw;
+            }
+        }
+    }
+}