Skip to content

Commit

Permalink
OTLP support for exporting exponential histograms (#4337)
Browse files Browse the repository at this point in the history
  • Loading branch information
alanwest authored Mar 28, 2023
1 parent 87a3313 commit 410532a
Show file tree
Hide file tree
Showing 14 changed files with 269 additions and 26 deletions.
20 changes: 20 additions & 0 deletions examples/AspNetCore/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// limitations under the License.
// </copyright>

using System.Diagnostics.Metrics;
using Examples.AspNetCore;
using OpenTelemetry.Exporter;
using OpenTelemetry.Instrumentation.AspNetCore;
Expand All @@ -33,6 +34,9 @@
// Note: Switch between Console/OTLP by setting UseLogExporter in appsettings.json.
var logExporter = appBuilder.Configuration.GetValue<string>("UseLogExporter").ToLowerInvariant();

// Note: Switch between Explicit/Exponential by setting HistogramAggregation in appsettings.json
var histogramAggregation = appBuilder.Configuration.GetValue<string>("HistogramAggregation").ToLowerInvariant();

// Build a resource configuration action to set service information.
Action<ResourceBuilder> configureResource = r => r.AddService(
serviceName: appBuilder.Configuration.GetValue<string>("ServiceName"),
Expand Down Expand Up @@ -111,6 +115,22 @@
.AddHttpClientInstrumentation()
.AddAspNetCoreInstrumentation();

switch (histogramAggregation)
{
case "exponential":
builder.AddView(instrument =>
{
return instrument.GetType().GetGenericTypeDefinition() == typeof(Histogram<>)
? new Base2ExponentialBucketHistogramConfiguration()
: null;
});
break;
default:
// Explicit bounds histogram is the default.
// No additional configuration necessary.
break;
}

switch (metricsExporter)
{
case "prometheus":
Expand Down
1 change: 1 addition & 0 deletions examples/AspNetCore/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"UseTracingExporter": "console",
"UseMetricsExporter": "console",
"UseLogExporter": "console",
"HistogramAggregation": "explicit",
"Jaeger": {
"AgentHost": "localhost",
"AgentPort": 6831,
Expand Down
58 changes: 33 additions & 25 deletions src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public override ExportResult Export(in Batch<Metric> batch)

var metricType = metric.MetricType;

if (metricType.IsHistogram())
if (metricType == MetricType.Histogram || metricType == MetricType.ExponentialHistogram)
{
var bucketsBuilder = new StringBuilder();
var sum = metricPoint.GetHistogramSum();
Expand All @@ -105,41 +105,49 @@ public override ExportResult Export(in Batch<Metric> batch)

bucketsBuilder.AppendLine();

bool isFirstIteration = true;
double previousExplicitBound = default;
foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets())
if (metricType == MetricType.Histogram)
{
if (isFirstIteration)
bool isFirstIteration = true;
double previousExplicitBound = default;
foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets())
{
bucketsBuilder.Append("(-Infinity,");
bucketsBuilder.Append(histogramMeasurement.ExplicitBound);
bucketsBuilder.Append(']');
bucketsBuilder.Append(':');
bucketsBuilder.Append(histogramMeasurement.BucketCount);
previousExplicitBound = histogramMeasurement.ExplicitBound;
isFirstIteration = false;
}
else
{
bucketsBuilder.Append('(');
bucketsBuilder.Append(previousExplicitBound);
bucketsBuilder.Append(',');
if (histogramMeasurement.ExplicitBound != double.PositiveInfinity)
if (isFirstIteration)
{
bucketsBuilder.Append("(-Infinity,");
bucketsBuilder.Append(histogramMeasurement.ExplicitBound);
bucketsBuilder.Append(']');
bucketsBuilder.Append(':');
bucketsBuilder.Append(histogramMeasurement.BucketCount);
previousExplicitBound = histogramMeasurement.ExplicitBound;
isFirstIteration = false;
}
else
{
bucketsBuilder.Append("+Infinity");
bucketsBuilder.Append('(');
bucketsBuilder.Append(previousExplicitBound);
bucketsBuilder.Append(',');
if (histogramMeasurement.ExplicitBound != double.PositiveInfinity)
{
bucketsBuilder.Append(histogramMeasurement.ExplicitBound);
previousExplicitBound = histogramMeasurement.ExplicitBound;
}
else
{
bucketsBuilder.Append("+Infinity");
}

bucketsBuilder.Append(']');
bucketsBuilder.Append(':');
bucketsBuilder.Append(histogramMeasurement.BucketCount);
}

bucketsBuilder.Append(']');
bucketsBuilder.Append(':');
bucketsBuilder.Append(histogramMeasurement.BucketCount);
bucketsBuilder.AppendLine();
}

bucketsBuilder.AppendLine();
}
else
{
// TODO: Consider how/if to display buckets for exponential histograms.
bucketsBuilder.AppendLine("Buckets are not displayed for exponential histograms.");
}

valueDisplay = bucketsBuilder.ToString();
Expand Down
4 changes: 4 additions & 0 deletions src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

* Add support for exporting histograms aggregated using the
[Base2 Exponential Bucket Histogram Aggregation](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#base2-exponential-bucket-histogram-aggregation).
([#4337](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4337))

* Added support to set `TraceState` when converting the
System.Diagnostics.Activity object to its corresponding
OpenTelemetry.Proto.Trace.V1.Span object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,57 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric)
otlpMetric.Histogram = histogram;
break;
}

case MetricType.ExponentialHistogram:
{
var histogram = new OtlpMetrics.ExponentialHistogram
{
AggregationTemporality = temporality,
};

foreach (ref readonly var metricPoint in metric.GetMetricPoints())
{
var dataPoint = new OtlpMetrics.ExponentialHistogramDataPoint
{
StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(),
TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(),
};

AddAttributes(metricPoint.Tags, dataPoint.Attributes);
dataPoint.Count = (ulong)metricPoint.GetHistogramCount();
dataPoint.Sum = metricPoint.GetHistogramSum();

if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max))
{
dataPoint.Min = min;
dataPoint.Max = max;
}

var exponentialHistogramData = metricPoint.GetExponentialHistogramData();
dataPoint.Scale = exponentialHistogramData.Scale;

dataPoint.Positive = new OtlpMetrics.ExponentialHistogramDataPoint.Types.Buckets();
dataPoint.Positive.Offset = exponentialHistogramData.PositiveBuckets.Offset;
foreach (var bucketCount in exponentialHistogramData.PositiveBuckets)
{
dataPoint.Positive.BucketCounts.Add((ulong)bucketCount);
}

dataPoint.Negative = new OtlpMetrics.ExponentialHistogramDataPoint.Types.Buckets();
dataPoint.Negative.Offset = exponentialHistogramData.NegativeBuckets.Offset;
foreach (var bucketCount in exponentialHistogramData.NegativeBuckets)
{
dataPoint.Negative.BucketCounts.Add((ulong)bucketCount);
}

// TODO: exemplars.

histogram.DataPoints.Add(dataPoint);
}

otlpMetric.ExponentialHistogram = histogram;
break;
}
}

return otlpMetric;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ UpDownCounter becomes gauge

public static int WriteMetric(byte[] buffer, int cursor, Metric metric)
{
if (metric.MetricType == MetricType.ExponentialHistogram)
{
// Exponential histograms are not yet support by Prometheus.
// They are ignored for now.
return cursor;
}

int metricType = (int)metric.MetricType >> 4;
cursor = WriteTypeMetadata(buffer, cursor, metric.Name, metric.Unit, MetricTypes[metricType]);
cursor = WriteUnitMetadata(buffer, cursor, metric.Name, metric.Unit);
Expand Down
6 changes: 6 additions & 0 deletions src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ OpenTelemetry.Metrics.AlwaysOffExemplarFilter
OpenTelemetry.Metrics.AlwaysOffExemplarFilter.AlwaysOffExemplarFilter() -> void
OpenTelemetry.Metrics.AlwaysOnExemplarFilter
OpenTelemetry.Metrics.AlwaysOnExemplarFilter.AlwaysOnExemplarFilter() -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.Base2ExponentialBucketHistogramConfiguration() -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxScale.get -> int
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxScale.set -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxSize.get -> int
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxSize.set -> void
OpenTelemetry.Metrics.Exemplar
OpenTelemetry.Metrics.Exemplar.DoubleValue.get -> double
OpenTelemetry.Metrics.Exemplar.Exemplar() -> void
Expand Down
6 changes: 6 additions & 0 deletions src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ OpenTelemetry.Metrics.AlwaysOffExemplarFilter
OpenTelemetry.Metrics.AlwaysOffExemplarFilter.AlwaysOffExemplarFilter() -> void
OpenTelemetry.Metrics.AlwaysOnExemplarFilter
OpenTelemetry.Metrics.AlwaysOnExemplarFilter.AlwaysOnExemplarFilter() -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.Base2ExponentialBucketHistogramConfiguration() -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxScale.get -> int
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxScale.set -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxSize.get -> int
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxSize.set -> void
OpenTelemetry.Metrics.Exemplar
OpenTelemetry.Metrics.Exemplar.DoubleValue.get -> double
OpenTelemetry.Metrics.Exemplar.Exemplar() -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ OpenTelemetry.Metrics.AlwaysOffExemplarFilter
OpenTelemetry.Metrics.AlwaysOffExemplarFilter.AlwaysOffExemplarFilter() -> void
OpenTelemetry.Metrics.AlwaysOnExemplarFilter
OpenTelemetry.Metrics.AlwaysOnExemplarFilter.AlwaysOnExemplarFilter() -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.Base2ExponentialBucketHistogramConfiguration() -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxScale.get -> int
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxScale.set -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxSize.get -> int
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxSize.set -> void
OpenTelemetry.Metrics.Exemplar
OpenTelemetry.Metrics.Exemplar.DoubleValue.get -> double
OpenTelemetry.Metrics.Exemplar.Exemplar() -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ OpenTelemetry.Metrics.AlwaysOffExemplarFilter
OpenTelemetry.Metrics.AlwaysOffExemplarFilter.AlwaysOffExemplarFilter() -> void
OpenTelemetry.Metrics.AlwaysOnExemplarFilter
OpenTelemetry.Metrics.AlwaysOnExemplarFilter.AlwaysOnExemplarFilter() -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.Base2ExponentialBucketHistogramConfiguration() -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxScale.get -> int
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxScale.set -> void
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxSize.get -> int
OpenTelemetry.Metrics.Base2ExponentialBucketHistogramConfiguration.MaxSize.set -> void
OpenTelemetry.Metrics.Exemplar
OpenTelemetry.Metrics.Exemplar.DoubleValue.get -> double
OpenTelemetry.Metrics.Exemplar.Exemplar() -> void
Expand Down
6 changes: 6 additions & 0 deletions src/OpenTelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Unreleased

* Add support for configuring the
[Base2 Exponential Bucket Histogram Aggregation](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#base2-exponential-bucket-histogram-aggregation)
using the `AddView` API. This aggregation is supported by OTLP but not yet by
Prometheus.
([#4337](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4337))

* Implementation of `SuppressInstrumentationScope` changed to improve
performance.
([#4304](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4304))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace OpenTelemetry.Metrics;
/// <summary>
/// Stores configuration for a histogram metric stream with base-2 exponential bucket boundaries.
/// </summary>
internal sealed class Base2ExponentialBucketHistogramConfiguration : HistogramConfiguration
public sealed class Base2ExponentialBucketHistogramConfiguration : HistogramConfiguration
{
private int maxSize = Metric.DefaultExponentialHistogramMaxBuckets;
private int maxScale = Metric.DefaultExponentialHistogramMaxScale;
Expand Down
Loading

0 comments on commit 410532a

Please sign in to comment.