Skip to content

Commit

Permalink
Restore the manual Tracer.ctor so that it works in version-conflict s…
Browse files Browse the repository at this point in the history
…cenarios
  • Loading branch information
andrewlock committed Nov 22, 2024
1 parent fcb1204 commit a637bb5
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 30 deletions.
25 changes: 22 additions & 3 deletions tracer/src/Datadog.Trace.Manual/Tracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

using Datadog.Trace.ClrProfiler.AutoInstrumentation.ManualInstrumentation;
using Datadog.Trace.Configuration;
using Datadog.Trace.DuckTyping;
using Datadog.Trace.SourceGenerators;
Expand All @@ -20,9 +21,22 @@ public sealed class Tracer : ITracer, IDatadogOpenTracingTracer
private object? _automaticSettings;
private ImmutableTracerSettings? _settings;

private Tracer(object? automaticTracer)
[Instrumented] // This is only _actually_ instrumented up to 3.6.0 (automatic)
private Tracer(object? automaticTracer, Dictionary<string, object?> initialValues)
{
AutomaticTracer = automaticTracer;

// In 3.7.0+ we don't bother populating the dictionary with the settings
// seeing as the whole _settings object is going to be thrown away and
// repopulated if the customer calls Settings. Kind of annoying...
// so to avoid the extra work/allocation we check whether the initial values contains the
// agent key, as an easy way of detecting if we're running in this version-conflict mode.
// If we're not in version conflict, we can delay allocating the settings object until
// its actually requested.
if (initialValues.ContainsKey(TracerSettingKeyConstants.AgentUriKey))
{
_settings = new ImmutableTracerSettings(initialValues);
}
}

// Not null when the automatic tracer is available
Expand All @@ -49,7 +63,7 @@ public static Tracer Instance

// need a new tracer instance, because either the automatic tracer has changed
// or this is the first time fetching it
var instance = new Tracer(automaticTracer);
var instance = new Tracer(automaticTracer, new());
_instance = instance;
return instance;
}
Expand Down Expand Up @@ -141,7 +155,12 @@ private static void Configure(Dictionary<string, object?> settings)
/// settings, only if the ImmutableTracerSettings (automatic) provided is different to the current one.
/// </summary>
[Instrumented]
private Dictionary<string, object?>? GetUpdatedImmutableTracerSettings(object? automaticTracer, ref object? automaticSettings) => null;
private Dictionary<string, object?>? GetUpdatedImmutableTracerSettings(object? automaticTracer, ref object? automaticSettings)
{
_ = automaticTracer;
_ = automaticSettings;
return null;
}

/// <summary>
/// Automatic instrumentation intercepts this method and returns a duck-typed Scope from Datadog.Trace.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public class CtorIntegration
{
internal static CallTargetState OnMethodBegin<TTarget>(TTarget instance, object? automaticTracer, Dictionary<string, object?> values)
{
// In earlier versions of the automatic tracer, the settings were passed in as a dictionary
// but in 3.7.0 we don't need to instrument them
if (automaticTracer is Datadog.Trace.Tracer tracer)
{
PopulateSettings(values, tracer.Settings);
Expand All @@ -43,6 +45,7 @@ internal static CallTargetState OnMethodBegin<TTarget>(TTarget instance, object?
internal static void PopulateSettings(Dictionary<string, object?> values, ImmutableTracerSettings settings)
{
// record all the settings in the dictionary
// This key is used to detect if the settings have been populated _at all_, so should always be sent
values[TracerSettingKeyConstants.AgentUriKey] = settings.ExporterInternal.AgentUriInternal;
#pragma warning disable CS0618 // Type or member is obsolete
values[TracerSettingKeyConstants.AnalyticsEnabledKey] = settings.AnalyticsEnabledInternal;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.ManualInstrumentation.Tr
MethodName = "GetUpdatedImmutableTracerSettings",
ReturnTypeName = "System.Collections.Generic.Dictionary`2[System.String,System.Object]",
ParameterTypeNames = [ClrNames.Object, "System.Object&"],
MinimumVersion = "3.6.*", // added in 3.7.0
MinimumVersion = "3.7.0", // added in 3.7.0
MaximumVersion = ManualInstrumentationConstants.MaxVersion,
IntegrationName = ManualInstrumentationConstants.IntegrationName)]
[Browsable(false)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,9 @@ public void DatadogTraceManual_AllInstrumentedMethodsAreDecoratedWithInstrumente
{
var manualAssembly = typeof(T).Assembly;
var assemblyName = manualAssembly.GetName().Name;
var assemblyVersion = manualAssembly.GetName().Version!;

// find all types in Datadog.Trace that instrument methods in the target assembly
// exclude the ones that don't target older versions
var instrumentations = GetAllInstrumentations(assemblyName)
.Where(x => GetMaxVersion(x.Attribute.MaximumVersion) >= assemblyVersion)
.GroupBy(x => x.Attribute.TypeName);
var instrumentations = GetAllInstrumentations(assemblyName).GroupBy(x => x.Attribute.TypeName);

var attributedMembers = manualAssembly
.GetTypes()
Expand Down Expand Up @@ -97,27 +93,6 @@ private static Type GetType(string type, Assembly targetAssembly)
: x.Attribute.AssemblyName == assemblyName);
}

private static Version GetMaxVersion(string version)
{
// handle our version numbers with * etc
var splits = version.Split('.');
var major = splits.Length > 0 ? ToVersion(splits[0]) : ushort.MaxValue;
var minor = splits.Length > 1 ? ToVersion(splits[1]) : ushort.MaxValue;
var patch = splits.Length > 2 ? ToVersion(splits[2]) : ushort.MaxValue;

return new Version(major, minor, patch);

static ushort ToVersion(string number)
{
if (!string.IsNullOrEmpty(number) && ushort.TryParse(number, out var value))
{
return value;
}

return ushort.MaxValue;
}
}

private static bool IsTarget(MemberInfo memberInfo, string methodName, List<Type> expectedParams)
{
if (memberInfo.Name != methodName)
Expand Down

0 comments on commit a637bb5

Please sign in to comment.