|
| 1 | +--- |
| 2 | +title: Log sampling |
| 3 | +description: Learn how to fine-tune the volume of logs emitted by your application using log sampling. |
| 4 | +ms.date: 04/29/2025 |
| 5 | +--- |
| 6 | + |
| 7 | +# Log sampling in .NET |
| 8 | + |
| 9 | +.NET provides log sampling capabilities that allow you to control the volume of logs your application emits without losing important information. The following sampling strategies are available: |
| 10 | + |
| 11 | +- Trace-based sampling: Sample logs based on the sampling decision of the current trace. |
| 12 | +- Random probabilistic sampling: Sample logs based on configured probability rules. |
| 13 | +- Custom sampling: Implement your own custom sampling strategy. For more information, see [Implement custom sampling](#implement-custom-sampling). |
| 14 | + |
| 15 | +> [!NOTE] |
| 16 | +> Only one sampler can be used at a time. If you register multiple samplers, the last one is used. |
| 17 | +
|
| 18 | +Log sampling extends [filtering capabilities](logging.md#configure-logging-with-code) by giving you more fine-grained control over which logs are emitted by your application. Instead of simply enabling or disabling logs, you can configure sampling to emit only a fraction of them. |
| 19 | + |
| 20 | +For example, while filtering typically uses probabilities like `0` (emit no logs) or `1` (emit all logs), sampling lets you choose any value in between—such as `0.1` to emit 10% of logs, or `0.25` to emit 25%. |
| 21 | + |
| 22 | +## Get started |
| 23 | + |
| 24 | +To get started, install the [📦 Microsoft.Extensions.Telemetry](https://www.nuget.org/packages/Microsoft.Extensions.Telemetry) NuGet package: |
| 25 | + |
| 26 | +### [.NET CLI](#tab/dotnet-cli) |
| 27 | + |
| 28 | +```dotnetcli |
| 29 | +dotnet add package Microsoft.Extensions.Telemetry |
| 30 | +``` |
| 31 | + |
| 32 | +### [PackageReference](#tab/package-reference) |
| 33 | + |
| 34 | +```xml |
| 35 | +<ItemGroup> |
| 36 | + <PackageReference Include="Microsoft.Extensions.Telemetry" |
| 37 | + Version="*" /> |
| 38 | +</ItemGroup> |
| 39 | +``` |
| 40 | + |
| 41 | +--- |
| 42 | + |
| 43 | +For more information, see [dotnet add package](../tools/dotnet-package-add.md) or [Manage package dependencies in .NET applications](../tools/dependencies.md). |
| 44 | + |
| 45 | +## Configure trace-based sampling |
| 46 | + |
| 47 | +Trace-based sampling ensures that logs are sampled consistently with the underlying <xref:System.Diagnostics.Activity>. This is useful when you want to maintain correlation between traces and logs. You can enable trace sampling (as described in the [guide](../diagnostics/distributed-tracing-concepts.md#sampling)), and then configure trace-based log sampling accordingly: |
| 48 | + |
| 49 | +:::code language="csharp" source="snippets/logging/log-sampling/trace-based/Program.cs" range="20"::: |
| 50 | + |
| 51 | +When trace-based sampling is enabled, logs will only be emitted if the underlying <xref:System.Diagnostics.Activity> is sampled. The sampling decision comes from the current <xref:System.Diagnostics.Activity.Recorded> value. |
| 52 | + |
| 53 | +## Configure random probabilistic sampling |
| 54 | + |
| 55 | +Random probabilistic sampling allows you to sample logs based on configured probability rules. You can define rules specific to: |
| 56 | + |
| 57 | +- Log category |
| 58 | +- Log level |
| 59 | +- Event ID |
| 60 | + |
| 61 | +There are several ways to configure random probabilistic sampling with its rules: |
| 62 | + |
| 63 | +### File-based configuration |
| 64 | + |
| 65 | +Create a configuration section in your _appsettings.json_, for example: |
| 66 | + |
| 67 | +:::code language="json" source="snippets/logging/log-sampling/file-config/appsettings.json" ::: |
| 68 | + |
| 69 | +The preceding configuration: |
| 70 | + |
| 71 | +- Samples 10% of logs from categories starting with `System.` of all levels. |
| 72 | +- Samples 25% of logs from categories starting with `Microsoft.AspNetCore.` of the <xref:Microsoft.Extensions.Logging.LogLevel.Information?displayProperty=nameWithType>. |
| 73 | +- Samples 5% of logs with event ID 1001 of all categories and levels. |
| 74 | +- Samples 100% of all other logs. |
| 75 | + |
| 76 | +> [!IMPORTANT] |
| 77 | +> The <xref:Microsoft.Extensions.Diagnostics.Sampling.RandomProbabilisticSamplerFilterRule.Probability> value represents probability with values from 0 to 1. For example, 0.25 means 25% of logs will be sampled. 0 means no logs will be sampled, and 1 means all logs will be sampled. Those cases with 0 and 1 can be used to effectively disable or enable all logs for a specific rule. Probability cannot be less than 0 or greater than 1, and if this occurs in the application, an exception is thrown. |
| 78 | +
|
| 79 | +To register the sampler with the configuration, consider the following code: |
| 80 | + |
| 81 | +:::code language="csharp" source="snippets/logging/log-sampling/file-config/Program.cs" range="16"::: |
| 82 | + |
| 83 | +#### Change sampling rules in a running app |
| 84 | + |
| 85 | +Random probabilistic sampling supports runtime configuration updates via the <xref:Microsoft.Extensions.Options.IOptionsMonitor%601> interface. If you're using a configuration provider that supports reloads—such as the [File Configuration Provider](configuration-providers.md#file-configuration-provider)—you can update sampling rules at runtime without restarting the application. |
| 86 | + |
| 87 | +For example, you can start your application with the following _appsettings.json_, which effectively acts as a no-op: |
| 88 | + |
| 89 | +:::code language="json" source="snippets/logging/log-sampling/appsettings.noop.json" ::: |
| 90 | + |
| 91 | +While the app is running, you can update the _appsettings.json_ with the following configuration: |
| 92 | + |
| 93 | +:::code language="json" source="snippets/logging/log-sampling/appsettings.updated.json" ::: |
| 94 | + |
| 95 | +The new rules will be applied automatically, for instance, with the preceding configuration, 1% of logs with the <xref:Microsoft.Extensions.Logging.LogLevel.Information?displayProperty=nameWithType> are sampled. |
| 96 | + |
| 97 | +#### How sampling rules are applied |
| 98 | + |
| 99 | +The algorithm is very similar to [log filtering](logging.md#how-filtering-rules-are-applied), yet there are some differences. |
| 100 | + |
| 101 | +Log sampling rules evaluation is performed on each log record, however, there are performance optimizations in place, such as caching. The following algorithm is used for each log record for a given category: |
| 102 | + |
| 103 | +- Select rules with `LogLevel` equal to or higher than the log level of the logger. |
| 104 | +- Select rules with `EventId` not defined or defined and equal to the log event ID. |
| 105 | +- Select rules with longest matching category prefix. If no match is found, select all rules that don't specify a category. |
| 106 | +- If multiple rules are selected, take the **last** one. |
| 107 | +- If no rules are selected, sampling is not applied, e.g. the log record is emitted as usual. |
| 108 | + |
| 109 | +### Inline code configuration |
| 110 | + |
| 111 | +:::code language="csharp" source="snippets/logging/log-sampling/code-config/Program.cs" range="16-22"::: |
| 112 | + |
| 113 | +The preceding configuration: |
| 114 | + |
| 115 | +- Samples 5% of logs with event ID 1001 of all categories and levels. |
| 116 | +- Samples 100% of all other logs. |
| 117 | + |
| 118 | +### Simple probability configuration |
| 119 | + |
| 120 | +For basic scenarios, you can configure a single probability value that applies to all logs at or below a specified level: |
| 121 | + |
| 122 | +:::code language="csharp" source="snippets/logging/log-sampling/Program.cs" range="14-15"::: |
| 123 | + |
| 124 | +The code above registers the sampler which would sample 10% of <xref:Microsoft.Extensions.Logging.LogLevel.Warning> logs and 1% of <xref:Microsoft.Extensions.Logging.LogLevel.Information> (and below) logs. |
| 125 | +If the configuration did not have the rule for <xref:Microsoft.Extensions.Logging.LogLevel.Information>, it would have sampled 10% of <xref:Microsoft.Extensions.Logging.LogLevel.Warning> logs and all levels below, including <xref:Microsoft.Extensions.Logging.LogLevel.Information>. |
| 126 | + |
| 127 | +## Implement custom sampling |
| 128 | + |
| 129 | +You can create a custom sampling strategy by deriving from the <xref:Microsoft.Extensions.Logging.LoggingSampler> abstract class and overriding its abstract members. This allows you to tailor the sampling behavior to your specific requirements. For example, a custom sampler could: |
| 130 | + |
| 131 | +- Make sampling decisions based on the presence and value of specific key/value pairs in the log state. |
| 132 | +- Apply rate-limiting logic, such as emitting logs only if the number of logs within a predefined time interval stays below a certain threshold. |
| 133 | + |
| 134 | +To implement a custom sampler, follow these steps: |
| 135 | + |
| 136 | +1. Create a class that inherits from <xref:Microsoft.Extensions.Logging.LoggingSampler>. |
| 137 | +1. Override the <xref:Microsoft.Extensions.Logging.LoggingSampler.ShouldSample*?displayProperty=nameWithType> method to define your custom sampling logic. |
| 138 | +1. Register your custom sampler in the logging pipeline using the <xref:Microsoft.Extensions.Logging.SamplingLoggerBuilderExtensions.AddSampler%2A> extension method. |
| 139 | + |
| 140 | +For each log record that isn't filtered out, the <xref:Microsoft.Extensions.Logging.LoggingSampler.ShouldSample*?displayProperty=nameWithType> method is called exactly once. Its return value determines whether the log record should be emitted. |
| 141 | + |
| 142 | +## Performance considerations |
| 143 | + |
| 144 | +Log sampling is designed to reduce storage costs, with a trade-off of slightly increased CPU usage. If your application generates a high volume of logs that are expensive to store, sampling can help reduce that volume. When configured appropriately, sampling can lower storage costs without losing information that's critical for diagnosing incidents. |
| 145 | + |
| 146 | +For the built-in sampling, see the benchmarks [here](https://github.com/dotnet/extensions/blob/main/bench/Libraries/Microsoft.Extensions.Telemetry.PerformanceTests/README.md). |
| 147 | + |
| 148 | +## Log level guidance on when to use sampling |
| 149 | + |
| 150 | +| Log level | Recommendation | |
| 151 | +|--|--| |
| 152 | +| <xref:Microsoft.Extensions.Logging.LogLevel.Trace> | Don't apply sampling, because normally you disable these logs in production | |
| 153 | +| <xref:Microsoft.Extensions.Logging.LogLevel.Debug> | Don't apply sampling, because normally you disable these logs in production | |
| 154 | +| <xref:Microsoft.Extensions.Logging.LogLevel.Information> | Do apply sampling | |
| 155 | +| <xref:Microsoft.Extensions.Logging.LogLevel.Warning> | Consider applying sampling | |
| 156 | +| <xref:Microsoft.Extensions.Logging.LogLevel.Error> | Don't apply sampling | |
| 157 | +| <xref:Microsoft.Extensions.Logging.LogLevel.Critical> | Don't apply sampling | |
| 158 | + |
| 159 | +## Best practices |
| 160 | + |
| 161 | +- Begin with higher sampling rates and adjust them downwards as necessary. |
| 162 | +- Use category-based rules to target specific components. |
| 163 | +- If you're using distributed tracing, consider implementing trace-based sampling. |
| 164 | +- Monitor the effectiveness of your sampling rules collectively. |
| 165 | +- Find the right balance for your application—too low a sampling rate can reduce observability, while too high a rate can increase costs. |
| 166 | + |
| 167 | +## See also |
| 168 | + |
| 169 | +- [Logging in .NET](logging.md) |
| 170 | +- [High-performance logging in .NET](high-performance-logging.md) |
| 171 | +- [OpenTelemetry Tracing Sampling](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#sampling) |
0 commit comments