Bladeren bron

Alias a sensor name by sensor id

LibreHardwareMonitor allows one to customize the name for a given
sensor. This customized name is stored in `LibreHardwareMonitor.config`
as a combination of sensor id and `/name` suffix:

```xml
<add key="/<sensor-id>/name" value="<alias>" />
```

Like the following:

```xml
<add key="/lpc/nct6792d/fan/1/name" value="superfan" />
```

The XML format of the config is the exact same as OhmGraphite's, so this commit
allows one to copy and paste an exact alias line from LibreHardwareMonitor's
config into OhmGraphite's config as shown below.

```xml
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="type" value="prometheus" />
    <add key="prometheus_port" value="4445" />
    <add key="prometheus_host" value="*" />

    <add key="/lpc/nct6792d/fan/1/name" value="superfan" />
   </appSettings>
</configuration>
```

The recommendation for users that want to alias is to prepare their
aliasing in LibreHardwareMonitor as that is the most surefire way to
generate the alias config (nothing beats copy + paste). For those not
interested in using LibreHardwareMonitor for creating aliases, InfluxDB
and Postgres / TimescaleDB users can craft it by hand by examining their
data sources as the sensor id is stored in those backends (Prometheus
collector omits sensor id due to avoid high cardinality and Graphite
translates it by removing inappropriate characters).

Aliasing sensors will allow users that additional ways to craft
dashboards with desired names as some backends make it difficult to
create aliases (eg: with postgres a `view` could be used but creating an
alias on a single metric in influxdb is more difficult).
Nick Babcock 5 jaren geleden
bovenliggende
commit
2b0bb77d42

+ 9 - 0
OhmGraphite.Test/BlankConfig.cs

@@ -0,0 +1,9 @@
+namespace OhmGraphite.Test
+{
+    class BlankConfig : IAppConfig
+    {
+        public string this[string name] => null;
+
+        public string[] GetKeys() => new string[] { };
+    }
+}

+ 15 - 0
OhmGraphite.Test/ConfigTest.cs

@@ -96,5 +96,20 @@ namespace OhmGraphite.Test
 
             Assert.Equal("my-cool-machine", results.LookupName());
         }
+
+        [Fact]
+        public void CanParseSensorAlias()
+        {
+            var configMap = new ExeConfigurationFileMap { ExeConfigFilename = "assets/rename.config" };
+            var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
+            var customConfig = new CustomConfig(config);
+            var results = MetricConfig.ParseAppSettings(customConfig);
+
+            Assert.True(results.TryGetAlias("/amdcpu/0/load/1", out string alias));
+            Assert.Equal("CPU Core 0 T0", alias);
+            Assert.True(results.TryGetAlias("/amdcpu/0/load/2", out alias));
+            Assert.Equal("CPU Core 0 T1", alias);
+            Assert.False(results.TryGetAlias("/amdcpu/0/load/3", out alias));
+        }
     }
 }

+ 1 - 0
OhmGraphite.Test/CustomConfig.cs

@@ -12,5 +12,6 @@ namespace OhmGraphite.Test
         }
 
         public string this[string name] => _config.AppSettings.Settings[name]?.Value;
+        public string[] GetKeys() => _config.AppSettings.Settings.AllKeys;
     }
 }

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

@@ -26,6 +26,7 @@
     <None Include="..\assets\default.config" Link="assets/default.config" CopyToOutputDirectory="PreserveNewest" />
     <None Include="..\assets\graphite.config" Link="assets/graphite.config" CopyToOutputDirectory="PreserveNewest" />
     <None Include="..\assets\static-name.config" Link="assets/static-name.config" CopyToOutputDirectory="PreserveNewest" />
+    <None Include="..\assets\rename.config" Link="assets/rename.config" CopyToOutputDirectory="PreserveNewest" />
   </ItemGroup>
 
 </Project>

+ 1 - 1
OhmGraphite.Test/SensorCollectorTest.cs

@@ -10,7 +10,7 @@ namespace OhmGraphite.Test
         public void SensorsAddedWhenHardwareAdded()
         {
             var computer = new Computer();
-            var collector = new SensorCollector(computer);
+            var collector = new SensorCollector(computer, MetricConfig.ParseAppSettings(new BlankConfig()));
 
             try
             {

+ 2 - 0
OhmGraphite/AppConfigManager.cs

@@ -5,5 +5,7 @@ namespace OhmGraphite
     class AppConfigManager : IAppConfig
     {
         public string this[string name] => ConfigurationManager.AppSettings[name];
+
+        public string[] GetKeys() => ConfigurationManager.AppSettings.AllKeys;
     }
 }

+ 1 - 0
OhmGraphite/IAppConfig.cs

@@ -3,5 +3,6 @@
     public interface IAppConfig
     {
         string this[string name] { get; }
+        string[] GetKeys();
     }
 }

+ 16 - 2
OhmGraphite/MetricConfig.cs

@@ -1,4 +1,6 @@
 using System;
+using System.Collections.Generic;
+using System.Linq;
 
 namespace OhmGraphite
 {
@@ -7,7 +9,7 @@ namespace OhmGraphite
         private readonly INameResolution _nameLookup;
 
         public MetricConfig(TimeSpan interval, INameResolution nameLookup, GraphiteConfig graphite, InfluxConfig influx,
-            PrometheusConfig prometheus, TimescaleConfig timescale)
+            PrometheusConfig prometheus, TimescaleConfig timescale, Dictionary<String, String> aliases)
         {
             _nameLookup = nameLookup;
             Interval = interval;
@@ -15,6 +17,7 @@ namespace OhmGraphite
             Influx = influx;
             Prometheus = prometheus;
             Timescale = timescale;
+            Aliases = aliases;
         }
 
         public string LookupName() => _nameLookup.LookupName();
@@ -23,6 +26,7 @@ namespace OhmGraphite
         public InfluxConfig Influx { get; }
         public PrometheusConfig Prometheus { get; }
         public TimescaleConfig Timescale { get; }
+        public Dictionary<string, string> Aliases { get; }
 
         public static MetricConfig ParseAppSettings(IAppConfig config)
         {
@@ -59,7 +63,15 @@ namespace OhmGraphite
                     break;
             }
 
-            return new MetricConfig(interval, nameLookup, gconfig, iconfig, pconfig, timescale);
+            // Trim off the LibreHardwareMonitor "/name" suffix so that it is just the
+            // the sensor ID.
+            var aliases = config.GetKeys().Where(x => x.EndsWith("/name"))
+                .ToDictionary(
+                    x => x.Remove(x.LastIndexOf("/name", StringComparison.Ordinal)),
+                    x => config[x]
+                );
+
+            return new MetricConfig(interval, nameLookup, gconfig, iconfig, pconfig, timescale, aliases);
         }
 
         private static INameResolution NameLookup(string lookup)
@@ -74,5 +86,7 @@ namespace OhmGraphite
                     return new StaticResolution(lookup);
             }
         }
+
+        public bool TryGetAlias(string v, out string alias) => Aliases.TryGetValue(v, out alias);
     }
 }

+ 1 - 2
OhmGraphite/Program.cs

@@ -27,13 +27,12 @@ namespace OhmGraphite
                         IsStorageEnabled = true,
                         IsControllerEnabled = true
                     };
-                    var collector = new SensorCollector(computer);
 
                     // 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 collector = new SensorCollector(computer, config);
                     var metricsManager = CreateManager(config, collector);
-
                     s.ConstructUsing(name => metricsManager);
                     s.WhenStarted(tc => tc.Start());
                     s.WhenStopped(tc => tc.Dispose());

+ 11 - 3
OhmGraphite/SensorCollector.cs

@@ -10,12 +10,18 @@ namespace OhmGraphite
     {
         private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
         private readonly Computer _computer;
+        private readonly MetricConfig _config;
         private readonly IVisitor _updateVisitor = new UpdateVisitor();
 
         private readonly ConcurrentDictionary<Identifier, object> _ids =
             new ConcurrentDictionary<Identifier, object>();
 
-        public SensorCollector(Computer computer) => _computer = computer;
+        public SensorCollector(Computer computer, MetricConfig config)
+        {
+            _computer = computer;
+            _config = config;
+        }
+
         public void Open()
         {
             foreach (var hardware in _computer.Hardware)
@@ -99,7 +105,7 @@ namespace OhmGraphite
             return _ids.Values.OfType<ISensor>().SelectMany(ReportedValues);
         }
 
-        private static IEnumerable<ReportedValue> ReportedValues(ISensor sensor)
+        private IEnumerable<ReportedValue> ReportedValues(ISensor sensor)
         {
             string id = sensor.Identifier.ToString();
 
@@ -124,8 +130,10 @@ namespace OhmGraphite
                 var ind = hwInstance.LastIndexOf('/');
                 hwInstance = hwInstance.Substring(ind + 1);
 
+                var name = _config.TryGetAlias(sensor.Identifier.ToString(), out string alias) ? alias : sensor.Name;
+
                 yield return new ReportedValue(id,
-                    sensor.Name,
+                    name,
                     sensor.Value.Value,
                     sensor.SensorType.ToOwnSensor(),
                     sensor.Hardware.Name,

+ 12 - 0
assets/rename.config

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+  <appSettings>
+    <add key="host" value="myhost" />
+    <add key="port" value="2004" />
+    <add key="interval" value="6" />
+    <add key="tags" value="true" />
+
+    <add key="/amdcpu/0/load/1/name" value="CPU Core 0 T0" />
+    <add key="/amdcpu/0/load/2/name" value="CPU Core 0 T1" />
+  </appSettings>
+</configuration>