Skip to content

Commit 050c019

Browse files
authored
Move DefaultServiceName to MutableSettings (#7530)
## Summary of changes - Expose `DefaultServiceName` on `MutableSettings` instead of on `TracerManager` - Expose `MutableSettings` on `PerTraceSettings` ## Reason for change The `DefaultServiceName` depends on `ServiceName`, which can change at runtime, so `MutableSettings` seems like the best place for it (eventually we will only have a single `TracerManager` and `TracerSettings` per lifetime > Note that this also solves an existing edge-case bug when customers do config in code and already-finished traces are serialized with the "incorrect" default service name. ## Implementation details Mostly commit-by-commit but: - Move the "fallback application name" calculation to a helper class - Expose the fallback application name on `TracerSettings` - Created as a `Lazy<>` because this calculation can be kind of expensive, and isn't necessary if the customer specifies a service name. - Exposed on `TracerSettings` because it doesn't change - Expose `DefaultServiceName` on `MutableSettings` instead of `TracerManager`. - Update usages to point to the new location Additionally, there are some places where I believe we were "incorrectly" using the `DD_SERVICE` value, and ignoring the real fallback name. - [x] Service Discovery's `StoreTracerMetadata` - @anna-git can you confirm if I'm correct that this _should_ be using the "calculated" service name as a fallback? - [x] `TraceExporterConfiguration` - @ganeshnj, same question, can you confirm that we should be passing the "calculated" service name, not just the "explictly set" service name? One additional aspect I think we should consider: - Currently we're calling `NormalizeService(serviceName)` in a few places. Is there any reason we shouldn't be _always_ normalizing the service name? - e.g. why don't we normalize `DefaultServiceName` automatically? ## Test coverage Covered by existing tests generally ## Other details https://datadoghq.atlassian.net/browse/LANGPLAT-819 Part of a config stack - #7522 - #7525 - #7530 👈 - #7532 - #7543 - #7544
1 parent a11314c commit 050c019

File tree

14 files changed

+137
-109
lines changed

14 files changed

+137
-109
lines changed

tracer/src/Datadog.Trace/Ci/TestOptimizationTracerManager.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ public TestOptimizationTracerManager(
3838
ITelemetryController telemetry,
3939
IDiscoveryService discoveryService,
4040
DataStreamsManager dataStreamsManager,
41-
string defaultServiceName,
4241
IGitMetadataTagsProvider gitMetadataTagsProvider,
4342
ITraceSampler traceSampler,
4443
ISpanSampler spanSampler,
@@ -56,7 +55,6 @@ public TestOptimizationTracerManager(
5655
telemetry,
5756
discoveryService,
5857
dataStreamsManager,
59-
defaultServiceName,
6058
gitMetadataTagsProvider,
6159
traceSampler,
6260
spanSampler,
@@ -156,7 +154,6 @@ public LockedManager(
156154
ITelemetryController telemetry,
157155
IDiscoveryService discoveryService,
158156
DataStreamsManager dataStreamsManager,
159-
string defaultServiceName,
160157
IGitMetadataTagsProvider gitMetadataTagsProvider,
161158
ITraceSampler traceSampler,
162159
ISpanSampler spanSampler,
@@ -174,7 +171,6 @@ public LockedManager(
174171
telemetry,
175172
discoveryService,
176173
dataStreamsManager,
177-
defaultServiceName,
178174
gitMetadataTagsProvider,
179175
traceSampler,
180176
spanSampler,

tracer/src/Datadog.Trace/Ci/TestOptimizationTracerManagerFactory.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ protected override TracerManager CreateTracerManagerFrom(
4747
ITelemetryController telemetry,
4848
IDiscoveryService discoveryService,
4949
DataStreamsManager dataStreamsManager,
50-
string defaultServiceName,
5150
IGitMetadataTagsProvider gitMetadataTagsProvider,
5251
ITraceSampler traceSampler,
5352
ISpanSampler spanSampler,
@@ -59,10 +58,10 @@ protected override TracerManager CreateTracerManagerFrom(
5958
telemetry.RecordTestOptimizationSettings(_settings);
6059
if (_testOptimizationTracerManagement.UseLockedTracerManager)
6160
{
62-
return new TestOptimizationTracerManager.LockedManager(settings, agentWriter, scopeManager, statsd, runtimeMetrics, logSubmissionManager, telemetry, discoveryService, dataStreamsManager, defaultServiceName, gitMetadataTagsProvider, traceSampler, spanSampler, remoteConfigurationManager, dynamicConfigurationManager, tracerFlareManager, spanEventsManager);
61+
return new TestOptimizationTracerManager.LockedManager(settings, agentWriter, scopeManager, statsd, runtimeMetrics, logSubmissionManager, telemetry, discoveryService, dataStreamsManager, gitMetadataTagsProvider, traceSampler, spanSampler, remoteConfigurationManager, dynamicConfigurationManager, tracerFlareManager, spanEventsManager);
6362
}
6463

65-
return new TestOptimizationTracerManager(settings, agentWriter, scopeManager, statsd, runtimeMetrics, logSubmissionManager, telemetry, discoveryService, dataStreamsManager, defaultServiceName, gitMetadataTagsProvider, traceSampler, spanSampler, remoteConfigurationManager, dynamicConfigurationManager, tracerFlareManager, spanEventsManager);
64+
return new TestOptimizationTracerManager(settings, agentWriter, scopeManager, statsd, runtimeMetrics, logSubmissionManager, telemetry, discoveryService, dataStreamsManager, gitMetadataTagsProvider, traceSampler, spanSampler, remoteConfigurationManager, dynamicConfigurationManager, tracerFlareManager, spanEventsManager);
6665
}
6766

6867
protected override ITelemetryController CreateTelemetryController(TracerSettings settings, IDiscoveryService discoveryService)

tracer/src/Datadog.Trace/Configuration/DynamicConfigurationManager.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,12 @@ private ApplyDetails[] ConfigurationUpdated(
247247
private void ApplyMergedConfiguration(List<RemoteConfiguration> remoteConfigurations)
248248
{
249249
// Get current service/environment for filtering
250-
var currentSettings = Tracer.Instance.Settings;
251-
var serviceName = currentSettings.ServiceName;
252-
var environment = currentSettings.Environment ?? Tracer.Instance.DefaultServiceName;
250+
var currentSettings = Tracer.Instance.CurrentTraceSettings.Settings;
253251

254252
var mergedConfigJToken = ApmTracingConfigMerger.MergeConfigurations(
255253
remoteConfigurations,
256-
serviceName,
257-
environment);
254+
serviceName: currentSettings.ServiceName,
255+
environment: currentSettings.Environment);
258256

259257
var configurationSource = new DynamicConfigConfigurationSource(mergedConfigJToken, ConfigurationOrigins.RemoteConfig);
260258

tracer/src/Datadog.Trace/Configuration/MutableSettings.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ private MutableSettings(
4747
bool startupDiagnosticLogEnabled,
4848
string? environment,
4949
string? serviceName,
50+
string defaultServiceName,
5051
string? serviceVersion,
5152
HashSet<string> disabledIntegrationNames,
5253
ReadOnlyDictionary<string, string> grpcTags,
@@ -74,6 +75,7 @@ private MutableSettings(
7475
StartupDiagnosticLogEnabled = startupDiagnosticLogEnabled;
7576
Environment = environment;
7677
ServiceName = serviceName;
78+
DefaultServiceName = defaultServiceName;
7779
ServiceVersion = serviceVersion;
7880
DisabledIntegrationNames = disabledIntegrationNames;
7981
GrpcTags = grpcTags;
@@ -158,11 +160,19 @@ private MutableSettings(
158160
public string? Environment { get; }
159161

160162
/// <summary>
161-
/// Gets the service name applied to top-level spans and used to build derived service names.
163+
/// Gets the user-specified service name for the application. You should typically
164+
/// favor <see cref="DefaultServiceName"/> which includes the calculated application
165+
/// name where an explicit service name is not provided.
162166
/// </summary>
163167
/// <seealso cref="ConfigurationKeys.ServiceName"/>
164168
public string? ServiceName { get; }
165169

170+
/// <summary>
171+
/// Gets the service name applied to top-level spans and used to build derived service names.
172+
/// Composed based on <see cref="ServiceName"/> if provided, or a fallback value
173+
/// </summary>
174+
public string DefaultServiceName { get; }
175+
166176
/// <summary>
167177
/// Gets the version tag applied to all spans.
168178
/// </summary>
@@ -713,6 +723,7 @@ public static MutableSettings CreateUpdatedMutableSettings(
713723
startupDiagnosticLogEnabled: startupDiagnosticLogEnabled,
714724
environment: environment,
715725
serviceName: serviceName,
726+
defaultServiceName: serviceName ?? tracerSettings.FallbackApplicationName,
716727
serviceVersion: serviceVersion,
717728
disabledIntegrationNames: disabledIntegrationNames,
718729
grpcTags: grpcTags,
@@ -1046,6 +1057,7 @@ public static MutableSettings CreateInitialMutableSettings(
10461057
startupDiagnosticLogEnabled: startupDiagnosticLogEnabled,
10471058
environment: environment,
10481059
serviceName: serviceName,
1060+
defaultServiceName: serviceName ?? tracerSettings.FallbackApplicationName,
10491061
serviceVersion: serviceVersion,
10501062
disabledIntegrationNames: disabledIntegrationNames,
10511063
grpcTags: grpcTags,

tracer/src/Datadog.Trace/Configuration/PerTraceSettings.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ internal class PerTraceSettings
1616
{
1717
private readonly ConcurrentDictionary<string, string> _serviceNameCache = new();
1818

19-
public PerTraceSettings(ITraceSampler? traceSampler, ISpanSampler? spanSampler, IReadOnlyDictionary<string, string> serviceNames, NamingSchema schema)
19+
public PerTraceSettings(ITraceSampler? traceSampler, ISpanSampler? spanSampler, IReadOnlyDictionary<string, string> serviceNames, NamingSchema schema, MutableSettings mutableSettings)
2020
{
2121
TraceSampler = traceSampler;
2222
SpanSampler = spanSampler;
2323
ServiceNames = serviceNames;
2424
Schema = schema;
2525
HasResourceBasedSamplingRule = (traceSampler?.HasResourceBasedSamplingRule ?? false) || (spanSampler?.HasResourceBasedSamplingRule ?? false);
26+
Settings = mutableSettings;
2627
}
2728

2829
public ITraceSampler? TraceSampler { get; }
@@ -35,6 +36,8 @@ public PerTraceSettings(ITraceSampler? traceSampler, ISpanSampler? spanSampler,
3536

3637
public bool HasResourceBasedSamplingRule { get; }
3738

39+
public MutableSettings Settings { get; }
40+
3841
internal string GetServiceName(Tracer tracer, string serviceName)
3942
{
4043
if (ServiceNames.TryGetValue(serviceName, out var name))

tracer/src/Datadog.Trace/Configuration/TracerSettings.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using Datadog.Trace.LibDatadog;
1818
using Datadog.Trace.Logging;
1919
using Datadog.Trace.Logging.DirectSubmission;
20+
using Datadog.Trace.PlatformHelpers;
2021
using Datadog.Trace.Propagators;
2122
using Datadog.Trace.Sampling;
2223
using Datadog.Trace.SourceGenerators;
@@ -32,12 +33,10 @@ namespace Datadog.Trace.Configuration
3233
public record TracerSettings
3334
{
3435
private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor<TracerSettings>();
35-
private static readonly HashSet<string> DefaultExperimentalFeatures = new HashSet<string>()
36-
{
37-
"DD_TAGS"
38-
};
36+
private static readonly HashSet<string> DefaultExperimentalFeatures = ["DD_TAGS"];
3937

4038
private readonly IConfigurationTelemetry _telemetry;
39+
private readonly Lazy<string> _fallbackApplicationName;
4140

4241
/// <summary>
4342
/// Initializes a new instance of the <see cref="TracerSettings"/> class with default values.
@@ -646,6 +645,9 @@ not null when string.Equals(x, "lowmemory", StringComparison.OrdinalIgnoreCase)
646645
config.WithKeys(ConfigurationKeys.GraphQLErrorExtensions).AsString(),
647646
commaSeparator);
648647

648+
// We create a lazy here because this is kind of expensive, and we want to avoid calling it if we can
649+
_fallbackApplicationName = new(() => ApplicationNameHelpers.GetFallbackApplicationName(this));
650+
649651
InitialMutableSettings = MutableSettings.CreateInitialMutableSettings(source, telemetry, errorLog, this);
650652
MutableSettings = InitialMutableSettings;
651653
}
@@ -662,6 +664,8 @@ not null when string.Equals(x, "lowmemory", StringComparison.OrdinalIgnoreCase)
662664

663665
internal MutableSettings MutableSettings { get; init; }
664666

667+
internal string FallbackApplicationName => _fallbackApplicationName.Value;
668+
665669
/// <inheritdoc cref="MutableSettings.Environment"/>
666670
public string? Environment => MutableSettings.Environment;
667671

tracer/src/Datadog.Trace/Debugger/DebuggerManager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ private string GetServiceName(TracerSettings tracerSettings)
8888
{
8989
try
9090
{
91-
return TraceUtil.NormalizeTag(tracerSettings.ServiceName ?? TracerManager.Instance.DefaultServiceName);
91+
return TraceUtil.NormalizeTag(tracerSettings.MutableSettings.DefaultServiceName);
9292
}
9393
catch (Exception e)
9494
{
9595
Log.Error(e, "Could not set `DynamicInstrumentationHelper.ServiceName`.");
96-
return TracerManager.Instance.DefaultServiceName;
96+
return tracerSettings.MutableSettings.DefaultServiceName;
9797
}
9898
}
9999

tracer/src/Datadog.Trace/LibDatadog/ServiceDiscovery/ServiceDiscoveryHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ internal static StoreMetadataResult StoreTracerMetadata(TracerSettings tracerSet
3636
TracerConstants.Language,
3737
TracerConstants.ThreePartVersion,
3838
Environment.MachineName,
39-
tracerSettings.ServiceName,
39+
tracerSettings.MutableSettings.DefaultServiceName,
4040
tracerSettings.Environment,
4141
tracerSettings.ServiceVersion);
4242

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// <copyright file="ApplicationNameHelpers.cs" company="Datadog">
2+
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
4+
// </copyright>
5+
6+
#nullable enable
7+
8+
using System;
9+
using System.Diagnostics.CodeAnalysis;
10+
using System.Reflection;
11+
using Datadog.Trace.Configuration;
12+
using Datadog.Trace.Logging;
13+
using Datadog.Trace.Util;
14+
15+
namespace Datadog.Trace.PlatformHelpers;
16+
17+
internal static class ApplicationNameHelpers
18+
{
19+
private const string UnknownServiceName = "UnknownService";
20+
private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor(typeof(ApplicationNameHelpers));
21+
22+
public static string GetFallbackApplicationName(TracerSettings settings)
23+
=> GetApplicationName(settings) ?? UnknownServiceName;
24+
25+
/// <summary>
26+
/// Gets a fallback "application name" for the executing application by looking at
27+
/// the hosted app name (.NET Framework on IIS only), assembly name, and process name.
28+
/// </summary>
29+
/// <returns>The default service name.</returns>
30+
private static string? GetApplicationName(TracerSettings settings)
31+
{
32+
try
33+
{
34+
if ((settings.IsRunningInAzureAppService || settings.IsRunningInAzureFunctions) &&
35+
settings.AzureAppServiceMetadata?.SiteName is { } siteName)
36+
{
37+
return siteName;
38+
}
39+
40+
if (settings.LambdaMetadata is { IsRunningInLambda: true, ServiceName: var serviceName })
41+
{
42+
return serviceName;
43+
}
44+
45+
try
46+
{
47+
if (TryLoadAspNetSiteName(out siteName))
48+
{
49+
return siteName;
50+
}
51+
}
52+
catch (Exception ex)
53+
{
54+
// Unable to call into System.Web.dll
55+
Log.Error(ex, "Unable to get application name through ASP.NET settings");
56+
}
57+
58+
return Assembly.GetEntryAssembly()?.GetName().Name ??
59+
ProcessHelpers.GetCurrentProcessName();
60+
}
61+
catch (Exception ex)
62+
{
63+
Log.Error(ex, "Error creating default service name");
64+
return null;
65+
}
66+
}
67+
68+
private static bool TryLoadAspNetSiteName([NotNullWhen(true)] out string? siteName)
69+
{
70+
#if NETFRAMEWORK
71+
try
72+
{
73+
// System.Web.dll is only available on .NET Framework
74+
if (System.Web.Hosting.HostingEnvironment.IsHosted)
75+
{
76+
// if this app is an ASP.NET application, return "SiteName/ApplicationVirtualPath".
77+
// note that ApplicationVirtualPath includes a leading slash.
78+
siteName = (System.Web.Hosting.HostingEnvironment.SiteName + System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath).TrimEnd('/');
79+
return true;
80+
}
81+
}
82+
catch (TypeLoadException ex)
83+
{
84+
Log.Warning(ex, "Unable to determine ASP.NET site name: HostingEnvironment type could not be loaded. This is expected when running ASP.NET Core on the .NET Framework CLR, which is not supported");
85+
}
86+
#endif
87+
siteName = null;
88+
return false;
89+
}
90+
}

tracer/src/Datadog.Trace/Tracer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ public IScope ActiveScope
151151
/// <summary>
152152
/// Gets the default service name for traces where a service name is not specified.
153153
/// </summary>
154-
public string DefaultServiceName => TracerManager.DefaultServiceName;
154+
public string DefaultServiceName => CurrentTraceSettings.Settings.DefaultServiceName;
155155

156156
/// <summary>
157157
/// Gets the git metadata provider.

0 commit comments

Comments
 (0)