Skip to content

Commit 89aa7a4

Browse files
authored
[sdk-metrics] Expose ExemplarReservoir and support configuration via views (#5542)
1 parent bf423cc commit 89aa7a4

File tree

6 files changed

+68
-6
lines changed

6 files changed

+68
-6
lines changed

src/OpenTelemetry/.publicApi/Experimental/PublicAPI.Unshipped.txt

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
abstract OpenTelemetry.Metrics.ExemplarReservoir.Collect() -> OpenTelemetry.Metrics.ReadOnlyExemplarCollection
2+
abstract OpenTelemetry.Metrics.ExemplarReservoir.Offer(in OpenTelemetry.Metrics.ExemplarMeasurement<double> measurement) -> void
3+
abstract OpenTelemetry.Metrics.ExemplarReservoir.Offer(in OpenTelemetry.Metrics.ExemplarMeasurement<long> measurement) -> void
14
OpenTelemetry.Logs.LoggerProviderBuilderExtensions
25
OpenTelemetry.Logs.LoggerProviderExtensions
36
OpenTelemetry.Logs.LogRecord.Logger.get -> OpenTelemetry.Logs.Logger!
@@ -21,9 +24,14 @@ OpenTelemetry.Metrics.ExemplarMeasurement<T>
2124
OpenTelemetry.Metrics.ExemplarMeasurement<T>.ExemplarMeasurement() -> void
2225
OpenTelemetry.Metrics.ExemplarMeasurement<T>.Tags.get -> System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string!, object?>>
2326
OpenTelemetry.Metrics.ExemplarMeasurement<T>.Value.get -> T
27+
OpenTelemetry.Metrics.ExemplarReservoir
28+
OpenTelemetry.Metrics.ExemplarReservoir.ExemplarReservoir() -> void
29+
OpenTelemetry.Metrics.ExemplarReservoir.ResetOnCollect.get -> bool
2430
OpenTelemetry.Metrics.MetricPoint.TryGetExemplars(out OpenTelemetry.Metrics.ReadOnlyExemplarCollection exemplars) -> bool
2531
OpenTelemetry.Metrics.MetricStreamConfiguration.CardinalityLimit.get -> int?
2632
OpenTelemetry.Metrics.MetricStreamConfiguration.CardinalityLimit.set -> void
33+
OpenTelemetry.Metrics.MetricStreamConfiguration.ExemplarReservoirFactory.get -> System.Func<OpenTelemetry.Metrics.ExemplarReservoir?>?
34+
OpenTelemetry.Metrics.MetricStreamConfiguration.ExemplarReservoirFactory.set -> void
2735
OpenTelemetry.Metrics.ReadOnlyExemplarCollection
2836
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.Enumerator
2937
OpenTelemetry.Metrics.ReadOnlyExemplarCollection.Enumerator.Current.get -> OpenTelemetry.Metrics.Exemplar

src/OpenTelemetry/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
during configuration reload.
88
([#5514](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5514))
99

10+
* **Experimental (pre-release builds only):** Exposed `ExemplarReservoir` as a
11+
public API and added support for setting an `ExemplarReservoir` factory
12+
function when configuring a view (applies to individual metrics).
13+
([#5542](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5542))
14+
1015
## 1.8.0
1116

1217
Released 2024-Apr-02

src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs

+15
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,15 @@ public void LoggerProcessStateSkipped<TState>()
158158
}
159159
}
160160

161+
[NonEvent]
162+
public void MetricViewException(string source, Exception ex)
163+
{
164+
if (this.IsEnabled(EventLevel.Error, EventKeywords.All))
165+
{
166+
this.MetricViewException(source, ex.ToInvariantString());
167+
}
168+
}
169+
161170
[Event(4, Message = "Unknown error in SpanProcessor event '{0}': '{1}'.", Level = EventLevel.Error)]
162171
public void SpanProcessorException(string evnt, string ex)
163172
{
@@ -359,6 +368,12 @@ public void TracesSamplerArgConfigInvalid(string configValue)
359368
this.WriteEvent(55, configValue);
360369
}
361370

371+
[Event(56, Message = "Exception thrown by user code supplied on metric view ('{0}'): '{1}'.", Level = EventLevel.Error)]
372+
public void MetricViewException(string source, string ex)
373+
{
374+
this.WriteEvent(56, source, ex);
375+
}
376+
362377
void IConfigurationExtensionsLogger.LogInvalidConfigurationValue(string key, string value)
363378
{
364379
this.InvalidConfigurationValue(key, value);

src/OpenTelemetry/Metrics/Exemplar/ExemplarReservoir.cs

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
11
// Copyright The OpenTelemetry Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4+
#if EXPOSE_EXPERIMENTAL_FEATURES && NET8_0_OR_GREATER
5+
using System.Diagnostics.CodeAnalysis;
6+
using OpenTelemetry.Internal;
7+
#endif
8+
49
namespace OpenTelemetry.Metrics;
510

11+
#if EXPOSE_EXPERIMENTAL_FEATURES
612
/// <summary>
713
/// ExemplarReservoir base implementation and contract.
814
/// </summary>
915
/// <remarks>
16+
/// <remarks><inheritdoc cref="Exemplar" path="/remarks/para[@experimental-warning='true']"/></remarks>
1017
/// Specification: <see
1118
/// href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplarreservoir"/>.
1219
/// </remarks>
13-
internal abstract class ExemplarReservoir
20+
#if NET8_0_OR_GREATER
21+
[Experimental(DiagnosticDefinitions.ExemplarExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
22+
#endif
23+
public
24+
#else
25+
internal
26+
#endif
27+
abstract class ExemplarReservoir
1428
{
1529
/// <summary>
1630
/// Gets a value indicating whether or not the <see

src/OpenTelemetry/Metrics/MetricPoint.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,13 @@ internal MetricPoint(
6262
ExemplarReservoir? reservoir;
6363
try
6464
{
65-
reservoir = aggregatorStore.ExemplarReservoirFactory?.Invoke();
65+
reservoir = isExemplarEnabled
66+
? aggregatorStore.ExemplarReservoirFactory?.Invoke()
67+
: null;
6668
}
67-
catch
69+
catch (Exception ex)
6870
{
69-
// TODO : Log that the factory on view threw an exception, once view exposes that capability
71+
OpenTelemetrySdkEventSource.Log.MetricViewException("ExemplarReservoirFactory", ex);
7072
reservoir = null;
7173
}
7274

src/OpenTelemetry/Metrics/MetricStreamConfiguration.cs

+20-2
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,27 @@ public string[]? TagKeys
137137
}
138138
}
139139

140-
// TODO: Expose this to be complaint with the spec:
141-
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#stream-configuration
140+
#if EXPOSE_EXPERIMENTAL_FEATURES
141+
/// <summary>
142+
/// Gets or sets a factory function used to generate an <see
143+
/// cref="ExemplarReservoir"/> for the metric managed by the view to use
144+
/// when storing <see cref="Exemplar"/>s.
145+
/// </summary>
146+
/// <remarks>
147+
/// <remarks><inheritdoc cref="Exemplar" path="/remarks/para[@experimental-warning='true']"/></remarks>
148+
/// <para>Note: Returning <see langword="null"/> from the factory function will
149+
/// result in the default <see cref="ExemplarReservoir"/> being chosen by
150+
/// the SDK based on the type of metric.</para>
151+
/// Specification: <see
152+
/// href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#stream-configuration"/>.
153+
/// </remarks>
154+
#if NET8_0_OR_GREATER
155+
[Experimental(DiagnosticDefinitions.ExemplarExperimentalApi, UrlFormat = DiagnosticDefinitions.ExperimentalApiUrlFormat)]
156+
#endif
157+
public Func<ExemplarReservoir?>? ExemplarReservoirFactory { get; set; }
158+
#else
142159
internal Func<ExemplarReservoir?>? ExemplarReservoirFactory { get; set; }
160+
#endif
143161

144162
internal string[]? CopiedTagKeys { get; private set; }
145163

0 commit comments

Comments
 (0)