diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md index b0944097751..52fc65b6158 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Fixed writing boolean values to use the JSON representation + ([#4823](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4823)) + ## 1.6.0-rc.1 Released 2023-Aug-21 diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md index 18ee39ba7ae..3b2eb78addf 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Fixed writing boolean values to use the JSON representation + ([#4823](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4823)) + ## 1.6.0-rc.1 Released 2023-Aug-21 diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs index 1ca91a5ee7f..3bcd4998f12 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs @@ -222,10 +222,22 @@ public static int WriteLabel(byte[] buffer, int cursor, string labelKey, object buffer[cursor++] = unchecked((byte)'"'); // In Prometheus, a label with an empty label value is considered equivalent to a label that does not exist. - cursor = WriteLabelValue(buffer, cursor, labelValue?.ToString() ?? string.Empty); + cursor = WriteLabelValue(buffer, cursor, GetLabelValueString(labelValue)); buffer[cursor++] = unchecked((byte)'"'); return cursor; + + static string GetLabelValueString(object labelValue) + { + // TODO: Attribute values should be written as their JSON representation. Extra logic may need to be added here to correctly convert other .NET types. + // More detail: https://github.com/open-telemetry/opentelemetry-dotnet/issues/4822#issuecomment-1707328495 + if (labelValue is bool b) + { + return b ? "true" : "false"; + } + + return labelValue?.ToString() ?? string.Empty; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs index 069a2e0c810..53617606cf0 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs @@ -155,6 +155,33 @@ public void GaugeOneDimension() Encoding.UTF8.GetString(buffer, 0, cursor)); } + [Fact] + public void GaugeBoolDimension() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + meter.CreateObservableGauge( + "test_gauge", + () => new Measurement(123, new KeyValuePair("tagKey", true))); + + provider.ForceFlush(); + + var cursor = WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_gauge gauge\n" + + "test_gauge{tagKey='true'} 123 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + [Fact] public void GaugeDoubleSubnormal() {