Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for decimal metric instruments #5620

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,17 @@ public override ExportResult Export(in Batch<Metric> batch)
valueDisplay = metricPoint.GetGaugeLastValueLong().ToString(CultureInfo.InvariantCulture);
}
}
else if (metricType.IsDecimal())
{
if (metricType.IsSum())
{
valueDisplay = metricPoint.GetSumDecimal().ToString(CultureInfo.InvariantCulture);
}
else
{
valueDisplay = metricPoint.GetGaugeLastValueDecimal().ToString(CultureInfo.InvariantCulture);
}
}

var exemplarString = new StringBuilder();
if (metricPoint.TryGetExemplars(out var exemplars))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,43 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric)
break;
}

case MetricType.DecimalSum:
case MetricType.DecimalSumNonMonotonic:
{
var sum = new Sum
{
IsMonotonic = metric.MetricType == MetricType.DecimalSum,
AggregationTemporality = temporality,
};

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

AddAttributes(metricPoint.Tags, dataPoint.Attributes);

dataPoint.AsDouble = (double)metricPoint.GetSumDecimal();

if (metricPoint.TryGetExemplars(out var exemplars))
{
foreach (ref readonly var exemplar in exemplars)
{
dataPoint.Exemplars.Add(
ToOtlpExemplar(exemplar.DoubleValue, in exemplar));
}
}

sum.DataPoints.Add(dataPoint);
}

otlpMetric.Sum = sum;
break;
}

case MetricType.LongGauge:
{
var gauge = new Gauge();
Expand Down Expand Up @@ -274,6 +311,37 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric)
break;
}

case MetricType.DecimalGauge:
{
var gauge = new Gauge();
foreach (ref readonly var metricPoint in metric.GetMetricPoints())
{
var dataPoint = new NumberDataPoint
{
StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(),
TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(),
};

AddAttributes(metricPoint.Tags, dataPoint.Attributes);

dataPoint.AsDouble = (double)metricPoint.GetGaugeLastValueDecimal();

if (metricPoint.TryGetExemplars(out var exemplars))
{
foreach (ref readonly var exemplar in exemplars)
{
dataPoint.Exemplars.Add(
ToOtlpExemplar(exemplar.DoubleValue, in exemplar));
}
}

gauge.DataPoints.Add(dataPoint);
}

otlpMetric.Gauge = gauge;
break;
}

case MetricType.Histogram:
{
var histogram = new Histogram
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
abstract OpenTelemetry.Metrics.ExemplarReservoir.Collect() -> OpenTelemetry.Metrics.ReadOnlyExemplarCollection
abstract OpenTelemetry.Metrics.ExemplarReservoir.Offer(in OpenTelemetry.Metrics.ExemplarMeasurement<decimal> measurement) -> void
abstract OpenTelemetry.Metrics.ExemplarReservoir.Offer(in OpenTelemetry.Metrics.ExemplarMeasurement<double> measurement) -> void
abstract OpenTelemetry.Metrics.ExemplarReservoir.Offer(in OpenTelemetry.Metrics.ExemplarMeasurement<long> measurement) -> void
OpenTelemetry.Logs.LoggerProviderBuilderExtensions
Expand Down
6 changes: 6 additions & 0 deletions src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ OpenTelemetry.Metrics.ExemplarFilterType
OpenTelemetry.Metrics.ExemplarFilterType.AlwaysOff = 0 -> OpenTelemetry.Metrics.ExemplarFilterType
OpenTelemetry.Metrics.ExemplarFilterType.AlwaysOn = 1 -> OpenTelemetry.Metrics.ExemplarFilterType
OpenTelemetry.Metrics.ExemplarFilterType.TraceBased = 2 -> OpenTelemetry.Metrics.ExemplarFilterType
OpenTelemetry.Metrics.MetricPoint.GetGaugeLastValueDecimal() -> decimal
OpenTelemetry.Metrics.MetricPoint.GetSumDecimal() -> decimal
OpenTelemetry.Metrics.MetricPoint.TryGetExemplars(out OpenTelemetry.Metrics.ReadOnlyExemplarCollection exemplars) -> bool
OpenTelemetry.Metrics.MetricType.DecimalGauge = 46 -> OpenTelemetry.Metrics.MetricType
OpenTelemetry.Metrics.MetricType.DecimalSum = 30 -> OpenTelemetry.Metrics.MetricType
OpenTelemetry.Metrics.MetricType.DecimalSumNonMonotonic = 142 -> OpenTelemetry.Metrics.MetricType
OpenTelemetry.Metrics.ReadOnlyExemplarCollection
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.Enumerator
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.Enumerator.Current.get -> OpenTelemetry.Metrics.Exemplar
Expand All @@ -26,3 +31,4 @@ OpenTelemetry.ReadOnlyFilteredTagCollection.Enumerator.MoveNext() -> bool
OpenTelemetry.ReadOnlyFilteredTagCollection.GetEnumerator() -> OpenTelemetry.ReadOnlyFilteredTagCollection.Enumerator
OpenTelemetry.ReadOnlyFilteredTagCollection.ReadOnlyFilteredTagCollection() -> void
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetExemplarFilter(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder, OpenTelemetry.Metrics.ExemplarFilterType exemplarFilter) -> OpenTelemetry.Metrics.MeterProviderBuilder!
static OpenTelemetry.Metrics.MetricTypeExtensions.IsDecimal(this OpenTelemetry.Metrics.MetricType self) -> bool
3 changes: 3 additions & 0 deletions src/OpenTelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
supported in stable builds.
([#5607](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5607))

* Add support for decimal metric instruments.
([#5620](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5620))

## 1.8.1

Released 2024-Apr-17
Expand Down
15 changes: 15 additions & 0 deletions src/OpenTelemetry/Metrics/AggregationType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,19 @@ internal enum AggregationType
/// Exponential Histogram with sum, count, min, max.
/// </summary>
Base2ExponentialHistogramWithMinMax = 11,

/// <summary>
/// Calculate SUM from incoming delta measurements.
/// </summary>
DecimalSumIncomingDelta = 12,

/// <summary>
/// Calculate SUM from incoming cumulative measurements.
/// </summary>
DecimalSumIncomingCumulative = 13,

/// <summary>
/// Keep LastValue.
/// </summary>
DecimalGauge = 14,
}
73 changes: 73 additions & 0 deletions src/OpenTelemetry/Metrics/AggregatorStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ internal sealed class AggregatorStore
private readonly int exponentialHistogramMaxScale;
private readonly UpdateLongDelegate updateLongCallback;
private readonly UpdateDoubleDelegate updateDoubleCallback;
private readonly UpdateDecimalDelegate updateDecimalCallback;
private readonly ExemplarFilterType exemplarFilter;
private readonly Func<KeyValuePair<string, object?>[], int, int> lookupAggregatorStore;

Expand Down Expand Up @@ -91,11 +92,13 @@ internal AggregatorStore(
{
this.updateLongCallback = this.UpdateLong;
this.updateDoubleCallback = this.UpdateDouble;
this.updateDecimalCallback = this.UpdateDecimal;
}
else
{
this.updateLongCallback = this.UpdateLongCustomTags;
this.updateDoubleCallback = this.UpdateDoubleCustomTags;
this.updateDecimalCallback = this.UpdateDecimalCustomTags;
#if NET8_0_OR_GREATER
var hs = FrozenSet.ToFrozenSet(metricStreamIdentity.TagKeys, StringComparer.Ordinal);
#else
Expand Down Expand Up @@ -150,6 +153,8 @@ internal AggregatorStore(

private delegate void UpdateDoubleDelegate(double value, ReadOnlySpan<KeyValuePair<string, object?>> tags);

private delegate void UpdateDecimalDelegate(decimal value, ReadOnlySpan<KeyValuePair<string, object?>> tags);

internal DateTimeOffset StartTimeExclusive { get; private set; }

internal DateTimeOffset EndTimeInclusive { get; private set; }
Expand Down Expand Up @@ -189,6 +194,19 @@ internal void Update(double value, ReadOnlySpan<KeyValuePair<string, object?>> t
}
}

internal void Update(decimal value, ReadOnlySpan<KeyValuePair<string, object?>> tags)
{
try
{
this.updateDecimalCallback(value, tags);
}
catch (Exception)
{
Interlocked.Increment(ref this.DroppedMeasurements);
OpenTelemetrySdkEventSource.Log.MeasurementDropped(this.name, "SDK internal error occurred.", "Contact SDK owners.");
}
}

internal int Snapshot()
{
this.batchSize = 0;
Expand Down Expand Up @@ -1043,6 +1061,20 @@ private void UpdateDoubleCustomTags(double value, ReadOnlySpan<KeyValuePair<stri
this.UpdateDoubleMetricPoint(index, value, tags);
}

private void UpdateDecimal(decimal value, ReadOnlySpan<KeyValuePair<string, object?>> tags)
{
var index = this.FindMetricAggregatorsDefault(tags);

this.UpdateDecimalMetricPoint(index, value, tags);
}

private void UpdateDecimalCustomTags(decimal value, ReadOnlySpan<KeyValuePair<string, object?>> tags)
{
var index = this.FindMetricAggregatorsCustomTag(tags);

this.UpdateDecimalMetricPoint(index, value, tags);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpdateDoubleMetricPoint(int metricPointIndex, double value, ReadOnlySpan<KeyValuePair<string, object?>> tags)
{
Expand Down Expand Up @@ -1084,6 +1116,47 @@ private void UpdateDoubleMetricPoint(int metricPointIndex, double value, ReadOnl
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpdateDecimalMetricPoint(int metricPointIndex, decimal value, ReadOnlySpan<KeyValuePair<string, object?>> tags)
{
if (metricPointIndex < 0)
{
Interlocked.Increment(ref this.DroppedMeasurements);

if (this.EmitOverflowAttribute)
{
this.InitializeOverflowTagPointIfNotInitialized();
this.metricPoints[1].Update(value);
}
else if (Interlocked.CompareExchange(ref this.metricCapHitMessageLogged, 1, 0) == 0)
{
OpenTelemetrySdkEventSource.Log.MeasurementDropped(this.name, this.metricPointCapHitMessage, MetricPointCapHitFixMessage);
}

return;
}

var exemplarFilterType = this.exemplarFilter;
if (exemplarFilterType == ExemplarFilterType.AlwaysOff)
{
this.metricPoints[metricPointIndex].Update(value);
}
else if (exemplarFilterType == ExemplarFilterType.AlwaysOn)
{
this.metricPoints[metricPointIndex].UpdateWithExemplar(
value,
tags,
offerExemplar: true);
}
else
{
this.metricPoints[metricPointIndex].UpdateWithExemplar(
value,
tags,
offerExemplar: Activity.Current?.Recorded ?? false);
}
}

private int FindMetricAggregatorsDefault(ReadOnlySpan<KeyValuePair<string, object?>> tags)
{
int tagLength = tags.Length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,13 @@ public override void Offer(in ExemplarMeasurement<double> measurement)

this.UpdateExemplar(measurement.ExplicitBucketHistogramBucketIndex, in measurement);
}

public override void Offer(in ExemplarMeasurement<decimal> measurement)
{
Debug.Assert(
measurement.ExplicitBucketHistogramBucketIndex != -1,
"ExplicitBucketHistogramBucketIndex was -1");

this.UpdateExemplar(measurement.ExplicitBucketHistogramBucketIndex, in measurement);
}
}
6 changes: 6 additions & 0 deletions src/OpenTelemetry/Metrics/Exemplar/ExemplarReservoir.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ internal ExemplarReservoir()
/// <param name="measurement"><see cref="ExemplarMeasurement{T}"/>.</param>
public abstract void Offer(in ExemplarMeasurement<double> measurement);

/// <summary>
/// Offers a measurement to the reservoir.
/// </summary>
/// <param name="measurement"><see cref="ExemplarMeasurement{T}"/>.</param>
public abstract void Offer(in ExemplarMeasurement<decimal> measurement);

/// <summary>
/// Collects all the exemplars accumulated by the Reservoir.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public override void Offer(in ExemplarMeasurement<double> measurement)
this.Offer(in measurement);
}

public override void Offer(in ExemplarMeasurement<decimal> measurement)
{
this.Offer(in measurement);
}

protected override void OnCollected()
{
// Reset internal state irrespective of temporality.
Expand Down
14 changes: 14 additions & 0 deletions src/OpenTelemetry/Metrics/MeterProviderSdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ internal MeterProviderSdk(
this.listener.SetMeasurementEventCallback<short>(static (instrument, value, tags, state) => MeasurementRecordedLong(instrument, value, tags, state));
this.listener.SetMeasurementEventCallback<byte>(static (instrument, value, tags, state) => MeasurementRecordedLong(instrument, value, tags, state));

// decimal
this.listener.SetMeasurementEventCallback<decimal>(MeasurementRecordedDecimal);

this.listener.MeasurementsCompleted = MeasurementsCompleted;

this.listener.Start();
Expand Down Expand Up @@ -228,6 +231,17 @@ internal static void MeasurementRecordedDouble(Instrument instrument, double val
metricState.RecordMeasurementDouble(value, tags);
}

internal static void MeasurementRecordedDecimal(Instrument instrument, decimal value, ReadOnlySpan<KeyValuePair<string, object?>> tags, object? state)
{
if (state is not MetricState metricState)
{
OpenTelemetrySdkEventSource.Log.MeasurementDropped(instrument?.Name ?? "UnknownInstrument", "SDK internal error occurred.", "Contact SDK owners.");
return;
}

metricState.RecordMeasurementDecimal(value, tags);
}

internal object? InstrumentPublished(Instrument instrument, bool listeningIsManagedExternally)
{
var listenToInstrumentUsingSdkConfiguration = this.shouldListenTo(instrument);
Expand Down
Loading
Loading