Skip to content

Commit 37f021e

Browse files
committed
Target compat layer specifically
1 parent 61a5e84 commit 37f021e

3 files changed

Lines changed: 90 additions & 14 deletions

File tree

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Serverless/CompatibilityLayer_CalculateDogStatsDPipeName_Integration.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,32 @@ internal static CallTargetReturn<string> OnMethodEnd<TTarget>(
5656

5757
try
5858
{
59-
// Lazy generation: generate unique pipe name once when compat layer first calls this method
59+
// Get the tracer's pipe name (generated in ExporterSettings if on Windows with no explicit config)
60+
// Use lazy caching to avoid repeated lookups
6061
if (_cachedDogStatsDPipeName == null)
6162
{
6263
lock (_lock)
6364
{
6465
if (_cachedDogStatsDPipeName == null)
6566
{
66-
_cachedDogStatsDPipeName = ServerlessCompatPipeNameHelper.GenerateUniquePipeName(
67-
returnValue,
68-
"dd_dogstatsd",
69-
"DogStatsD");
67+
var tracerInstance = Tracer.Instance;
68+
var exporterSettings = tracerInstance?.Settings?.Exporter;
69+
_cachedDogStatsDPipeName = exporterSettings?.MetricsPipeName;
70+
71+
if (string.IsNullOrEmpty(_cachedDogStatsDPipeName))
72+
{
73+
// Fallback: if tracer doesn't have a pipe name, generate one here
74+
// This shouldn't happen in normal flow, but provides safety
75+
_cachedDogStatsDPipeName = ServerlessCompatPipeNameHelper.GenerateUniquePipeName(
76+
returnValue,
77+
"dd_dogstatsd",
78+
"DogStatsD");
79+
Log.Warning("ServerlessCompat integration: Tracer DogStatsD pipe name not available, generated fallback: {PipeName}", _cachedDogStatsDPipeName);
80+
}
81+
else
82+
{
83+
Log.Information("ServerlessCompat integration: Using tracer's DogStatsD pipe name: {TracerPipeName}", _cachedDogStatsDPipeName);
84+
}
7085
}
7186
}
7287
}
@@ -81,7 +96,7 @@ internal static CallTargetReturn<string> OnMethodEnd<TTarget>(
8196
}
8297
catch (Exception ex)
8398
{
84-
Log.Error(ex, "ServerlessCompat integration: Error generating DogStatsD pipe name");
99+
Log.Error(ex, "ServerlessCompat integration: Error overriding DogStatsD pipe name");
85100
}
86101

87102
// Fallback to compat layer's original value

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Serverless/CompatibilityLayer_CalculateTracePipeName_Integration.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,32 @@ internal static CallTargetReturn<string> OnMethodEnd<TTarget>(
5656

5757
try
5858
{
59-
// Lazy generation: generate unique pipe name once when compat layer first calls this method
59+
// Get the tracer's pipe name (generated in ExporterSettings if on Windows with no explicit config)
60+
// Use lazy caching to avoid repeated lookups
6061
if (_cachedTracePipeName == null)
6162
{
6263
lock (_lock)
6364
{
6465
if (_cachedTracePipeName == null)
6566
{
66-
_cachedTracePipeName = ServerlessCompatPipeNameHelper.GenerateUniquePipeName(
67-
returnValue,
68-
"dd_trace",
69-
"trace");
67+
var tracerInstance = Tracer.Instance;
68+
var exporterSettings = tracerInstance?.Settings?.Exporter;
69+
_cachedTracePipeName = exporterSettings?.TracesPipeName;
70+
71+
if (string.IsNullOrEmpty(_cachedTracePipeName))
72+
{
73+
// Fallback: if tracer doesn't have a pipe name, generate one here
74+
// This shouldn't happen in normal flow, but provides safety
75+
_cachedTracePipeName = ServerlessCompatPipeNameHelper.GenerateUniquePipeName(
76+
returnValue,
77+
"dd_trace",
78+
"trace");
79+
Log.Warning("ServerlessCompat integration: Tracer pipe name not available, generated fallback: {PipeName}", _cachedTracePipeName);
80+
}
81+
else
82+
{
83+
Log.Information("ServerlessCompat integration: Using tracer's pipe name: {TracerPipeName}", _cachedTracePipeName);
84+
}
7085
}
7186
}
7287
}
@@ -81,7 +96,7 @@ internal static CallTargetReturn<string> OnMethodEnd<TTarget>(
8196
}
8297
catch (Exception ex)
8398
{
84-
Log.Error(ex, "ServerlessCompat integration: Error generating trace pipe name");
99+
Log.Error(ex, "ServerlessCompat integration: Error overriding trace pipe name");
85100
}
86101

87102
// Fallback to compat layer's original value

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

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,30 @@ internal ExporterSettings(Raw rawSettings, Func<string, bool> fileExists, IConfi
8787

8888
ValidationWarnings = new List<string>();
8989

90+
// Generate unique pipe names for Azure Functions (when not using AAS Site Extension) if not explicitly configured
91+
// This ensures multi-function scenarios don't conflict when using the compat layer
92+
// If names are explicitly configured, use them as-is
93+
var tracesPipeName = rawSettings.TracesPipeName;
94+
var metricsPipeName = rawSettings.MetricsPipeName;
95+
96+
if (Util.EnvironmentHelpers.IsAzureFunctions() && !Util.EnvironmentHelpers.IsUsingAzureAppServicesSiteExtension())
97+
{
98+
if (string.IsNullOrEmpty(tracesPipeName))
99+
{
100+
tracesPipeName = GenerateUniquePipeName("dd_trace");
101+
Log.Information("Azure Functions environment detected with no explicit trace pipe name. Generated unique pipe name: {TracesPipeName}", tracesPipeName);
102+
}
103+
104+
if (string.IsNullOrEmpty(metricsPipeName))
105+
{
106+
metricsPipeName = GenerateUniquePipeName("dd_dogstatsd");
107+
Log.Information("Azure Functions environment detected with no explicit metrics pipe name. Generated unique pipe name: {MetricsPipeName}", metricsPipeName);
108+
}
109+
}
110+
90111
var traceSettings = GetTraceTransport(
91112
agentUri: rawSettings.TraceAgentUri,
92-
tracesPipeName: rawSettings.TracesPipeName,
113+
tracesPipeName: tracesPipeName,
93114
agentHost: rawSettings.TraceAgentHost,
94115
agentPort: rawSettings.TraceAgentPort,
95116
tracesUnixDomainSocketPath: rawSettings.TracesUnixDomainSocketPath);
@@ -104,7 +125,7 @@ internal ExporterSettings(Raw rawSettings, Func<string, bool> fileExists, IConfi
104125
traceAgentUrl: rawSettings.TraceAgentUri,
105126
agentHost: rawSettings.TraceAgentHost,
106127
dogStatsdPort: rawSettings.DogStatsdPort,
107-
metricsPipeName: rawSettings.MetricsPipeName,
128+
metricsPipeName: metricsPipeName,
108129
metricsUnixDomainSocketPath: rawSettings.MetricsUnixDomainSocketPath);
109130

110131
MetricsHostname = metricsSettings.Hostname;
@@ -562,5 +583,30 @@ internal static Raw CreateUpdatedFromManualConfig(
562583
}
563584
}
564585
}
586+
587+
/// <summary>
588+
/// Generates a unique pipe name by appending a GUID to the base name.
589+
/// Used in Azure Functions to avoid conflicts when multiple functions run in the same hosting plan.
590+
/// </summary>
591+
/// <param name="baseName">The base name for the pipe</param>
592+
/// <returns>A unique pipe name in the format {base}_{guid}</returns>
593+
private static string GenerateUniquePipeName(string baseName)
594+
{
595+
// Validate base pipe name length before appending GUID
596+
// Windows pipe path format: \\.\pipe\{base}_{guid}
597+
// Max total: 256 - 9 (\\.\pipe\) - 1 (underscore) - 32 (GUID) = 214
598+
const int maxBaseLength = 214;
599+
600+
if (baseName.Length > maxBaseLength)
601+
{
602+
Log.Warning("Pipe base name exceeds {MaxLength} characters ({ActualLength}). Truncating to allow for GUID suffix.", maxBaseLength, baseName.Length);
603+
baseName = baseName.Substring(0, maxBaseLength);
604+
}
605+
606+
var guid = Guid.NewGuid().ToString("N"); // "N" format removes hyphens (32 chars)
607+
var uniqueName = $"{baseName}_{guid}";
608+
609+
return uniqueName;
610+
}
565611
}
566612
}

0 commit comments

Comments
 (0)