# OpenTelemetry .NET SDK [![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.svg)](https://www.nuget.org/packages/OpenTelemetry) [![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.svg)](https://www.nuget.org/packages/OpenTelemetry)
Table of Contents * [Installation](#installation) * [Introduction](#introduction) * [Self-Observability (Experimental)](#self-observability-experimental) * [Troubleshooting](#troubleshooting) * [Self-diagnostics](#self-diagnostics) * [Configuration Parameters](#configuration-parameters) * [Remarks](#remarks) * [References](#references)
## Installation ```shell dotnet add package OpenTelemetry ``` ## Introduction OpenTelemetry SDK is a reference implementation of the OpenTelemetry API. It implements the Logging API, Metrics API, Tracing API, Resource API, and the Context API. Once a valid SDK is installed and configured all the OpenTelemetry API methods, which were no-ops without an SDK, will start emitting telemetry. This SDK also ships with [ILogger](https://learn.microsoft.com/dotnet/core/extensions/logging) integration to automatically capture and enrich logs emitted using `Microsoft.Extensions.Logging`. The SDK deals with concerns such as sampling, processing pipelines (exporting telemetry to a particular backend, etc.), metrics aggregation, and other concerns outlined in the [OpenTelemetry Specification](https://github.com/open-telemetry/opentelemetry-specification). In most cases, users indirectly install and enable the SDK when they install an exporter. To learn how to set up and configure the OpenTelemetry SDK see: [Getting started](../../README.md#getting-started). For additional details about initialization patterns see: [Initialize the SDK](../../docs/README.md#initialize-the-sdk). ## Self-Observability (Experimental) The SDK can emit metrics about its own internal operations, enabling operators to monitor the health of the telemetry pipeline itself (e.g., detecting dropped telemetry due to queue overflow). > [!NOTE] > Self-observability metrics are **experimental** and may change in future > releases. They are emitted under the meter name `otel.sdk.experimental`. ### Opt-in Self-observability metrics are only emitted when explicitly enabled by subscribing to the `otel.sdk.experimental` meter. There is no performance cost unless enabled. ```csharp var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter("otel.sdk.experimental") .AddOtlpExporter() // or any exporter .Build(); ``` ### Available Metrics These metrics follow the [OpenTelemetry SDK Self-Observability Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/otel/sdk-metrics/). | Metric Name | Instrument | Unit | Description | | --- | --- | --- | --- | | `otel.sdk.processor.log.processed` | Counter | `{log_record}` | Number of log records processed by the SDK, tagged with outcome. | | `otel.sdk.processor.span.processed` | Counter | `{span}` | Number of spans processed by the SDK, tagged with outcome. | ### Attributes | Attribute | Description | Example | | --- | --- | --- | | `otel.component.type` | The processor type. | `batching_log_processor`, `simple_log_processor`, `batching_span_processor`, `simple_span_processor` | | `otel.component.name` | Unique instance identifier. | `batching_log_processor/0`, `batching_span_processor/0` | | `error.type` | Present only on failure. | `queue_full`, `already_shutdown` | When `error.type` is absent, the item was successfully accepted by the processor. This means the processor completed its intended handling of the item; for the Simple and Batching processors it is recorded when the item is handed to the exporter, and it does **not** indicate that the export itself succeeded or that the item reached the backend. Export failures are not reflected in this metric. When present: * `queue_full` - The batch processor's internal queue was full; the item was dropped. * `already_shutdown` - The processor had already been shut down; the item was lost. > [!NOTE] > Sampling affects `otel.sdk.processor.span.processed` as follows. Spans dropped > by the sampler (`DROP`) are not counted, because span processors are not > invoked for them at all. Spans sampled as `RECORD_ONLY` are counted as > successfully processed because they do reach the processor and by design are > never handed to an exporter. ## Troubleshooting All the components shipped from this repo uses [EventSource](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventsource) for its internal logging. The name of the `EventSource` used by OpenTelemetry SDK is "OpenTelemetry-Sdk". To know the `EventSource` names used by other components, refer to the individual readme files. While it is possible to view these logs using tools such as [PerfView](https://github.com/microsoft/perfview), [dotnet-trace](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-trace) etc., this SDK also ships a [self-diagnostics](#self-diagnostics) feature, which helps with troubleshooting. ### Self-diagnostics OpenTelemetry SDK ships with built-in self-diagnostics feature. This feature, when enabled, will listen to internal logs generated by all OpenTelemetry components (i.e EventSources whose name starts with "OpenTelemetry-") and writes them to a log file. The self-diagnostics feature can be enabled/changed/disabled while the process is running (without restarting the process). The SDK will attempt to read the configuration file every `10` seconds in non-exclusive read-only mode. The SDK will create or overwrite a file with new logs according to the configuration. This file will not exceed the configured max size and will be overwritten in a circular way. To enable self-diagnostics, go to the [current working directory](https://en.wikipedia.org/wiki/Working_directory) of your process and create a configuration file named `OTEL_DIAGNOSTICS.json` with the following content: ```json { "LogDirectory": ".", "FileSize": 32768, "LogLevel": "Warning", "FormatMessage": "true" } ``` To disable self-diagnostics, delete the above file. Tip: In most cases, you could just drop the file along your application. On Windows, you can use [Process Explorer](https://docs.microsoft.com/sysinternals/downloads/process-explorer), double click on the process to pop up Properties dialog and find "Current directory" in "Image" tab. Internally, it looks for the configuration file located in [GetCurrentDirectory](https://docs.microsoft.com/dotnet/api/system.io.directory.getcurrentdirectory), and then [AppContext.BaseDirectory](https://docs.microsoft.com/dotnet/api/system.appcontext.basedirectory). You can also find the exact directory by calling these methods from your code. #### Configuration Parameters 1. `LogDirectory` is the directory where the output log file will be stored. It can be an absolute path or a relative path to the current directory. 2. `FileSize` is a positive integer, which specifies the log file size in [KiB](https://en.wikipedia.org/wiki/Kibibyte). This value must be within range `[1024, 131072]` (1 MiB \<= size \<= 128 MiB), or it will be rounded to the closest upper or lower limit. The log file will never exceed this configured size, and will be overwritten in a circular way. 3. `LogLevel` is the lowest level of the events to be captured. It has to be one of the [values](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventlevel#fields) of the [`EventLevel` enum](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventlevel). The level signifies the severity of an event. Lower severity levels encompass higher severity levels. For example, `Warning` includes the `Error` and `Critical` levels. 4. `FormatMessage` is a boolean value that controls whether log messages should be formatted by replacing placeholders (`{0}`, `{1}`, etc.) with their actual parameter values. When set to `false` (default), messages are logged with unformatted placeholders followed by raw parameter values. When set to `true`, placeholders are replaced with formatted parameter values for improved readability. **Example with `FormatMessage: false` (default):** ```txt 2025-07-24T01:45:04.1020880Z:Measurements from Instrument '{0}', Meter '{1}' will be ignored. Reason: '{2}'. Suggested action: '{3}'{dotnet.gc.collections}{System.Runtime}{Instrument belongs to a Meter not subscribed by the provider.}{Use AddMeter to add the Meter to the provider.} ``` **Example with `FormatMessage: true`:** ```txt 2025-07-24T01:44:44.7059260Z:Measurements from Instrument 'dotnet.gc.collections', Meter 'System.Runtime' will be ignored. Reason: 'Instrument belongs to a Meter not subscribed by the provider.'. Suggested action: 'Use AddMeter to add the Meter to the provider.' ``` #### Remarks A `FileSize`-KiB log file named as `ExecutableName.ProcessId.log` (e.g. `foobar.exe.12345.log`) will be generated at the specified directory `LogDirectory`, into which logs are written to. If the SDK fails to parse the `LogDirectory`, `FileSize` or `LogLevel` fields as the specified format, the configuration file will be treated as invalid and no log file would be generated. When the `LogDirectory` or `FileSize` is found to be changed, the SDK will create or overwrite a file with new logs according to the new configuration. The configuration file has to be no more than 4 KiB. In case the file is larger than 4 KiB, only the first 4 KiB of content will be read. The log file might not be a proper text file format to achieve the goal of having minimal overhead and bounded resource usage: it may have trailing `NUL`s if log text is less than configured size; once write operation reaches the end, it will start from beginning and overwrite existing text. ## References * [OpenTelemetry Logging SDK specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md) * [OpenTelemetry Metrics SDK specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md) * [OpenTelemetry Tracing SDK specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md) * [OpenTelemetry Resource SDK specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md)