diff --git a/customer-samples/AutomaticTraceIdInjection/Log4NetExample/Log4NetExample.csproj b/customer-samples/AutomaticTraceIdInjection/Log4NetExample/Log4NetExample.csproj new file mode 100644 index 000000000000..3e70bc0b16fd --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/Log4NetExample/Log4NetExample.csproj @@ -0,0 +1,20 @@ + + + + Exe + netcoreapp2.1 + + + + + + + + + + + PreserveNewest + + + + \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/Log4NetExample/Program.cs b/customer-samples/AutomaticTraceIdInjection/Log4NetExample/Program.cs new file mode 100644 index 000000000000..89fb892ed0cb --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/Log4NetExample/Program.cs @@ -0,0 +1,34 @@ +using System.IO; +using Datadog.Trace; +using log4net; +using log4net.Config; + +namespace Log4NetExample +{ + class Program + { + private static readonly ILog log = LogManager.GetLogger(typeof(Program)); + + static void Main(string[] args) + { + var logRepository = LogManager.GetRepository(typeof(Program).Assembly); + XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config")); + + try + { + LogicalThreadContext.Properties["order-number"] = 1024; + log.Info("Message before a trace."); + using (var scope = Tracer.Instance.StartActive("Log4NetExample - Main()")) + { + log.Info("Message during a trace."); + } + } + finally + { + LogicalThreadContext.Properties.Remove("order-number"); + } + + log.Info("Message after a trace."); + } + } +} diff --git a/customer-samples/AutomaticTraceIdInjection/Log4NetExample/Properties/launchSettings.json b/customer-samples/AutomaticTraceIdInjection/Log4NetExample/Properties/launchSettings.json new file mode 100644 index 000000000000..dbc3a69e3d8e --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/Log4NetExample/Properties/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "Log4NetExample": { + "commandName": "Project", + "environmentVariables": { + "DD_LOGS_INJECTION": "true" + }, + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/Log4NetExample/log4net.config b/customer-samples/AutomaticTraceIdInjection/Log4NetExample/log4net.config new file mode 100644 index 000000000000..55ea4f60d422 --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/Log4NetExample/log4net.config @@ -0,0 +1,80 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/NLog45Example/NLog.config b/customer-samples/AutomaticTraceIdInjection/NLog45Example/NLog.config new file mode 100644 index 000000000000..8902dab86bff --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/NLog45Example/NLog.config @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/NLog45Example/NLog45Example.csproj b/customer-samples/AutomaticTraceIdInjection/NLog45Example/NLog45Example.csproj new file mode 100644 index 000000000000..6809fd87ff6d --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/NLog45Example/NLog45Example.csproj @@ -0,0 +1,19 @@ + + + + Exe + netcoreapp2.1 + + + + + + + + + + PreserveNewest + + + + \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/NLog45Example/Program.cs b/customer-samples/AutomaticTraceIdInjection/NLog45Example/Program.cs new file mode 100644 index 000000000000..f73e0c4b55a3 --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/NLog45Example/Program.cs @@ -0,0 +1,25 @@ +using Datadog.Trace; +using NLog; + +namespace NLog45Example +{ + class Program + { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + static void Main(string[] args) + { + using (MappedDiagnosticsLogicalContext.SetScoped("order-number", 1024)) + { + Logger.Info("Message before a trace."); + + using (var scope = Tracer.Instance.StartActive("NLog45Example - Main()")) + { + Logger.Info("Message during a trace."); + } + + Logger.Info("Message after a trace."); + } + } + } +} diff --git a/customer-samples/AutomaticTraceIdInjection/NLog45Example/Properties/launchSettings.json b/customer-samples/AutomaticTraceIdInjection/NLog45Example/Properties/launchSettings.json new file mode 100644 index 000000000000..3d9206d93e00 --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/NLog45Example/Properties/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "NLog45Example": { + "commandName": "Project", + "environmentVariables": { + "DD_LOGS_INJECTION": "true" + }, + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/NLog46Example/NLog.config b/customer-samples/AutomaticTraceIdInjection/NLog46Example/NLog.config new file mode 100644 index 000000000000..949f3e82efa6 --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/NLog46Example/NLog.config @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/NLog46Example/NLog46Example.csproj b/customer-samples/AutomaticTraceIdInjection/NLog46Example/NLog46Example.csproj new file mode 100644 index 000000000000..1ab72a92facc --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/NLog46Example/NLog46Example.csproj @@ -0,0 +1,19 @@ + + + + Exe + netcoreapp2.1 + + + + + + + + + + PreserveNewest + + + + \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/NLog46Example/Program.cs b/customer-samples/AutomaticTraceIdInjection/NLog46Example/Program.cs new file mode 100644 index 000000000000..f682d98dc3bf --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/NLog46Example/Program.cs @@ -0,0 +1,25 @@ +using Datadog.Trace; +using NLog; + +namespace NLog46Example +{ + class Program + { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + static void Main(string[] args) + { + using (MappedDiagnosticsLogicalContext.SetScoped("order-number", 1024)) + { + Logger.Info("Message before a trace."); + + using (var scope = Tracer.Instance.StartActive("NLog46Example - Main()")) + { + Logger.Info("Message during a trace."); + } + + Logger.Info("Message after a trace."); + } + } + } +} diff --git a/customer-samples/AutomaticTraceIdInjection/NLog46Example/Properties/launchSettings.json b/customer-samples/AutomaticTraceIdInjection/NLog46Example/Properties/launchSettings.json new file mode 100644 index 000000000000..5d9b9f9e2999 --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/NLog46Example/Properties/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "NLog46Example": { + "commandName": "Project", + "environmentVariables": { + "DD_LOGS_INJECTION": "true" + }, + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/README.md b/customer-samples/AutomaticTraceIdInjection/README.md new file mode 100644 index 000000000000..a93fbcc2f2bd --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/README.md @@ -0,0 +1,21 @@ +# Automatic Trace ID injection +Follow the official documentation steps to set up [C# log collection](https://docs.datadoghq.com/logs/log_collection/csharp/) and [automatic trace ID injection](https://docs.datadoghq.com/tracing/connect_logs_and_traces/?tab=net), then run these samples to see the feature in action! + +If there is a logging layout that you would like to see documented here, please feel free to reach out with an issue or contribution! + +## Supported Logging Frameworks +### Log4Net +Layouts configured in the sample: +- JSON format: `SerializedLayout` (from the `log4net.Ext.Json` NuGet package) +- Raw format: `PatternLayout` (requires a custom Datadog Log Pipeline for processing) + +### NLog +Layouts configured in the sample: +- JSON format: `JsonLayout` +- Raw format: Custom layout (requires a custom Datadog Log Pipeline for processing) + +### Serilog +Layouts configured in the sample: +- JSON format: `JsonFormatter` +- JSON format: `CompactJsonFormatter` (from the `Serilog.Formatting.Compact` NuGet package) +- Raw format: output template (requires a custom Datadog Log Pipeline for processing) diff --git a/customer-samples/AutomaticTraceIdInjection/SerilogExample/Program.cs b/customer-samples/AutomaticTraceIdInjection/SerilogExample/Program.cs new file mode 100644 index 000000000000..288b7a0d7eae --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/SerilogExample/Program.cs @@ -0,0 +1,69 @@ +using System.IO; +using Datadog.Trace; +using Serilog; +using Serilog.Context; +using Serilog.Formatting.Compact; +using Serilog.Formatting.Json; + +namespace SerilogExample +{ + class Program + { + static void Main(string[] args) + { + // Regardless of the output layout, your LoggerConfiguration must be + // enriched from the LogContext to extract the `dd.trace_id` and `dd.span_id` + // properties that are automatically injected by the .NET tracer + // + // Additions to LoggerConfiguration: + // - .Enrich.FromLogContext() + var loggerConfiguration = new LoggerConfiguration() + .Enrich.FromLogContext() + .MinimumLevel.Is(Serilog.Events.LogEventLevel.Information); + + // When using a message template, you must emit all properties using the {Properties} syntax in order to emit `dd.trace_id` and `dd.span_id` (see: https://github.com/serilog/serilog/wiki/Formatting-Output#formatting-plain-text) + // This is because Serilog cannot look up these individual keys by name due to the '.' in the key name (see https://github.com/serilog/serilog/wiki/Writing-Log-Events#message-template-syntax) + // Additionally, Datadog will only parse log properties if they are in a JSON-like map, and the values for dd.trace_id and dd.span_id must be surrounded by quotes + // + // Additions to layout: + // - {Properties} + // + loggerConfiguration = loggerConfiguration + .WriteTo.File( + "log-Serilog-textFile.log", + outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Properties} {Message:lj} {NewLine}{Exception}"); + + // The built-in JsonFormatter will display all properties by default, so no extra work is needed to emit `dd.trace_id` and `dd.span_id` + // + // Additions to layout: none + // + loggerConfiguration = loggerConfiguration + .WriteTo.File( + new JsonFormatter(), + "log-Serilog-jsonFile-allProperties.log"); + + // The CompactJsonFormatter from the Serilog.Formatting.Compact NuGet package will display all properties by default, so no extra work is needed to emit `dd.trace_id` and `dd.span_id` + // + // Additions to layout: none + // + loggerConfiguration = loggerConfiguration + .WriteTo.File( + new CompactJsonFormatter(), + "log-Serilog-compactJsonFile-allProperties.log"); + + // Main procedure + var log = loggerConfiguration.CreateLogger(); + using (LogContext.PushProperty("order-number", 1024)) + { + log.Information("Message before a trace."); + + using (var scope = Tracer.Instance.StartActive("SerilogExample - Main()")) + { + log.Information("Message during a trace."); + } + + log.Information("Message after a trace."); + } + } + } +} diff --git a/customer-samples/AutomaticTraceIdInjection/SerilogExample/Properties/launchSettings.json b/customer-samples/AutomaticTraceIdInjection/SerilogExample/Properties/launchSettings.json new file mode 100644 index 000000000000..7613ba2babb2 --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/SerilogExample/Properties/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "SerilogExample": { + "commandName": "Project", + "environmentVariables": { + "DD_LOGS_INJECTION": "true" + }, + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/customer-samples/AutomaticTraceIdInjection/SerilogExample/SerilogExample.csproj b/customer-samples/AutomaticTraceIdInjection/SerilogExample/SerilogExample.csproj new file mode 100644 index 000000000000..e77f95022e71 --- /dev/null +++ b/customer-samples/AutomaticTraceIdInjection/SerilogExample/SerilogExample.csproj @@ -0,0 +1,15 @@ + + + + Exe + netcoreapp2.1 + + + + + + + + + + \ No newline at end of file diff --git a/customer-samples/customer-samples.sln b/customer-samples/customer-samples.sln new file mode 100644 index 000000000000..cd391e0562ee --- /dev/null +++ b/customer-samples/customer-samples.sln @@ -0,0 +1,59 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29324.140 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutomaticTraceIdInjection", "AutomaticTraceIdInjection", "{8AD58831-2198-4661-AC87-EFA754EDC4E9}" + ProjectSection(SolutionItems) = preProject + AutomaticTraceIdInjection\README.md = AutomaticTraceIdInjection\README.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Log4NetExample", "AutomaticTraceIdInjection\Log4NetExample\Log4NetExample.csproj", "{1115F7F9-B6A6-4E4C-8731-E3E875616DF7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SerilogExample", "AutomaticTraceIdInjection\SerilogExample\SerilogExample.csproj", "{51F8B356-6F95-460A-9549-52534B85042D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F901F53D-6A53-421C-91F6-B6E32A65826A}" + ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NLog45Example", "AutomaticTraceIdInjection\NLog45Example\NLog45Example.csproj", "{B987A36C-111D-41B7-9DA0-35DF790DD450}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NLog46Example", "AutomaticTraceIdInjection\NLog46Example\NLog46Example.csproj", "{82DD704F-20C9-4F77-B3ED-7E555E8077C8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1115F7F9-B6A6-4E4C-8731-E3E875616DF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1115F7F9-B6A6-4E4C-8731-E3E875616DF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1115F7F9-B6A6-4E4C-8731-E3E875616DF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1115F7F9-B6A6-4E4C-8731-E3E875616DF7}.Release|Any CPU.Build.0 = Release|Any CPU + {51F8B356-6F95-460A-9549-52534B85042D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51F8B356-6F95-460A-9549-52534B85042D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51F8B356-6F95-460A-9549-52534B85042D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51F8B356-6F95-460A-9549-52534B85042D}.Release|Any CPU.Build.0 = Release|Any CPU + {B987A36C-111D-41B7-9DA0-35DF790DD450}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B987A36C-111D-41B7-9DA0-35DF790DD450}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B987A36C-111D-41B7-9DA0-35DF790DD450}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B987A36C-111D-41B7-9DA0-35DF790DD450}.Release|Any CPU.Build.0 = Release|Any CPU + {82DD704F-20C9-4F77-B3ED-7E555E8077C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {82DD704F-20C9-4F77-B3ED-7E555E8077C8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {82DD704F-20C9-4F77-B3ED-7E555E8077C8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {82DD704F-20C9-4F77-B3ED-7E555E8077C8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1115F7F9-B6A6-4E4C-8731-E3E875616DF7} = {8AD58831-2198-4661-AC87-EFA754EDC4E9} + {51F8B356-6F95-460A-9549-52534B85042D} = {8AD58831-2198-4661-AC87-EFA754EDC4E9} + {B987A36C-111D-41B7-9DA0-35DF790DD450} = {8AD58831-2198-4661-AC87-EFA754EDC4E9} + {82DD704F-20C9-4F77-B3ED-7E555E8077C8} = {8AD58831-2198-4661-AC87-EFA754EDC4E9} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1C64C3C7-7F87-46D4-88F8-1DB81303FBAC} + EndGlobalSection +EndGlobal