|
| 1 | +--- |
| 2 | +title: Troubleshooting |
| 3 | +description: Learn how to troubleshoot OpenTelemetry .NET |
| 4 | +weight: 100 |
| 5 | +cSpell:ignore: eventsource OTEL |
| 6 | +--- |
| 7 | + |
| 8 | +All the components shipped from the OpenTelemetry .NET repositories |
| 9 | +([opentelemetry-dotnet][] and [opentelemetry-dotnet-contrib][]) use |
| 10 | +[EventSource](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventsource) |
| 11 | +for internal logging. The name of the `EventSource` used by the OpenTelemetry |
| 12 | +SDK is "OpenTelemetry-Sdk". To know the `EventSource` names used by other |
| 13 | +components, refer to the individual component documentation. |
| 14 | + |
| 15 | +While it is possible to view these logs using tools such as |
| 16 | +[PerfView](https://github.com/microsoft/perfview) or |
| 17 | +[`dotnet-trace`][dotnet-trace], the SDK also ships with a self-diagnostics |
| 18 | +feature, which helps with troubleshooting. |
| 19 | + |
| 20 | +## Self-diagnostics |
| 21 | + |
| 22 | +OpenTelemetry SDK ships with built-in self-diagnostics feature. This feature, |
| 23 | +when enabled, listens to internal logs generated by all OpenTelemetry components |
| 24 | +(that is, EventSources whose name starts with "OpenTelemetry-") and writes them |
| 25 | +to a log file. |
| 26 | + |
| 27 | +The self-diagnostics feature can be enabled, changed, or disabled while the |
| 28 | +process is running (without restarting the process). The SDK attempts to read |
| 29 | +the configuration file every 10 seconds in non-exclusive read-only mode. The SDK |
| 30 | +creates or overwrites a file with new logs according to the configuration. This |
| 31 | +file doesn't exceed the configured max size and is overwritten in a circular |
| 32 | +way. |
| 33 | + |
| 34 | +To enable self-diagnostics, go to the |
| 35 | +[current working directory](https://en.wikipedia.org/wiki/Working_directory) of |
| 36 | +your process and create a configuration file named `OTEL_DIAGNOSTICS.json` with |
| 37 | +the following content: |
| 38 | + |
| 39 | +```json |
| 40 | +{ |
| 41 | + "LogDirectory": ".", |
| 42 | + "FileSize": 32768, |
| 43 | + "LogLevel": "Warning", |
| 44 | + "FormatMessage": "true" |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | +To disable self-diagnostics, delete the configuration file. |
| 49 | + |
| 50 | +{{% alert title="Tip" %}} |
| 51 | + |
| 52 | +In most cases, you can drop the file alongside your application. On Windows, you |
| 53 | +can use |
| 54 | +[Process Explorer](https://docs.microsoft.com/sysinternals/downloads/process-explorer), |
| 55 | +double-click on the process to open the Properties dialog, and find "Current |
| 56 | +directory" in the "Image" tab. |
| 57 | + |
| 58 | +Internally, the SDK looks for the configuration file located in |
| 59 | +[GetCurrentDirectory](https://docs.microsoft.com/dotnet/api/system.io.directory.getcurrentdirectory), |
| 60 | +and then |
| 61 | +[AppContext.BaseDirectory](https://docs.microsoft.com/dotnet/api/system.appcontext.basedirectory). |
| 62 | +You can also find the exact directory by calling these methods from your code. |
| 63 | + |
| 64 | +{{% /alert %}} |
| 65 | + |
| 66 | +### Configuration parameters |
| 67 | + |
| 68 | +The configuration file supports the following parameters: |
| 69 | + |
| 70 | +#### LogDirectory |
| 71 | + |
| 72 | +The directory where the output log file is stored. It can be an absolute path or |
| 73 | +a relative path to the current directory. |
| 74 | + |
| 75 | +#### FileSize |
| 76 | + |
| 77 | +A positive integer that specifies the log file size in |
| 78 | +[KiB](https://en.wikipedia.org/wiki/Kibibyte). This value must be within the |
| 79 | +range `[1024, 131072]` (1 MiB <= size <= 128 MiB), or it will be rounded to the |
| 80 | +closest upper or lower limit. The log file never exceeds this configured size |
| 81 | +and is overwritten in a circular way. |
| 82 | + |
| 83 | +#### LogLevel |
| 84 | + |
| 85 | +The lowest level of the events to be captured. It must be one of the |
| 86 | +[values](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventlevel#fields) |
| 87 | +of the |
| 88 | +[`EventLevel` enum](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventlevel). |
| 89 | +The level signifies the severity of an event. Lower severity levels encompass |
| 90 | +higher severity levels. For example, `Warning` includes the `Error` and |
| 91 | +`Critical` levels. |
| 92 | + |
| 93 | +#### FormatMessage |
| 94 | + |
| 95 | +A boolean value that controls whether log messages should be formatted by |
| 96 | +replacing placeholders (`{0}`, `{1}`, etc.) with their actual parameter values. |
| 97 | +When set to `false` (default), messages are logged with unformatted placeholders |
| 98 | +followed by raw parameter values. When set to `true`, placeholders are replaced |
| 99 | +with formatted parameter values for improved readability. |
| 100 | + |
| 101 | +**Example with `FormatMessage: false` (default):** |
| 102 | + |
| 103 | +```text |
| 104 | +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.} |
| 105 | +``` |
| 106 | + |
| 107 | +**Example with `FormatMessage: true`:** |
| 108 | + |
| 109 | +```text |
| 110 | +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.' |
| 111 | +``` |
| 112 | + |
| 113 | +### Remarks |
| 114 | + |
| 115 | +A log file named `ExecutableName.ProcessId.log` (for example, |
| 116 | +`myapp.exe.12345.log`) is generated at the specified `LogDirectory`, into which |
| 117 | +logs are written. |
| 118 | + |
| 119 | +If the SDK fails to parse the `LogDirectory`, `FileSize`, or `LogLevel` fields, |
| 120 | +the configuration file is treated as invalid and no log file is generated. |
| 121 | + |
| 122 | +When the `LogDirectory` or `FileSize` is changed, the SDK creates or overwrites |
| 123 | +a file with new logs according to the new configuration. The configuration file |
| 124 | +must be no more than 4 KiB. If the file is larger than 4 KiB, only the first 4 |
| 125 | +KiB of content is read. |
| 126 | + |
| 127 | +The log file might not be a proper text file format to achieve the goal of |
| 128 | +having minimal overhead and bounded resource usage: it might have trailing `NUL` |
| 129 | +characters if log text is less than configured size; once write operation |
| 130 | +reaches the end, it starts from the beginning and overwrites existing text. |
| 131 | + |
| 132 | +[dotnet-trace]: https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-trace |
| 133 | +[opentelemetry-dotnet]: https://github.com/open-telemetry/opentelemetry-dotnet |
| 134 | +[opentelemetry-dotnet-contrib]: |
| 135 | + https://github.com/open-telemetry/opentelemetry-dotnet-contrib |
0 commit comments