Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Microsoft.Extensions.Logging.ILogger instrumentation #1663

Merged
merged 10 commits into from
Aug 23, 2021
13 changes: 13 additions & 0 deletions Datadog.Trace.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
53 changes: 53 additions & 0 deletions integrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
17 changes: 16 additions & 1 deletion src/Datadog.Trace.ClrProfiler.Native/dd_profiler_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// <copyright file="DatadogLoggingScope.cs" company="Datadog">
// 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.
// </copyright>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.ILogger
{
internal class DatadogLoggingScope : IReadOnlyList<KeyValuePair<string, object>>
{
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<string, object> this[int index]
{
get
{
return index switch
{
0 => new KeyValuePair<string, object>("dd_service", _tracer.ActiveScope?.Span.ServiceName ?? _service),
1 => new KeyValuePair<string, object>("dd_env", _env),
2 => new KeyValuePair<string, object>("dd_version", _version),
3 => new KeyValuePair<string, object>("dd_trace_id", _tracer.ActiveScope?.Span.TraceId),
4 => new KeyValuePair<string, object>("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<KeyValuePair<string, object>> GetEnumerator()
{
var span = _tracer.ActiveScope?.Span;
yield return new KeyValuePair<string, object>("dd_service", span?.ServiceName ?? _service);
yield return new KeyValuePair<string, object>("dd_env", _env);
yield return new KeyValuePair<string, object>("dd_version", _version);

if (span is not null)
{
yield return new KeyValuePair<string, object>("dd_trace_id", span.TraceId);
yield return new KeyValuePair<string, object>("dd_span_id", span.SpanId);
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// <copyright file="LoggerExternalScopeProviderForEachScopeIntegration.cs" company="Datadog">
// 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.
// </copyright>

using System;
using System.ComponentModel;
using Datadog.Trace.ClrProfiler.CallTarget;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.ILogger
{
/// <summary>
/// LoggerExternalScopeProvider.ForEach&lt;TState&gt; calltarget instrumentation
/// </summary>
[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
{
/// <summary>
/// OnMethodBegin callback
/// </summary>
/// <typeparam name="TTarget">Type of the target</typeparam>
/// <typeparam name="TAction">The type of the action</typeparam>
/// <typeparam name="TState">The type of the state</typeparam>
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
/// <param name="callback">The callback to be invoked per scope</param>
/// <param name="state">The state to pass to the callback</param>
/// <returns>Calltarget state value</returns>
public static CallTargetState OnMethodBegin<TTarget, TAction, TState>(TTarget instance, TAction callback, TState state)
{
LoggerIntegrationCommon.AddScope(Tracer.Instance, callback, state);
return new CallTargetState(scope: null, state: null);
}

/// <summary>
/// OnMethodEnd callback
/// </summary>
/// <typeparam name="TTarget">Type of the target</typeparam>
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
/// <param name="exception">Exception instance in case the original code threw an exception.</param>
/// <param name="state">Calltarget state value</param>
/// <returns>A response value, in an async scenario will be T of Task of T</returns>
public static CallTargetReturn OnMethodEnd<TTarget>(TTarget instance, Exception exception, CallTargetState state)
{
return CallTargetReturn.GetDefault();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// <copyright file="LoggerFactoryScopeProviderForEachScopeIntegration.cs" company="Datadog">
// 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.
// </copyright>

using System;
using System.ComponentModel;
using Datadog.Trace.ClrProfiler.CallTarget;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.ILogger
{
/// <summary>
/// LoggerFactoryScopeProvider.ForEach&lt;TState&gt; calltarget instrumentation
/// </summary>
[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
{
/// <summary>
/// OnMethodBegin callback
/// </summary>
/// <typeparam name="TTarget">Type of the target</typeparam>
/// <typeparam name="TAction">The type of the action</typeparam>
/// <typeparam name="TState">The type of the state</typeparam>
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
/// <param name="callback">The callback to be invoked per scope</param>
/// <param name="state">The state to pass to the callback</param>
/// <returns>Calltarget state value</returns>
public static CallTargetState OnMethodBegin<TTarget, TAction, TState>(TTarget instance, TAction callback, TState state)
{
LoggerIntegrationCommon.AddScope(Tracer.Instance, callback, state);
return new CallTargetState(scope: null, state: null);
}

/// <summary>
/// OnMethodEnd callback
/// </summary>
/// <typeparam name="TTarget">Type of the target</typeparam>
/// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
/// <param name="exception">Exception instance in case the original code threw an exception.</param>
/// <param name="state">Calltarget state value</param>
/// <returns>A response value, in an async scenario will be T of Task of T</returns>
public static CallTargetReturn OnMethodEnd<TTarget>(TTarget instance, Exception exception, CallTargetState state)
{
return CallTargetReturn.GetDefault();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// <copyright file="LoggerIntegrationCommon.cs" company="Datadog">
// 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.
// </copyright>

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<TAction, TState>(Tracer tracer, TAction callback, TState state)
{
if (tracer.Settings.LogsInjectionEnabled
&& tracer.Settings.IsIntegrationEnabled(IntegrationId)
&& callback is Action<object, TState> foreachCallback)
{
foreachCallback.Invoke(DatadogScope, state);
}
}
}
}
1 change: 1 addition & 0 deletions src/Datadog.Trace/Configuration/IntegrationIds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ internal enum IntegrationIds
CosmosDb,
AwsSdk,
AwsSqs,
ILogger,
}
}
Loading