Skip to content

Commit

Permalink
Support Prometheus UNIT metadata (#3651)
Browse files Browse the repository at this point in the history
* support Prometheus UNIT metadata

* changelog
  • Loading branch information
reyang authored Sep 13, 2022
1 parent de98eb7 commit 6ea078e
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 16 deletions.
6 changes: 2 additions & 4 deletions src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
* Bug fix for Prometheus Exporter reporting StatusCode 204
instead of 200, when no metrics are collected
([#3643](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3643))

* Added overloads which accept a name to the `MeterProviderBuilder`
`AddPrometheusExporter` extension to allow for more fine-grained options
management
([#3648](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3648))
* Added support for OpenMetrics UNIT metadata
([#3651](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3651))

## 1.4.0-alpha.2

Expand All @@ -21,7 +22,6 @@ Released 2022-Aug-18
([#3430](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3430)
[#3503](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3503)
[#3507](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3507))

* Added `IEndpointRouteBuilder` extension methods to help with Prometheus
middleware configuration on ASP.NET Core
([#3295](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3295))
Expand All @@ -41,10 +41,8 @@ Released 2022-Apr-15
* Added `IApplicationBuilder` extension methods to help with Prometheus
middleware configuration on ASP.NET Core
([#3029](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3029))

* Changed Prometheus exporter to return 204 No Content and log a warning event
if there are no metrics to collect.

* Removes .NET Framework 4.6.1. The minimum .NET Framework
version supported is .NET 4.6.2. ([#3190](https://github.com/open-telemetry/opentelemetry-dotnet/issues/3190))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
* Bug fix for Prometheus Exporter reporting StatusCode 204
instead of 200, when no metrics are collected
([#3643](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3643))

* Added overloads which accept a name to the `MeterProviderBuilder`
`AddPrometheusHttpListener` extension to allow for more fine-grained options
management
([#3648](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3648))
* Added support for OpenMetrics UNIT metadata
([#3651](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3651))

## 1.4.0-alpha.2

Expand Down Expand Up @@ -41,10 +42,8 @@ Released 2022-Apr-15
* Added `IApplicationBuilder` extension methods to help with Prometheus
middleware configuration on ASP.NET Core
([#3029](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3029))

* Changed Prometheus exporter to return 204 No Content and log a warning event
if there are no metrics to collect.

* Removes .NET Framework 4.6.1. The minimum .NET Framework
version supported is .NET 4.6.2. ([#3190](https://github.com/open-telemetry/opentelemetry-dotnet/issues/3190))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,13 @@ public static int WriteMetricName(byte[] buffer, int cursor, string metricName,
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int WriteHelpText(byte[] buffer, int cursor, string metricName, string metricUnit = null, string metricDescription = null)
public static int WriteHelpMetadata(byte[] buffer, int cursor, string metricName, string metricUnit, string metricDescription)
{
if (string.IsNullOrEmpty(metricDescription))
{
return cursor;
}

cursor = WriteAsciiStringNoEscape(buffer, cursor, "# HELP ");
cursor = WriteMetricName(buffer, cursor, metricName, metricUnit);

Expand All @@ -288,7 +293,7 @@ public static int WriteHelpText(byte[] buffer, int cursor, string metricName, st
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int WriteTypeInfo(byte[] buffer, int cursor, string metricName, string metricUnit, string metricType)
public static int WriteTypeMetadata(byte[] buffer, int cursor, string metricName, string metricUnit, string metricType)
{
Debug.Assert(!string.IsNullOrEmpty(metricType), $"{nameof(metricType)} should not be null or empty.");

Expand All @@ -301,5 +306,39 @@ public static int WriteTypeInfo(byte[] buffer, int cursor, string metricName, st

return cursor;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int WriteUnitMetadata(byte[] buffer, int cursor, string metricName, string metricUnit)
{
if (string.IsNullOrEmpty(metricUnit))
{
return cursor;
}

cursor = WriteAsciiStringNoEscape(buffer, cursor, "# UNIT ");
cursor = WriteMetricName(buffer, cursor, metricName, metricUnit);

buffer[cursor++] = unchecked((byte)' ');

for (int i = 0; i < metricUnit.Length; i++)
{
var ordinal = (ushort)metricUnit[i];

if ((ordinal >= (ushort)'A' && ordinal <= (ushort)'Z') ||
(ordinal >= (ushort)'a' && ordinal <= (ushort)'z') ||
(ordinal >= (ushort)'0' && ordinal <= (ushort)'9'))
{
buffer[cursor++] = unchecked((byte)ordinal);
}
else
{
buffer[cursor++] = unchecked((byte)'_');
}
}

buffer[cursor++] = ASCII_LINEFEED;

return cursor;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,10 @@ UpDownCounter becomes gauge

public static int WriteMetric(byte[] buffer, int cursor, Metric metric)
{
if (!string.IsNullOrWhiteSpace(metric.Description))
{
cursor = WriteHelpText(buffer, cursor, metric.Name, metric.Unit, metric.Description);
}

int metricType = (int)metric.MetricType >> 4;
cursor = WriteTypeInfo(buffer, cursor, metric.Name, metric.Unit, MetricTypes[metricType]);
cursor = WriteTypeMetadata(buffer, cursor, metric.Name, metric.Unit, MetricTypes[metricType]);
cursor = WriteUnitMetadata(buffer, cursor, metric.Name, metric.Unit);
cursor = WriteHelpMetadata(buffer, cursor, metric.Name, metric.Unit, metric.Description);

if (!metric.MetricType.IsHistogram())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ public void GaugeZeroDimensionWithDescription()
var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]);
Assert.Matches(
("^"
+ "# HELP test_gauge Hello, world!\n"
+ "# TYPE test_gauge gauge\n"
+ "# HELP test_gauge Hello, world!\n"
+ "test_gauge 123 \\d+\n"
+ "$").Replace('\'', '"'),
Encoding.UTF8.GetString(buffer, 0, cursor));
Expand All @@ -96,6 +96,34 @@ public void GaugeZeroDimensionWithUnit()
Assert.Matches(
("^"
+ "# TYPE test_gauge_seconds gauge\n"
+ "# UNIT test_gauge_seconds seconds\n"
+ "test_gauge_seconds 123 \\d+\n"
+ "$").Replace('\'', '"'),
Encoding.UTF8.GetString(buffer, 0, cursor));
}

[Fact]
public void GaugeZeroDimensionWithDescriptionAndUnit()
{
var buffer = new byte[85000];
var metrics = new List<Metric>();

using var meter = new Meter(Utils.GetCurrentMethodName());
using var provider = Sdk.CreateMeterProviderBuilder()
.AddMeter(meter.Name)
.AddInMemoryExporter(metrics)
.Build();

meter.CreateObservableGauge("test_gauge", () => 123, unit: "seconds", description: "Hello, world!");

provider.ForceFlush();

var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]);
Assert.Matches(
("^"
+ "# TYPE test_gauge_seconds gauge\n"
+ "# UNIT test_gauge_seconds seconds\n"
+ "# HELP test_gauge_seconds Hello, world!\n"
+ "test_gauge_seconds 123 \\d+\n"
+ "$").Replace('\'', '"'),
Encoding.UTF8.GetString(buffer, 0, cursor));
Expand Down

0 comments on commit 6ea078e

Please sign in to comment.