Skip to content

Commit

Permalink
Merge branch 'main' into vibankwa/otlp-retry-part1-client-refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
vishweshbankwar committed Feb 9, 2024
2 parents 52b20b0 + f6c31f3 commit a5ea051
Show file tree
Hide file tree
Showing 18 changed files with 219 additions and 262 deletions.
38 changes: 28 additions & 10 deletions docs/diagnostics/experimental-apis/OTEL1003.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,37 @@ Experimental APIs may be changed or removed in the future.

## Details

The OpenTelemetry Specification defines the
[cardinality limit](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#cardinality-limits)
of a metric can be set by the matching view.

From the specification:

> The cardinality limit for an aggregation is defined in one of three ways:
> A view with criteria matching the instrument an aggregation is created for has
> an aggregation_cardinality_limit value defined for the stream, that value
> SHOULD be used. If there is no matching view, but the MetricReader defines a
> default cardinality limit value based on the instrument an aggregation is
> created for, that value SHOULD be used. If none of the previous values are
> defined, the default value of 2000 SHOULD be used.
>
> 1. A view with criteria matching the instrument an aggregation is created for
> has an `aggregation_cardinality_limit` value defined for the stream, that
> value SHOULD be used.
> 2. If there is no matching view, but the `MetricReader` defines a default
> cardinality limit value based on the instrument an aggregation is created
> for, that value SHOULD be used.
> 3. If none of the previous values are defined, the default value of 2000
> SHOULD be used.
We are exposing these APIs experimentally until the specification declares them
stable.

### Setting cardinality limit for a specific Metric via the View API

The OpenTelemetry Specification defines the [cardinality
limit](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#cardinality-limits)
of a metric can be set by the matching view.

```csharp
using var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddView(
instrumentName: "MyFruitCounter",
new MetricStreamConfiguration { CardinalityLimit = 10 })
.Build();
```

### Setting cardinality limit for a specific MetricReader

[This is not currently supported by OpenTelemetry
.NET.](https://github.com/open-telemetry/opentelemetry-dotnet/issues/5331)
6 changes: 3 additions & 3 deletions docs/logs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ OpenTelemetry .NET:
:heavy_check_mark: You should use structured logging.

* Structured logging is more efficient than unstructured logging.
* Filtering and redaction can happen on invidual key-value pairs instead of
* Filtering and redaction can happen on individual key-value pairs instead of
the entire log message.
* Storage and indexing are more efficient.
* Structured logging makes it easier to manage and consume logs.
Expand Down Expand Up @@ -63,8 +63,8 @@ from the latest stable version of
[Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging/)
package, regardless of the .NET runtime version being used:

* If you're using the latest stable version of [OpenTelemetry .NET
SDK](../../src/OpenTelemetry/README.md), you don't have to worry about the
* If you are using the latest stable version of [OpenTelemetry .NET
SDK](../../src/OpenTelemetry/README.md), you do not have to worry about the
version of `Microsoft.Extensions.Logging` package because it is already taken
care of for you via [package dependency](../../Directory.Packages.props).
* Starting from version `3.1.0`, the .NET runtime team is holding a high bar for
Expand Down
54 changes: 28 additions & 26 deletions docs/metrics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

## Best Practices

The following tutorials have demonstrated the best practices for while using
metrics with OpenTelemetry .NET:
The following tutorials have demonstrated the best practices for using metrics
with OpenTelemetry .NET:

* [Getting Started - ASP.NET Core
Application](./getting-started-aspnetcore/README.md)
Expand All @@ -37,8 +37,8 @@ APIs from the latest stable version of
[System.Diagnostics.DiagnosticSource](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/)
package, regardless of the .NET runtime version being used:

* If you're using the latest stable version of [OpenTelemetry .NET
SDK](../../src/OpenTelemetry/README.md), you don't have to worry about the
* If you are using the latest stable version of [OpenTelemetry .NET
SDK](../../src/OpenTelemetry/README.md), you do not have to worry about the
version of `System.Diagnostics.DiagnosticSource` package because it is already
taken care of for you via [package
dependency](../../Directory.Packages.props).
Expand Down Expand Up @@ -163,9 +163,9 @@ Here is the rule of thumb:

> [!NOTE]
> When reporting measurements with more than 8 tags, the API allocates memory on
the hot-path. You SHOULD try to keep the number of tags less than or equal to 8.
If you are exceeding this, check if you can model some of the tags as Resource,
as [shown here](#metrics-enrichment).
the hot code path. You SHOULD try to keep the number of tags less than or
equal to 8. If you are exceeding this, check if you can model some of the tags
as Resource, as [shown here](#metrics-enrichment).

## MeterProvider Management

Expand Down Expand Up @@ -232,9 +232,9 @@ In OpenTelemetry,
[measurements](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#measurement)
are reported via the metrics API. The SDK
[aggregates](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#aggregation)
metrics using certain algorithm and memory management strategy to achieve good
performance and efficiency. Here are the rules which OpenTelemetry .NET follows
while implementing the metrics aggregation logic:
metrics using certain algorithms and memory management strategies to achieve
good performance and efficiency. Here are the rules which OpenTelemetry .NET
follows while implementing the metrics aggregation logic:

1. [**Pre-Aggregation**](#pre-aggregation): aggregation occurs within the SDK.
2. [**Cardinality Limits**](#cardinality-limits): the aggregation logic respects
Expand All @@ -249,7 +249,7 @@ while implementing the metrics aggregation logic:

### Example

Let's take the following example:
Let us take the following example:

* During the time range (T0, T1]:
* value = 1, name = `apple`, color = `red`
Expand Down Expand Up @@ -285,7 +285,7 @@ Temporality](https://github.com/open-telemetry/opentelemetry-specification/blob/
* attributes: {name = `apple`, color = `red`}, count: `1`
* attributes: {verb = `lemon`, color = `yellow`}, count: `2`
* (T1, T2]
* nothing since we don't have any measurement received
* nothing since we do not have any measurement received
* (T2, T3]
* attributes: {name = `apple`, color = `red`}, count: `5`
* attributes: {name = `apple`, color = `green`}, count: `2`
Expand All @@ -294,8 +294,8 @@ Temporality](https://github.com/open-telemetry/opentelemetry-specification/blob/
### Pre-Aggregation

Taking the [fruit example](#example), there are 6 measurements reported during
`(T2, T3]`. Instead of exporting every individual measurement events, the SDK
aggregates them and only export the summarized results. This approach, as
`(T2, T3]`. Instead of exporting every individual measurement event, the SDK
aggregates them and only exports the summarized results. This approach, as
illustrated in the following diagram, is called pre-aggregation:

```mermaid
Expand All @@ -312,7 +312,7 @@ end
Pre-Aggregation --> | Metrics | Aggregation
```

Pre-aggregation brings serveral benefits:
Pre-aggregation brings several benefits:

1. Although the amount of calculation remains the same, the amount of data
transmitted can be significantly reduced using pre-aggregation, thus
Expand Down Expand Up @@ -364,12 +364,12 @@ table to summarize the total number of fruits based on the name and color.
In other words, we know how much storage and network are needed to collect and
transmit these metrics, regardless of the traffic pattern.

In real world applications, the cardinality can be very high. Imagine if we have
a long running service and we collect metrics with 7 attributes and each
In real world applications, the cardinality can be extremely high. Imagine if we
have a long running service and we collect metrics with 7 attributes and each
attribute can have 30 different values. We might eventually end up having to
remember the complete set of all 21,870,000,000 combinations! This cardinality
explosion is a well-known challenge in the metrics space. For example, it can
cause surprisingly high cost in the observability system, or even be leveraged
cause surprisingly high costs in the observability system, or even be leveraged
by hackers to launch a denial-of-service attack.

[Cardinality
Expand All @@ -379,17 +379,19 @@ predictable and reliable behavior when excessive cardinality happens, whether it
was due to a malicious attack or developer making mistakes while writing code.

OpenTelemetry has a default cardinality limit of `2000` per metric. This limit
can be configured at `MeterProvider` level using the
`SetMaxMetricPointsPerMetricStream` method, or at individual
[view](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#view)
level using `MetricStreamConfiguration.CardinalityLimit`. Refer to this
[doc](../../docs/metrics/customizing-the-sdk/README.md#changing-maximum-metricpoints-per-metricstream)
can be configured at the individual metric level using the [View
API](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#view)
and the `MetricStreamConfiguration.CardinalityLimit` setting. Refer to this
[doc](../../docs/metrics/customizing-the-sdk/README.md#changing-the-cardinality-limit-for-a-metric)
for more information.

Given a metric, once the cardinality limit is reached, any new measurement which
cannot be independently aggregated because of the limit will be aggregated using
the [overflow
attribute](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#overflow-attribute).
cannot be independently aggregated because of the limit will be dropped or
aggregated using the [overflow
attribute](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#overflow-attribute)
(if enabled). When NOT using the overflow attribute feature a warning is written
to the [self-diagnostic log](../../src/OpenTelemetry/README.md#self-diagnostics)
the first time an overflow is detected for a given metric.

> [!NOTE]
> Overflow attribute was introduced in OpenTelemetry .NET
Expand Down
88 changes: 11 additions & 77 deletions docs/metrics/customizing-the-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,90 +367,24 @@ MyFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
AnotherFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
```

### Changing maximum MetricPoints per MetricStream
### Changing the cardinality limit for a Metric

A Metric stream can contain as many Metric points as the number of unique
combination of keys and values. To protect the SDK from unbounded memory usage,
SDK limits the maximum number of metric points per metric stream, to a default
of 2000. Once the limit is hit, any new key/value combination for that metric is
ignored. The SDK chooses the key/value combinations in the order in which they
are emitted. `SetMaxMetricPointsPerMetricStream` can be used to override the
default.
To set the [cardinality limit](../README.md#cardinality-limits) for an
individual metric, use `MetricStreamConfiguration.CardinalityLimit` setting on
the View API:

> [!NOTE]
> One `MetricPoint` is reserved for every `MetricStream` for the
special case where there is no key/value pair associated with the metric. The
maximum number of `MetricPoint`s has to accommodate for this special case.

Consider the below example. Here we set the maximum number of `MetricPoint`s
allowed to be `3`. This means that for every `MetricStream`, the SDK will export
measurements for up to `3` distinct key/value combinations of the metric. There
are two instruments published here: `MyFruitCounter` and `AnotherFruitCounter`.
There are two total `MetricStream`s created one for each of these instruments.
SDK will limit the maximum number of distinct key/value combinations for each of
these `MetricStream`s to `3`.

```csharp
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using OpenTelemetry;
using OpenTelemetry.Metrics;

Counter<long> MyFruitCounter = MyMeter.CreateCounter<long>("MyFruitCounter");
Counter<long> AnotherFruitCounter = MyMeter.CreateCounter<long>("AnotherFruitCounter");

using var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("*")
.AddConsoleExporter()
.SetMaxMetricPointsPerMetricStream(3) // The default value is 2000
.Build();

// There are four distinct key/value combinations emitted for `MyFruitCounter`:
// 1. No key/value pair
// 2. (name:apple, color:red)
// 3. (name:lemon, color:yellow)
// 4. (name:apple, color:green)
// Since the maximum number of `MetricPoint`s allowed is `3`, the SDK will only export measurements for the following three combinations:
// 1. No key/value pair
// 2. (name:apple, color:red)
// 3. (name:lemon, color:yellow)
MyFruitCounter.Add(1); // Exported (No key/value pair)
MyFruitCounter.Add(1, new("name", "apple"), new("color", "red")); // Exported
MyFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow")); // Exported
MyFruitCounter.Add(1, new("name", "lemon"), new("color", "yellow")); // Exported
MyFruitCounter.Add(2, new("name", "apple"), new("color", "green")); // Not exported
MyFruitCounter.Add(5, new("name", "apple"), new("color", "red")); // Exported
MyFruitCounter.Add(4, new("name", "lemon"), new("color", "yellow")); // Exported
// There are four distinct key/value combinations emitted for `AnotherFruitCounter`:
// 1. (name:kiwi)
// 2. (name:banana, color:yellow)
// 3. (name:mango, color:yellow)
// 4. (name:banana, color:green)
// Since the maximum number of `MetricPoint`s allowed is `3`, the SDK will only export measurements for the following three combinations:
// 1. No key/value pair (This is a special case. The SDK reserves a `MetricPoint` for it even if it's not explicitly emitted.)
// 2. (name:kiwi)
// 3. (name:banana, color:yellow)
AnotherFruitCounter.Add(4, new KeyValuePair<string, object>("name", "kiwi")); // Exported
AnotherFruitCounter.Add(1, new("name", "banana"), new("color", "yellow")); // Exported
AnotherFruitCounter.Add(2, new("name", "mango"), new("color", "yellow")); // Not exported
AnotherFruitCounter.Add(1, new("name", "mango"), new("color", "yellow")); // Not exported
AnotherFruitCounter.Add(2, new("name", "banana"), new("color", "green")); // Not exported
AnotherFruitCounter.Add(5, new("name", "banana"), new("color", "yellow")); // Exported
AnotherFruitCounter.Add(4, new("name", "mango"), new("color", "yellow")); // Not exported
```

To set the [cardinality limit](../README.md#cardinality-limits) at individual
metric level, use `MetricStreamConfiguration.CardinalityLimit`:
> `MetricStreamConfiguration.CardinalityLimit` is an experimental API only
available in pre-release builds. For details see:
[OTEL1003](../../diagnostics/experimental-apis/OTEL1003.md).

```csharp
var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("MyCompany.MyProduct.MyLibrary")
.AddView(instrumentName: "MyFruitCounter", new MetricStreamConfiguration { CardinalityLimit = 10 })
// Set a custom CardinalityLimit (10) for "MyFruitCounter"
.AddView(
instrumentName: "MyFruitCounter",
new MetricStreamConfiguration { CardinalityLimit = 10 })
.AddConsoleExporter()
.Build();
```
Expand Down
17 changes: 8 additions & 9 deletions docs/trace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

## Best Practices

The following tutorials have demonstrated the best practices for while using
traces with OpenTelemetry .NET:
The following tutorials have demonstrated the best practices for using traces
with OpenTelemetry .NET:

* [Getting Started - ASP.NET Core
Application](./getting-started-aspnetcore/README.md)
Expand All @@ -32,8 +32,8 @@ APIs from the latest stable version of
[System.Diagnostics.DiagnosticSource](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/)
package, regardless of the .NET runtime version being used:

* If you're using the latest stable version of [OpenTelemetry .NET
SDK](../../src/OpenTelemetry/README.md), you don't have to worry about the
* If you are using the latest stable version of [OpenTelemetry .NET
SDK](../../src/OpenTelemetry/README.md), you do not have to worry about the
version of `System.Diagnostics.DiagnosticSource` package because it is already
taken care of for you via [package
dependency](../../Directory.Packages.props).
Expand Down Expand Up @@ -150,10 +150,9 @@ information, as opposed to creating a new one.
### Modelling static tags as Resource

Tags such as `MachineName`, `Environment` etc. which are static throughout the
process lifetime should be be modelled as `Resource`, instead of adding them
to each `Activity`. Refer to this
[doc](./customizing-the-sdk/README.md#resource) for details and
examples.
process lifetime should be modelled as `Resource`, instead of adding them to
each `Activity`. Refer to this [doc](./customizing-the-sdk/README.md#resource)
for details and examples.

## Common issues that lead to missing traces

Expand All @@ -166,7 +165,7 @@ examples.
and is disposed of at application shutdown. For an ASP.NET Core application,
use `AddOpenTelemetry` and `WithTraces` methods from the
`OpenTelemetry.Extensions.Hosting` package to correctly setup
`TracerProvider`. Here's a [sample ASP.NET Core
`TracerProvider`. Here is a [sample ASP.NET Core
app](../../examples/AspNetCore/Program.cs) for reference. For simpler
applications such as Console apps, refer to this
[example](../../docs/trace/getting-started-console/Program.cs).
Expand Down
8 changes: 6 additions & 2 deletions src/OpenTelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@

* **Experimental (pre-release builds only):** Added support for setting
`CardinalityLimit` (the maximum number of data points allowed for a metric)
when configuring a view.
([#5312](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5312))
when configuring a view (applies to individual metrics) and obsoleted
`MeterProviderBuilderExtensions.SetMaxMetricPointsPerMetricStream` (previously
applied to all metrics). The default cardinality limit for metrics remains at
`2000`.
([#5312](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5312),
[#5328](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5328))

* Updated `LogRecord` to keep `CategoryName` and `Logger` in sync when using the
experimental Log Bridge API.
Expand Down
Loading

0 comments on commit a5ea051

Please sign in to comment.