diff --git a/config/promitor/scraper/metrics.yaml b/config/promitor/scraper/metrics.yaml
index e0fb6afb2..a30605b0d 100644
--- a/config/promitor/scraper/metrics.yaml
+++ b/config/promitor/scraper/metrics.yaml
@@ -127,4 +127,16 @@ metrics:
aggregation:
type: Total
resourceDiscoveryGroups:
- - name: service-bus-landscape
\ No newline at end of file
+ - name: service-bus-landscape
+ - name: promitor_demo_app_insights
+ description: "Average dependency duration per dependency type"
+ resourceType: Generic
+ azureMetricConfiguration:
+ metricName: dependencies/duration
+ dimension:
+ name: dependency/type
+ aggregation:
+ type: Average
+ resources:
+ - resourceUri: Microsoft.Insights/Components/docker-hub-metrics
+ resourceGroupName: docker-hub-metrics
\ No newline at end of file
diff --git a/src/Promitor.Integrations.Sinks.Prometheus/Extensions/StringExtensions.cs b/src/Promitor.Integrations.Sinks.Prometheus/Extensions/StringExtensions.cs
new file mode 100644
index 000000000..20e2999c2
--- /dev/null
+++ b/src/Promitor.Integrations.Sinks.Prometheus/Extensions/StringExtensions.cs
@@ -0,0 +1,21 @@
+// ReSharper disable once CheckNamespace
+
+namespace System
+{
+ public static class StringExtensions
+ {
+ ///
+ /// Ensures label key name is valid according to Prometheus requirements
+ ///
+ /// Current label key value
+ public static string SanitizeForPrometheusLabelKey(this string labelKey)
+ {
+ if (string.IsNullOrWhiteSpace(labelKey))
+ {
+ return labelKey;
+ }
+
+ return labelKey.Replace("/", "_").ToLower();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs
index 320057098..d1b152242 100644
--- a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs
+++ b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using GuardNet;
@@ -85,18 +86,18 @@ private IMetricFamily CreateGauge(string metricName, string metricDescri
private Dictionary DetermineLabels(PrometheusMetricDefinition metricDefinition, ScrapeResult scrapeResult, MeasuredMetric measuredMetric)
{
- var labels = new Dictionary(scrapeResult.Labels.Select(label => new KeyValuePair(label.Key.ToLower(), label.Value)));
+ var labels = new Dictionary(scrapeResult.Labels.Select(label => new KeyValuePair(label.Key.SanitizeForPrometheusLabelKey(), label.Value)));
if (measuredMetric.IsDimensional)
{
- labels.Add(measuredMetric.DimensionName.ToLower(), measuredMetric.DimensionValue);
+ labels.Add(measuredMetric.DimensionName.SanitizeForPrometheusLabelKey(), measuredMetric.DimensionValue);
}
if (metricDefinition?.Labels?.Any() == true)
{
foreach (var customLabel in metricDefinition.Labels)
{
- var customLabelKey = customLabel.Key.ToLower();
+ var customLabelKey = customLabel.Key.SanitizeForPrometheusLabelKey();
if (labels.ContainsKey(customLabelKey))
{
_logger.LogWarning("Custom label {CustomLabelName} was already specified with value 'LabelValue' instead of 'CustomLabelValue'. Ignoring...", customLabel.Key, labels[customLabelKey], customLabel.Value);
diff --git a/src/Promitor.Tests.Unit/Prometheus/StringExtensionTests.cs b/src/Promitor.Tests.Unit/Prometheus/StringExtensionTests.cs
new file mode 100644
index 000000000..8a38c0be5
--- /dev/null
+++ b/src/Promitor.Tests.Unit/Prometheus/StringExtensionTests.cs
@@ -0,0 +1,51 @@
+using System;
+using System.ComponentModel;
+using Xunit;
+
+namespace Promitor.Tests.Unit.Prometheus
+{
+ [Category("Unit")]
+ public class StringExtensionTests
+ {
+ [Fact]
+ public void SanitizeForPrometheusLabelKey_ValidKey_IdenticalOutput()
+ {
+ // Arrange
+ var labelKeyInput = "sample_label";
+
+ // Act
+ var sanitizedLabelKey = labelKeyInput.SanitizeForPrometheusLabelKey();
+
+ // Assert
+ Assert.Equal(labelKeyInput, sanitizedLabelKey);
+ }
+
+ [Fact]
+ public void SanitizeForPrometheusLabelKey_KeyIsUppercase_ConvertedToLowercase()
+ {
+ // Arrange
+ var labelKeyInput = "SAMPLE_LABEL";
+ var expectedLabelKey = "sample_label";
+
+ // Act
+ var sanitizedLabelKey = labelKeyInput.SanitizeForPrometheusLabelKey();
+
+ // Assert
+ Assert.Equal(expectedLabelKey, sanitizedLabelKey);
+ }
+
+ [Fact]
+ public void SanitizeForPrometheusLabelKey_KeyWithSlash_SlashIsReplaced()
+ {
+ // Arrange
+ var labelKeyInput = "sample/label";
+ var expectedLabelKey = "sample_label";
+
+ // Act
+ var sanitizedLabelKey = labelKeyInput.SanitizeForPrometheusLabelKey();
+
+ // Assert
+ Assert.Equal(expectedLabelKey, sanitizedLabelKey);
+ }
+ }
+}
\ No newline at end of file