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

[sdk-metrics] Exemplar spec & perf improvements #5364

Closed
Closed
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
bf8b6dd
WIP to update exmplar code.
CodeBlanch Feb 13, 2024
daf57cd
First compiling version.
CodeBlanch Feb 14, 2024
c23e7bf
Tweak.
CodeBlanch Feb 14, 2024
feb1c7e
Improvements.
CodeBlanch Feb 14, 2024
4e97f10
API updates.
CodeBlanch Feb 14, 2024
05e058a
Tweak.
CodeBlanch Feb 14, 2024
4542e83
Tweaks.
CodeBlanch Feb 14, 2024
82e6fa6
Better concurrency. Bug fixes.
CodeBlanch Feb 14, 2024
6b20ac3
Tweaks.
CodeBlanch Feb 14, 2024
4c849be
Tweaks.
CodeBlanch Feb 14, 2024
de1856a
Tweaks.
CodeBlanch Feb 14, 2024
ea58f75
Tweak.
CodeBlanch Feb 15, 2024
369738b
Tweak.
CodeBlanch Feb 15, 2024
645bb75
Merge from main.
CodeBlanch Feb 15, 2024
17cbe69
Cleanup.
CodeBlanch Feb 15, 2024
39230c9
Cleanup.
CodeBlanch Feb 15, 2024
7a8669c
Tweaks.
CodeBlanch Feb 15, 2024
65e87eb
CHANGELOG patch.
CodeBlanch Feb 15, 2024
aa0b3b5
Faster init for FixedSizeExemplarReservoir buffers.
CodeBlanch Feb 16, 2024
b21ba8d
Merge from main.
CodeBlanch Feb 16, 2024
ea2f149
Tweaks.
CodeBlanch Feb 16, 2024
ee7a978
Tweak.
CodeBlanch Feb 18, 2024
6ccfd4d
Tweaks.
CodeBlanch Feb 18, 2024
b2b327a
Tweak.
CodeBlanch Feb 18, 2024
04d56ca
Merge from main.
CodeBlanch Feb 20, 2024
a6011de
WIP
CodeBlanch Feb 20, 2024
015670a
Tweaks.
CodeBlanch Feb 21, 2024
fb521aa
Test improvements and tweaks.
CodeBlanch Feb 21, 2024
8bde052
Code review.
CodeBlanch Feb 21, 2024
c2c7f0a
Code review.
CodeBlanch Feb 21, 2024
0ffba7d
Code review.
CodeBlanch Feb 21, 2024
fb9b07a
Code review.
CodeBlanch Feb 21, 2024
4512b49
Merge remote-tracking branch 'upstream/main' into sdk-exemplar-spec-i…
CodeBlanch Feb 22, 2024
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
1 change: 1 addition & 0 deletions OpenTelemetry.sln
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A49299
src\Shared\TagAndValueTransformer.cs = src\Shared\TagAndValueTransformer.cs
src\Shared\TagTransformer.cs = src\Shared\TagTransformer.cs
src\Shared\TagTransformerJsonHelper.cs = src\Shared\TagTransformerJsonHelper.cs
src\Shared\ThreadSafeRandom.cs = src\Shared\ThreadSafeRandom.cs
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DiagnosticSourceInstrumentation", "DiagnosticSourceInstrumentation", "{28F3EC79-660C-4659-8B73-F90DC1173316}"
Expand Down
46 changes: 30 additions & 16 deletions src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,30 +188,44 @@ public override ExportResult Export(in Batch<Metric> batch)
}

var exemplarString = new StringBuilder();
foreach (var exemplar in metricPoint.GetExemplars())
if (metricPoint.TryGetExemplars(out var exemplars))
{
if (exemplar.Timestamp != default)
foreach (ref readonly var exemplar in exemplars)
cijothomas marked this conversation as resolved.
Show resolved Hide resolved
{
exemplarString.Append("Value: ");
exemplarString.Append(exemplar.DoubleValue);
exemplarString.Append(" Timestamp: ");
exemplarString.Append("Timestamp: ");
exemplarString.Append(exemplar.Timestamp.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ", CultureInfo.InvariantCulture));
exemplarString.Append(" TraceId: ");
exemplarString.Append(exemplar.TraceId);
exemplarString.Append(" SpanId: ");
exemplarString.Append(exemplar.SpanId);
if (metricType.IsDouble())
{
exemplarString.Append(" Value: ");
exemplarString.Append(exemplar.DoubleValue);
}
else if (metricType.IsLong())
{
exemplarString.Append(" Value: ");
exemplarString.Append(exemplar.LongValue);
}

if (exemplar.FilteredTags != null && exemplar.FilteredTags.Count > 0)
if (exemplar.TraceId.HasValue)
{
exemplarString.Append(" Filtered Tags : ");
exemplarString.Append(" TraceId: ");
exemplarString.Append(exemplar.TraceId.Value.ToHexString());
exemplarString.Append(" SpanId: ");
exemplarString.Append(exemplar.SpanId.Value.ToHexString());
}

foreach (var tag in exemplar.FilteredTags)
bool appendedTagString = false;
foreach (var tag in exemplar.FilteredTags)
{
if (ConsoleTagTransformer.Instance.TryTransformTag(tag, out var result))
{
if (ConsoleTagTransformer.Instance.TryTransformTag(tag, out var result))
if (!appendedTagString)
{
exemplarString.Append(result);
exemplarString.Append(' ');
exemplarString.Append(" Filtered Tags : ");
appendedTagString = true;
}

exemplarString.Append(result);
exemplarString.Append(' ');
}
}

Expand Down Expand Up @@ -239,7 +253,7 @@ public override ExportResult Export(in Batch<Metric> batch)
{
msg.AppendLine();
msg.AppendLine("Exemplars");
msg.Append(exemplarString.ToString());
msg.Append(exemplarString);
}

this.WriteLine(msg.ToString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Google.Protobuf;
using Google.Protobuf.Collections;
Expand Down Expand Up @@ -267,37 +268,12 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric)
}
}

var exemplars = metricPoint.GetExemplars();
foreach (var examplar in exemplars)
if (metricPoint.TryGetExemplars(out var exemplars))
{
if (examplar.Timestamp != default)
foreach (ref readonly var exemplar in exemplars)
{
byte[] traceIdBytes = new byte[16];
examplar.TraceId?.CopyTo(traceIdBytes);

byte[] spanIdBytes = new byte[8];
examplar.SpanId?.CopyTo(spanIdBytes);

var otlpExemplar = new OtlpMetrics.Exemplar
{
TimeUnixNano = (ulong)examplar.Timestamp.ToUnixTimeNanoseconds(),
TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes),
SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes),
AsDouble = examplar.DoubleValue,
};

if (examplar.FilteredTags != null)
{
foreach (var tag in examplar.FilteredTags)
{
if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result))
{
otlpExemplar.FilteredAttributes.Add(result);
}
}
}

dataPoint.Exemplars.Add(otlpExemplar);
dataPoint.Exemplars.Add(
ToOtlpExemplar(exemplar.DoubleValue, in exemplar));
}
}

Expand Down Expand Up @@ -379,51 +355,48 @@ private static void AddScopeAttributes(IEnumerable<KeyValuePair<string, object>>
}
}

/*
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static OtlpMetrics.Exemplar ToOtlpExemplar(this IExemplar exemplar)
private static OtlpMetrics.Exemplar ToOtlpExemplar<T>(T value, in Metrics.Exemplar exemplar)
where T : struct
{
var otlpExemplar = new OtlpMetrics.Exemplar();

if (exemplar.Value is double doubleValue)
var otlpExemplar = new OtlpMetrics.Exemplar
{
otlpExemplar.AsDouble = doubleValue;
}
else if (exemplar.Value is long longValue)
TimeUnixNano = (ulong)exemplar.Timestamp.ToUnixTimeNanoseconds(),
};

if (exemplar.TraceId.HasValue)
{
otlpExemplar.AsInt = longValue;
byte[] traceIdBytes = new byte[16];
exemplar.TraceId.Value.CopyTo(traceIdBytes);

byte[] spanIdBytes = new byte[8];
exemplar.SpanId.Value.CopyTo(spanIdBytes);

otlpExemplar.TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes);
otlpExemplar.SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes);
}
else

if (typeof(T) == typeof(long))
{
// TODO: Determine how we want to handle exceptions here.
// Do we want to just skip this exemplar and move on?
// Should we skip recording the whole metric?
throw new ArgumentException();
otlpExemplar.AsInt = (long)(object)value;
}

otlpExemplar.TimeUnixNano = (ulong)exemplar.Timestamp.ToUnixTimeNanoseconds();

// TODO: Do the TagEnumerationState thing.
foreach (var tag in exemplar.FilteredTags)
else if (typeof(T) == typeof(double))
{
otlpExemplar.FilteredAttributes.Add(tag.ToOtlpAttribute());
otlpExemplar.AsDouble = (double)(object)value;
}

if (exemplar.TraceId != default)
else
{
byte[] traceIdBytes = new byte[16];
exemplar.TraceId.CopyTo(traceIdBytes);
otlpExemplar.TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes);
Debug.Fail("Unexpected type");
otlpExemplar.AsDouble = Convert.ToDouble(value);
}

if (exemplar.SpanId != default)
foreach (var tag in exemplar.FilteredTags)
{
byte[] spanIdBytes = new byte[8];
exemplar.SpanId.CopyTo(spanIdBytes);
otlpExemplar.SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes);
if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result))
{
otlpExemplar.FilteredAttributes.Add(result);
}
}

return otlpExemplar;
}
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,38 @@ OpenTelemetry.Metrics.AlwaysOnExemplarFilter.AlwaysOnExemplarFilter() -> void
OpenTelemetry.Metrics.Exemplar
OpenTelemetry.Metrics.Exemplar.DoubleValue.get -> double
OpenTelemetry.Metrics.Exemplar.Exemplar() -> void
OpenTelemetry.Metrics.Exemplar.FilteredTags.get -> OpenTelemetry.ReadOnlyFilteredTagCollection
OpenTelemetry.Metrics.Exemplar.LongValue.get -> long
OpenTelemetry.Metrics.Exemplar.SpanId.get -> System.Diagnostics.ActivitySpanId?
OpenTelemetry.Metrics.Exemplar.Timestamp.get -> System.DateTimeOffset
OpenTelemetry.Metrics.Exemplar.TraceId.get -> System.Diagnostics.ActivityTraceId?
OpenTelemetry.Metrics.ExemplarFilter
OpenTelemetry.Metrics.ExemplarFilter.ExemplarFilter() -> void
OpenTelemetry.Metrics.MetricPoint.GetExemplars() -> OpenTelemetry.Metrics.Exemplar[]!
OpenTelemetry.Metrics.ExemplarMeasurement<T>
OpenTelemetry.Metrics.ExemplarMeasurement<T>.ExemplarMeasurement() -> void
OpenTelemetry.Metrics.ExemplarMeasurement<T>.Tags.get -> System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string!, object?>>
OpenTelemetry.Metrics.ExemplarMeasurement<T>.Value.get -> T
OpenTelemetry.Metrics.MetricPoint.TryGetExemplars(out OpenTelemetry.Metrics.ReadOnlyExemplarCollection? exemplars) -> bool
OpenTelemetry.Metrics.MetricStreamConfiguration.CardinalityLimit.get -> int?
OpenTelemetry.Metrics.MetricStreamConfiguration.CardinalityLimit.set -> void
OpenTelemetry.Metrics.ReadOnlyExemplarCollection
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.Enumerator
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.Enumerator.Current.get -> OpenTelemetry.Metrics.Exemplar
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.Enumerator.Enumerator() -> void
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.Enumerator.MoveNext() -> bool
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.GetEnumerator() -> OpenTelemetry.Metrics.ReadOnlyExemplarCollection.Enumerator
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.MaximumCount.get -> int
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.ReadOnlyExemplarCollection() -> void
OpenTelemetry.Metrics.TraceBasedExemplarFilter
OpenTelemetry.Metrics.TraceBasedExemplarFilter.TraceBasedExemplarFilter() -> void
OpenTelemetry.ReadOnlyFilteredTagCollection
OpenTelemetry.ReadOnlyFilteredTagCollection.Enumerator
OpenTelemetry.ReadOnlyFilteredTagCollection.Enumerator.Current.get -> System.Collections.Generic.KeyValuePair<string!, object?>
OpenTelemetry.ReadOnlyFilteredTagCollection.Enumerator.Enumerator() -> void
OpenTelemetry.ReadOnlyFilteredTagCollection.Enumerator.MoveNext() -> bool
OpenTelemetry.ReadOnlyFilteredTagCollection.GetEnumerator() -> OpenTelemetry.ReadOnlyFilteredTagCollection.Enumerator
OpenTelemetry.ReadOnlyFilteredTagCollection.MaximumCount.get -> int
OpenTelemetry.ReadOnlyFilteredTagCollection.ReadOnlyFilteredTagCollection() -> void
static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, OpenTelemetry.BaseProcessor<OpenTelemetry.Logs.LogRecord!>! processor) -> OpenTelemetry.Logs.LoggerProviderBuilder!
static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddProcessor(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder, System.Func<System.IServiceProvider!, OpenTelemetry.BaseProcessor<OpenTelemetry.Logs.LogRecord!>!>! implementationFactory) -> OpenTelemetry.Logs.LoggerProviderBuilder!
static OpenTelemetry.Logs.LoggerProviderBuilderExtensions.AddProcessor<T>(this OpenTelemetry.Logs.LoggerProviderBuilder! loggerProviderBuilder) -> OpenTelemetry.Logs.LoggerProviderBuilder!
Expand All @@ -38,7 +60,6 @@ static OpenTelemetry.OpenTelemetryBuilderSdkExtensions.WithLogging(this OpenTele
static OpenTelemetry.Sdk.CreateLoggerProviderBuilder() -> OpenTelemetry.Logs.LoggerProviderBuilder!
abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(double value, System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string!, object?>> tags) -> bool
abstract OpenTelemetry.Metrics.ExemplarFilter.ShouldSample(long value, System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string!, object?>> tags) -> bool
OpenTelemetry.Metrics.Exemplar.FilteredTags.get -> System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string!, object?>>?
override OpenTelemetry.Metrics.AlwaysOffExemplarFilter.ShouldSample(double value, System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string!, object?>> tags) -> bool
override OpenTelemetry.Metrics.AlwaysOffExemplarFilter.ShouldSample(long value, System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string!, object?>> tags) -> bool
override OpenTelemetry.Metrics.AlwaysOnExemplarFilter.ShouldSample(double value, System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string!, object?>> tags) -> bool
Expand Down
5 changes: 5 additions & 0 deletions src/OpenTelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@
[IMetricsListener](https://learn.microsoft.com/dotNet/api/microsoft.extensions.diagnostics.metrics.imetricslistener).
([#5265](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5265))

* **Experimental (pre-release builds only):** `Exemplar` and `ExemplarReservoir`
APIs have been updated to match the OpenTelemetry Specification and to achieve
better throughput under load.
([#5364](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5364))

## 1.7.0

Released 2023-Dec-08
Expand Down
Loading