diff --git a/Datadog.Trace.sln b/Datadog.Trace.sln
index f2aab4956baa..09bdab4e9602 100644
--- a/Datadog.Trace.sln
+++ b/Datadog.Trace.sln
@@ -401,6 +401,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.AspNetCore2", "test
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Datadog.Instrumentation", "src\Datadog.Instrumentation\Datadog.Instrumentation.csproj", "{CF364E70-F5B5-4D44-B29E-2165525D3A69}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogsInjection.ILogger", "test\test-applications\integrations\LogsInjection.ILogger\LogsInjection.ILogger.csproj", "{463A6FB2-1ABE-4B92-A470-97134D0BBC7E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1668,6 +1670,16 @@ Global
{CF364E70-F5B5-4D44-B29E-2165525D3A69}.Release|x64.Build.0 = Release|Any CPU
{CF364E70-F5B5-4D44-B29E-2165525D3A69}.Release|x86.ActiveCfg = Release|Any CPU
{CF364E70-F5B5-4D44-B29E-2165525D3A69}.Release|x86.Build.0 = Release|Any CPU
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Debug|x64.ActiveCfg = Debug|x64
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Debug|x64.Build.0 = Debug|x64
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Debug|x86.ActiveCfg = Debug|x86
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Debug|x86.Build.0 = Debug|x86
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Release|x64.ActiveCfg = Release|x64
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Release|x64.Build.0 = Release|x64
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Release|x86.ActiveCfg = Release|x86
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Release|x86.Build.0 = Release|x86
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E}.Release|Any CPU.ActiveCfg = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1803,6 +1815,7 @@ Global
{7C66569C-1174-49AF-8DA7-8B216685C1D4} = {8CEC2042-F11C-49F5-A674-2355793B600A}
{8A73100E-F2C3-44D3-A5B8-49B5BFDF1B52} = {0972AD57-B16B-494F-AE0A-091DD6F3B42B}
{CF364E70-F5B5-4D44-B29E-2165525D3A69} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}
+ {463A6FB2-1ABE-4B92-A470-97134D0BBC7E} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}
diff --git a/integrations.json b/integrations.json
index 281052ad6145..22eb2822a6b6 100644
--- a/integrations.json
+++ b/integrations.json
@@ -1401,6 +1401,59 @@
}
]
},
+ {
+ "name": "ILogger",
+ "method_replacements": [
+ {
+ "caller": {},
+ "target": {
+ "assembly": "Microsoft.Extensions.Logging.Abstractions",
+ "type": "Microsoft.Extensions.Logging.LoggerExternalScopeProvider",
+ "method": "ForEachScope",
+ "signature_types": [
+ "System.Void",
+ "System.Action`2[System.Object,!!0]",
+ "!!0"
+ ],
+ "minimum_major": 2,
+ "minimum_minor": 0,
+ "minimum_patch": 0,
+ "maximum_major": 5,
+ "maximum_minor": 65535,
+ "maximum_patch": 65535
+ },
+ "wrapper": {
+ "assembly": "Datadog.Trace, Version=1.28.3.0, Culture=neutral, PublicKeyToken=def86d061d0d2eeb",
+ "type": "Datadog.Trace.ClrProfiler.AutoInstrumentation.ILogger.LoggerExternalScopeProviderForEachScopeIntegration",
+ "action": "CallTargetModification"
+ }
+ },
+ {
+ "caller": {},
+ "target": {
+ "assembly": "Microsoft.Extensions.Logging",
+ "type": "Microsoft.Extensions.Logging.LoggerFactoryScopeProvider",
+ "method": "ForEachScope",
+ "signature_types": [
+ "System.Void",
+ "System.Action`2[System.Object,!!0]",
+ "!!0"
+ ],
+ "minimum_major": 2,
+ "minimum_minor": 0,
+ "minimum_patch": 0,
+ "maximum_major": 5,
+ "maximum_minor": 65535,
+ "maximum_patch": 65535
+ },
+ "wrapper": {
+ "assembly": "Datadog.Trace, Version=1.28.3.0, Culture=neutral, PublicKeyToken=def86d061d0d2eeb",
+ "type": "Datadog.Trace.ClrProfiler.AutoInstrumentation.ILogger.LoggerFactoryScopeProviderForEachScopeIntegration",
+ "action": "CallTargetModification"
+ }
+ }
+ ]
+ },
{
"name": "Kafka",
"method_replacements": [
diff --git a/src/Datadog.Trace.ClrProfiler.Native/dd_profiler_constants.h b/src/Datadog.Trace.ClrProfiler.Native/dd_profiler_constants.h
index 97be57a3907d..9fe8aa65e5d7 100644
--- a/src/Datadog.Trace.ClrProfiler.Native/dd_profiler_constants.h
+++ b/src/Datadog.Trace.ClrProfiler.Native/dd_profiler_constants.h
@@ -40,7 +40,22 @@ const WSTRING skip_assembly_prefixes[]{
WStr("Microsoft.ApplicationInsights"),
WStr("Microsoft.Build"),
WStr("Microsoft.CSharp"),
- WStr("Microsoft.Extensions"),
+ WStr("Microsoft.Extensions.Caching"),
+ WStr("Microsoft.Extensions.Configuration"),
+ WStr("Microsoft.Extensions.DependencyInjection"),
+ WStr("Microsoft.Extensions.DependencyModel"),
+ WStr("Microsoft.Extensions.Diagnostics"),
+ WStr("Microsoft.Extensions.FileProviders"),
+ WStr("Microsoft.Extensions.FileSystemGlobbing"),
+ WStr("Microsoft.Extensions.Hosting"),
+ WStr("Microsoft.Extensions.Http"),
+ WStr("Microsoft.Extensions.Identity"),
+ WStr("Microsoft.Extensions.Localization"),
+ WStr("Microsoft.Extensions.ObjectPool"),
+ WStr("Microsoft.Extensions.Options"),
+ WStr("Microsoft.Extensions.PlatformAbstractions"),
+ WStr("Microsoft.Extensions.Primitives"),
+ WStr("Microsoft.Extensions.WebEncoders "),
WStr("Microsoft.Web.Compilation.Snapshots"),
WStr("System.Core"),
WStr("System.Console"),
diff --git a/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/DatadogLoggingScope.cs b/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/DatadogLoggingScope.cs
new file mode 100644
index 000000000000..5d7618aef4cc
--- /dev/null
+++ b/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/DatadogLoggingScope.cs
@@ -0,0 +1,84 @@
+//
+// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
+// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.ILogger
+{
+ internal class DatadogLoggingScope : IReadOnlyList>
+ {
+ private readonly string _service;
+ private readonly string _env;
+ private readonly string _version;
+ private readonly Tracer _tracer;
+
+ public DatadogLoggingScope()
+ : this(Tracer.Instance)
+ {
+ }
+
+ internal DatadogLoggingScope(Tracer tracer)
+ {
+ _tracer = tracer;
+ _service = tracer.DefaultServiceName ?? string.Empty;
+ _env = tracer.Settings.Environment ?? string.Empty;
+ _version = tracer.Settings.ServiceVersion ?? string.Empty;
+ }
+
+ public int Count => 5;
+
+ public KeyValuePair this[int index]
+ {
+ get
+ {
+ return index switch
+ {
+ 0 => new KeyValuePair("dd_service", _tracer.ActiveScope?.Span.ServiceName ?? _service),
+ 1 => new KeyValuePair("dd_env", _env),
+ 2 => new KeyValuePair("dd_version", _version),
+ 3 => new KeyValuePair("dd_trace_id", _tracer.ActiveScope?.Span.TraceId),
+ 4 => new KeyValuePair("dd_span_id", _tracer.ActiveScope?.Span.SpanId),
+ _ => throw new ArgumentOutOfRangeException(nameof(index))
+ };
+ }
+ }
+
+ public override string ToString()
+ {
+ var span = _tracer.ActiveScope?.Span;
+
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "dd_service:{0}, dd_env:{1}, dd_version:{2}, dd_trace_id:{3}, dd_span_id:{4}",
+ span?.ServiceName ?? _service,
+ _env,
+ _version,
+ _tracer.ActiveScope?.Span.TraceId,
+ _tracer.ActiveScope?.Span.SpanId);
+ }
+
+ public IEnumerator> GetEnumerator()
+ {
+ var span = _tracer.ActiveScope?.Span;
+ yield return new KeyValuePair("dd_service", span?.ServiceName ?? _service);
+ yield return new KeyValuePair("dd_env", _env);
+ yield return new KeyValuePair("dd_version", _version);
+
+ if (span is not null)
+ {
+ yield return new KeyValuePair("dd_trace_id", span.TraceId);
+ yield return new KeyValuePair("dd_span_id", span.SpanId);
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+}
diff --git a/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/LoggerExternalScopeProviderForEachScopeIntegration.cs b/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/LoggerExternalScopeProviderForEachScopeIntegration.cs
new file mode 100644
index 000000000000..506b2c0ccb0d
--- /dev/null
+++ b/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/LoggerExternalScopeProviderForEachScopeIntegration.cs
@@ -0,0 +1,57 @@
+//
+// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
+// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
+//
+
+using System;
+using System.ComponentModel;
+using Datadog.Trace.ClrProfiler.CallTarget;
+
+namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.ILogger
+{
+ ///
+ /// LoggerExternalScopeProvider.ForEach<TState> calltarget instrumentation
+ ///
+ [InstrumentMethod(
+ AssemblyName = "Microsoft.Extensions.Logging.Abstractions",
+ TypeName = "Microsoft.Extensions.Logging.LoggerExternalScopeProvider",
+ MethodName = "ForEachScope",
+ ReturnTypeName = ClrNames.Void,
+ ParameterTypeNames = new[] { "System.Action`2[System.Object,!!0]", "!!0" },
+ MinimumVersion = "2.0.0",
+ MaximumVersion = "5.*.*",
+ IntegrationName = LoggerIntegrationCommon.IntegrationName)]
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class LoggerExternalScopeProviderForEachScopeIntegration
+ {
+ ///
+ /// OnMethodBegin callback
+ ///
+ /// Type of the target
+ /// The type of the action
+ /// The type of the state
+ /// Instance value, aka `this` of the instrumented method.
+ /// The callback to be invoked per scope
+ /// The state to pass to the callback
+ /// Calltarget state value
+ public static CallTargetState OnMethodBegin(TTarget instance, TAction callback, TState state)
+ {
+ LoggerIntegrationCommon.AddScope(Tracer.Instance, callback, state);
+ return new CallTargetState(scope: null, state: null);
+ }
+
+ ///
+ /// OnMethodEnd callback
+ ///
+ /// Type of the target
+ /// Instance value, aka `this` of the instrumented method.
+ /// Exception instance in case the original code threw an exception.
+ /// Calltarget state value
+ /// A response value, in an async scenario will be T of Task of T
+ public static CallTargetReturn OnMethodEnd(TTarget instance, Exception exception, CallTargetState state)
+ {
+ return CallTargetReturn.GetDefault();
+ }
+ }
+}
diff --git a/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/LoggerFactoryScopeProviderForEachScopeIntegration.cs b/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/LoggerFactoryScopeProviderForEachScopeIntegration.cs
new file mode 100644
index 000000000000..e0b7f2df2dda
--- /dev/null
+++ b/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/LoggerFactoryScopeProviderForEachScopeIntegration.cs
@@ -0,0 +1,57 @@
+//
+// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
+// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
+//
+
+using System;
+using System.ComponentModel;
+using Datadog.Trace.ClrProfiler.CallTarget;
+
+namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.ILogger
+{
+ ///
+ /// LoggerFactoryScopeProvider.ForEach<TState> calltarget instrumentation
+ ///
+ [InstrumentMethod(
+ AssemblyName = "Microsoft.Extensions.Logging",
+ TypeName = "Microsoft.Extensions.Logging.LoggerFactoryScopeProvider",
+ MethodName = "ForEachScope",
+ ReturnTypeName = ClrNames.Void,
+ ParameterTypeNames = new[] { "System.Action`2[System.Object,!!0]", "!!0" },
+ MinimumVersion = "2.0.0",
+ MaximumVersion = "5.*.*",
+ IntegrationName = LoggerIntegrationCommon.IntegrationName)]
+ [Browsable(false)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class LoggerFactoryScopeProviderForEachScopeIntegration
+ {
+ ///
+ /// OnMethodBegin callback
+ ///
+ /// Type of the target
+ /// The type of the action
+ /// The type of the state
+ /// Instance value, aka `this` of the instrumented method.
+ /// The callback to be invoked per scope
+ /// The state to pass to the callback
+ /// Calltarget state value
+ public static CallTargetState OnMethodBegin(TTarget instance, TAction callback, TState state)
+ {
+ LoggerIntegrationCommon.AddScope(Tracer.Instance, callback, state);
+ return new CallTargetState(scope: null, state: null);
+ }
+
+ ///
+ /// OnMethodEnd callback
+ ///
+ /// Type of the target
+ /// Instance value, aka `this` of the instrumented method.
+ /// Exception instance in case the original code threw an exception.
+ /// Calltarget state value
+ /// A response value, in an async scenario will be T of Task of T
+ public static CallTargetReturn OnMethodEnd(TTarget instance, Exception exception, CallTargetState state)
+ {
+ return CallTargetReturn.GetDefault();
+ }
+ }
+}
diff --git a/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/LoggerIntegrationCommon.cs b/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/LoggerIntegrationCommon.cs
new file mode 100644
index 000000000000..d77629c2daaa
--- /dev/null
+++ b/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ILogger/LoggerIntegrationCommon.cs
@@ -0,0 +1,28 @@
+//
+// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
+// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
+//
+
+using System;
+using Datadog.Trace.Configuration;
+
+namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.ILogger
+{
+ internal static class LoggerIntegrationCommon
+ {
+ public const string IntegrationName = nameof(IntegrationIds.ILogger);
+ private static readonly IntegrationInfo IntegrationId = IntegrationRegistry.GetIntegrationInfo(IntegrationName);
+
+ private static readonly DatadogLoggingScope DatadogScope = new();
+
+ public static void AddScope(Tracer tracer, TAction callback, TState state)
+ {
+ if (tracer.Settings.LogsInjectionEnabled
+ && tracer.Settings.IsIntegrationEnabled(IntegrationId)
+ && callback is Action