[docs-metrics] Customer ExemplarReservoir and View API configuration (#5624)
This commit is contained in:
parent
16f2bf0fb9
commit
2abf2a9e71
|
|
@ -54,9 +54,9 @@ We are exposing these APIs experimentally for the following reasons:
|
|||
**TL;DR** We want to gather feedback on the usability of the API and for the
|
||||
need(s) in general for custom reservoirs before exposing a stable API.
|
||||
|
||||
<!--
|
||||
## Provide feedback
|
||||
|
||||
Please provide feedback on [this issue](TODO) if you need stable support for
|
||||
custom `ExemplarReservoir`s.
|
||||
-->
|
||||
Please provide feedback on [this
|
||||
issue](https://github.com/open-telemetry/opentelemetry-dotnet/issues/5629) if
|
||||
you need stable support for custom `ExemplarReservoir`s. The feedback will help
|
||||
inform decisions about what to expose stable and when.
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ within the maximum number of buckets defined by `MaxSize`. The default
|
|||
`MaxSize` is 160 buckets and the default `MaxScale` is 20.
|
||||
|
||||
```csharp
|
||||
// Change the maximum number of buckets
|
||||
// Change the maximum number of buckets for "MyHistogram"
|
||||
.AddView(
|
||||
instrumentName: "MyHistogram",
|
||||
new Base2ExponentialBucketHistogramConfiguration { MaxSize = 40 })
|
||||
|
|
@ -251,6 +251,28 @@ by using Views.
|
|||
|
||||
See [Program.cs](./Program.cs) for a complete example.
|
||||
|
||||
#### Change the ExemplarReservoir
|
||||
|
||||
> [!NOTE]
|
||||
> `MetricStreamConfiguration.ExemplarReservoirFactory` is an experimental API only
|
||||
available in pre-release builds. For details see:
|
||||
[OTEL1004](../../diagnostics/experimental-apis/OTEL1004.md).
|
||||
|
||||
To set the [ExemplarReservoir](#exemplarreservoir) for an instrument, use the
|
||||
`MetricStreamConfiguration.ExemplarReservoirFactory` property on the View API:
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Setting `MetricStreamConfiguration.ExemplarReservoirFactory` alone will NOT
|
||||
enable `Exemplar`s for an instrument. An [ExemplarFilter](#exemplarfilter)
|
||||
MUST also be used.
|
||||
|
||||
```csharp
|
||||
// Use MyCustomExemplarReservoir for "MyFruitCounter"
|
||||
.AddView(
|
||||
instrumentName: "MyFruitCounter",
|
||||
new MetricStreamConfiguration { ExemplarReservoirFactory = () => new MyCustomExemplarReservoir() })
|
||||
```
|
||||
|
||||
### Changing maximum Metric Streams
|
||||
|
||||
Every instrument results in the creation of a single Metric stream. With Views,
|
||||
|
|
@ -421,20 +443,24 @@ and is responsible for recording `Exemplar`s. The following are the default
|
|||
reservoirs:
|
||||
|
||||
* `AlignedHistogramBucketExemplarReservoir` is the default reservoir used for
|
||||
Histograms with buckets, and it stores at most one exemplar per histogram
|
||||
bucket. The exemplar stored is the last measurement recorded - i.e. any new
|
||||
Histograms with buckets, and it stores at most one `Exemplar` per histogram
|
||||
bucket. The `Exemplar` stored is the last measurement recorded - i.e. any new
|
||||
measurement overwrites the previous one in that bucket.
|
||||
|
||||
* `SimpleFixedSizeExemplarReservoir` is the default reservoir used for all
|
||||
metrics except Histograms with buckets. It has a fixed reservoir pool, and
|
||||
metrics except histograms with buckets. It has a fixed reservoir pool, and
|
||||
implements the equivalent of [naive
|
||||
reservoir](https://en.wikipedia.org/wiki/Reservoir_sampling). The reservoir pool
|
||||
size (currently defaulting to 1) determines the maximum number of exemplars
|
||||
size (currently defaulting to 1) determines the maximum number of `Exemplar`s
|
||||
stored. Exponential histograms use a `SimpleFixedSizeExemplarReservoir` with a
|
||||
pool size equal to the number of buckets up to a max of `20`.
|
||||
|
||||
> [!NOTE]
|
||||
> Currently there is no ability to change or configure `ExemplarReservoir`.
|
||||
See [Change the ExemplarReservoir](#change-the-exemplarreservoir) for details on
|
||||
how to use the View API to change `ExemplarReservoir`s for an instrument.
|
||||
|
||||
See [Building your own
|
||||
ExemplarReservoir](../extending-the-sdk/README.md#exemplarreservoir) for details
|
||||
on how to implement custom `ExemplarReservoir`s.
|
||||
|
||||
### Instrumentation
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
* [Building your own exporter](#exporter)
|
||||
* [Building your own reader](#reader)
|
||||
* [Building your own exemplar filter](#exemplarfilter)
|
||||
* [Building your own exemplar reservoir](#exemplarreservoir)
|
||||
* [Building your own resource detector](../../resources/README.md#resource-detector)
|
||||
* [References](#references)
|
||||
|
|
@ -72,12 +71,103 @@ to the `MeterProvider` as shown in the example [here](./Program.cs).
|
|||
|
||||
Not supported.
|
||||
|
||||
## ExemplarFilter
|
||||
|
||||
Not supported.
|
||||
|
||||
## ExemplarReservoir
|
||||
|
||||
Not supported.
|
||||
> [!NOTE]
|
||||
> `ExemplarReservoir` is an experimental API only available in pre-release
|
||||
builds. For details see:
|
||||
[OTEL1004](../../diagnostics/experimental-apis/OTEL1004.md). Please [provide
|
||||
feedback](https://github.com/open-telemetry/opentelemetry-dotnet/issues/5629)
|
||||
to help inform decisions about what should be exposed stable and when.
|
||||
|
||||
Custom [ExemplarReservoir](../customizing-the-sdk/README.md#exemplarreservoir)s
|
||||
can be implemented to control how `Exemplar`s are recorded for a metric:
|
||||
|
||||
* `ExemplarReservoir`s should derive from `FixedSizeExemplarReservoir` (which
|
||||
belongs to the [OpenTelemetry](../../../src/OpenTelemetry/README.md) package)
|
||||
and implement the `Offer` methods.
|
||||
* The `FixedSizeExemplarReservoir` constructor accepts a `capacity` parameter to
|
||||
control the number of `Exemplar`s which may be recorded by the
|
||||
`ExemplarReservoir`.
|
||||
* The `virtual` `OnCollected` method is called after the `ExemplarReservoir`
|
||||
collection operation has completed and may be used to implement cleanup or
|
||||
reset logic.
|
||||
* The `bool` `ResetOnCollect` property on `ExemplarReservoir` is set to `true`
|
||||
when delta aggregation temporality is used for the metric using the
|
||||
`ExemplarReservoir`.
|
||||
* The `Offer` and `Collect` `ExemplarReservoir` methods are called concurrently
|
||||
by the OpenTelemetry SDK. As such any state required by custom
|
||||
`ExemplarReservoir` implementations needs to be managed using appropriate
|
||||
thread-safety/concurrency mechanisms (`lock`, `Interlocked`, etc.).
|
||||
* Custom `ExemplarReservoir` implementations MUST NOT throw exceptions.
|
||||
Exceptions thrown in custom implementations MAY lead to unreleased locks and
|
||||
undefined behaviors.
|
||||
|
||||
The following example demonstrates a custom `ExemplarReservoir` implementation
|
||||
which records `Exemplar`s for measurements which have the highest value. When
|
||||
delta aggregation temporality is used the recorded `Exemplar` will be the
|
||||
highest value for a given collection cycle. When cumulative aggregation
|
||||
temporality is used the recorded `Exemplar` will be the highest value for the
|
||||
lifetime of the process.
|
||||
|
||||
```csharp
|
||||
class HighestValueExemplarReservoir : FixedSizeExemplarReservoir
|
||||
{
|
||||
private readonly object lockObject = new();
|
||||
private long? previousValueLong;
|
||||
private double? previousValueDouble;
|
||||
|
||||
public HighestValueExemplarReservoir()
|
||||
: base(capacity: 1)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Offer(in ExemplarMeasurement<long> measurement)
|
||||
{
|
||||
if (!this.previousValueLong.HasValue || measurement.Value > this.previousValueLong.Value)
|
||||
{
|
||||
lock (this.lockObject)
|
||||
{
|
||||
if (!this.previousValueLong.HasValue || measurement.Value > this.previousValueLong.Value)
|
||||
{
|
||||
this.UpdateExemplar(0, in measurement);
|
||||
this.previousValueLong = measurement.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Offer(in ExemplarMeasurement<double> measurement)
|
||||
{
|
||||
if (!this.previousValueDouble.HasValue || measurement.Value > this.previousValueDouble.Value)
|
||||
{
|
||||
lock (this.lockObject)
|
||||
{
|
||||
if (!this.previousValueDouble.HasValue || measurement.Value > this.previousValueDouble.Value)
|
||||
{
|
||||
this.UpdateExemplar(0, in measurement);
|
||||
this.previousValueDouble = measurement.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnCollected()
|
||||
{
|
||||
if (this.ResetOnCollect)
|
||||
{
|
||||
lock (this.lockObject)
|
||||
{
|
||||
this.previousValueLong = null;
|
||||
this.previousValueDouble = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Custom [ExemplarReservoir](../customizing-the-sdk/README.md#exemplarreservoir)s
|
||||
can be configured using the View API. For details see: [Change the
|
||||
ExemplarReservoir](../customizing-the-sdk/README.md#change-the-exemplarreservoir).
|
||||
|
||||
## References
|
||||
|
|
|
|||
Loading…
Reference in New Issue