diff --git a/Samples.sln b/Samples.sln
index 8e7c6297..1130b64c 100644
--- a/Samples.sln
+++ b/Samples.sln
@@ -55,6 +55,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compliance", "Compliance",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuditReports", "src\Compliance\AuditReports\AuditReports.csproj", "{9B5FB8C7-27BA-4397-B4B8-DD0B0D525CB2}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogSampling", "src\Telemetry\Logging\LogSampling\LogSampling.csproj", "{1A8652E7-EA1D-49AF-98B3-56D655F759B6}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -93,6 +95,10 @@ Global
{9B5FB8C7-27BA-4397-B4B8-DD0B0D525CB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B5FB8C7-27BA-4397-B4B8-DD0B0D525CB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B5FB8C7-27BA-4397-B4B8-DD0B0D525CB2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1A8652E7-EA1D-49AF-98B3-56D655F759B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1A8652E7-EA1D-49AF-98B3-56D655F759B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1A8652E7-EA1D-49AF-98B3-56D655F759B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1A8652E7-EA1D-49AF-98B3-56D655F759B6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -116,6 +122,7 @@ Global
{931A6585-1085-4185-AE12-78BBA87F2A73} = {175F98E5-AFE8-4978-A512-EB84AD660208}
{C42F13CB-E8D9-4A37-BFCC-A50458509D69} = {301296EC-54FF-4ADC-B2D1-281E0C7F2867}
{9B5FB8C7-27BA-4397-B4B8-DD0B0D525CB2} = {C42F13CB-E8D9-4A37-BFCC-A50458509D69}
+ {1A8652E7-EA1D-49AF-98B3-56D655F759B6} = {248CB37C-2412-4231-96C0-092413C10D4B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6083D400-BF26-4ACE-86A8-778D26A8FA6A}
diff --git a/src/Telemetry/Logging/LogSampling/Log.cs b/src/Telemetry/Logging/LogSampling/Log.cs
new file mode 100644
index 00000000..90c37a3b
--- /dev/null
+++ b/src/Telemetry/Logging/LogSampling/Log.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Extensions.Logging;
+
+namespace LogSampling;
+
+internal static partial class Log
+{
+ [LoggerMessage(Level = LogLevel.Error, Message = "ERROR log message in my application.")]
+ public static partial void ErrorMessage(ILogger logger);
+
+ [LoggerMessage(Level = LogLevel.Information, Message = "INFORMATION log message in my application.")]
+ public static partial void InformationMessage(ILogger logger);
+
+}
diff --git a/src/Telemetry/Logging/LogSampling/LogSampling.csproj b/src/Telemetry/Logging/LogSampling/LogSampling.csproj
new file mode 100644
index 00000000..143395db
--- /dev/null
+++ b/src/Telemetry/Logging/LogSampling/LogSampling.csproj
@@ -0,0 +1,21 @@
+
+
+
+ Demonstrates how to use log sampling feature.
+ Exe
+ $(NoWarn);EXTEXP0003
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/src/Telemetry/Logging/LogSampling/Program.cs b/src/Telemetry/Logging/LogSampling/Program.cs
new file mode 100644
index 00000000..310b9f48
--- /dev/null
+++ b/src/Telemetry/Logging/LogSampling/Program.cs
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Threading;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace LogSampling;
+
+internal static class Program
+{
+ public static void Main()
+ {
+ var hostBuilder = Host.CreateApplicationBuilder();
+ hostBuilder.Logging.AddSimpleConsole(options =>
+ {
+ options.SingleLine = true;
+ options.TimestampFormat = "hh:mm:ss";
+ });
+
+ // Add the Random probabilistic sampler to the logging pipeline.
+ hostBuilder.Logging.AddRandomProbabilisticSampler(hostBuilder.Configuration);
+
+ var app = hostBuilder.Build();
+ var loggerFactory = app.Services.GetRequiredService();
+ var logger = loggerFactory.CreateLogger("SamplingDemo");
+
+ // Simulate a prod application with many log messages generated:
+ while (true)
+ {
+ Log.ErrorMessage(logger);
+
+ for (int i = 0; i < 10; i++)
+ {
+ Log.InformationMessage(logger);
+ Thread.Sleep(300);
+ }
+ }
+ }
+}
diff --git a/src/Telemetry/Logging/LogSampling/README.md b/src/Telemetry/Logging/LogSampling/README.md
new file mode 100644
index 00000000..d6f82dde
--- /dev/null
+++ b/src/Telemetry/Logging/LogSampling/README.md
@@ -0,0 +1,20 @@
+# Log Sampling
+
+This sample shows how to use
+[log sampling](https://github.com/dotnet/extensions/blob/main/src/Libraries/Microsoft.Extensions.Telemetry/README.md).
+Log Sampling allows logs to be sampled, e.g. only some share of all log messages will be emitted.
+
+The sample uses a typical `HostApplicationBuilder` pattern to configure a small console application with
+logging. Log sampling is enabled by calling `.AddRandomProbabilisticSampler()` on the logging builder
+and
+providing a configuration via `appsettings.json`.
+
+The configuration in `appsettings.json` is flexible - you can configure specific sampling rates per
+any combination of
+- log level
+- category name
+- event id
+
+And, importantly, the configuration supports dynamic runtime updates via the `IOptionsMonitor` pattern.
+So you can change the `appsettings.json` (in the `/artifacts/bin/LogSampling/Debug` folder) at runtime
+and the changes will be picked up by the Log sampling.
diff --git a/src/Telemetry/Logging/LogSampling/appsettings.json b/src/Telemetry/Logging/LogSampling/appsettings.json
new file mode 100644
index 00000000..3467ad32
--- /dev/null
+++ b/src/Telemetry/Logging/LogSampling/appsettings.json
@@ -0,0 +1,20 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information"
+ }
+ },
+
+ "RandomProbabilisticSampler": {
+ "Rules": [
+ {
+ "LogLevel": "Information",
+ "Probability": 1
+ },
+ {
+ "LogLevel": "Error",
+ "Probability": 1
+ }
+ ]
+ }
+}