Skip to content

Commit

Permalink
Add better fallback for Lambda service name (#3378)
Browse files Browse the repository at this point in the history
* minor refactor: extract handler name variable immediately when running in Lambda

* Use provided handler assembly name as default fallback service name in AWS Lambda

* Remove explicit DD_SERVICE from handler containers

To verify that the fallback is used correctly

* Fix snapshot capitalisation
  • Loading branch information
andrewlock committed Oct 24, 2022
1 parent 0f7c26d commit 1e50298
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 131 deletions.
29 changes: 0 additions & 29 deletions docker-compose.serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -173,7 +172,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -197,7 +195,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -221,7 +218,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -245,7 +241,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -269,7 +264,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -293,7 +287,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -317,7 +310,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -341,7 +333,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -365,7 +356,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -389,7 +379,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -413,7 +402,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -437,7 +425,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -461,7 +448,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -485,7 +471,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -509,7 +494,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -533,7 +517,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -557,7 +540,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -581,7 +563,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -605,7 +586,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -629,7 +609,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -653,7 +632,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -677,7 +655,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -701,7 +678,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -725,7 +701,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -749,7 +724,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -773,7 +747,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -797,7 +770,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand All @@ -821,7 +793,6 @@ services:
- DUMMY_API_HOST=http://serverless-dummy-api:9005
- DD_INSTRUMENTATION_TELEMETRY_ENABLED=0
- DD_TRACE_DEBUG=1
- DD_SERVICE=Samples.Aws.Lambda
ports:
- "8080"
volumes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ namespace Datadog.Trace.ClrProfiler.ServerlessInstrumentation;

internal class LambdaHandler
{
private static readonly string[] Separator = { "::" };
internal const string Separator = "::";
private static readonly string[] Separators = { "::" };

internal LambdaHandler(string? handlerName)
{
Expand All @@ -22,7 +23,7 @@ internal LambdaHandler(string? handlerName)
ThrowHelper.ThrowArgumentNullException(nameof(handlerName));
}

var handlerTokens = handlerName.Split(Separator, StringSplitOptions.None);
var handlerTokens = handlerName.Split(Separators, StringSplitOptions.None);
if (handlerTokens.Length != 3)
{
ThrowHelper.ThrowArgumentException($"The handler name {handlerName} did not have the expected format A::B::C");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ namespace Datadog.Trace.ClrProfiler.ServerlessInstrumentation
internal static class Serverless
{
private const string DefinitionsId = "68224F20D001430F9400668DD25245BA";
private const string HandlerEnvName = "_HANDLER";
private const string LogLevelEnvName = "DD_LOG_LEVEL";

private static NativeCallTargetDefinition[] callTargetDefinitions = null;
Expand All @@ -22,44 +21,22 @@ internal static class Serverless

internal static void InitIfNeeded()
{
if (Metadata.IsRunningInLambda)
if (Metadata is { IsRunningInLambda: true, HandlerName: var handlerName })
{
if (string.IsNullOrEmpty(handlerName))
{
Error("Error initializing serverless integration: handler name not found");
return;
}

Debug("Sending CallTarget serverless integration definitions to native library.");
var serverlessDefinitions = GetServerlessDefinitions();
var serverlessDefinitions = GetServerlessDefinitions(handlerName);
NativeMethods.InitializeProfiler(DefinitionsId, serverlessDefinitions);

Debug("The profiler has been initialized with serverless definitions, count = " + serverlessDefinitions.Length);
}
}

internal static NativeCallTargetDefinition[] GetServerlessDefinitions()
{
try
{
if (callTargetDefinitions == null)
{
LambdaHandler handler = new LambdaHandler(EnvironmentHelpers.GetEnvironmentVariable(HandlerEnvName));
var assemblyName = typeof(InstrumentationDefinitions).Assembly.FullName;
var paramCount = handler.ParamTypeArray.Length;

var integrationType = GetIntegrationType(handler.ParamTypeArray[0], paramCount);
callTargetDefinitions = new NativeCallTargetDefinition[]
{
new(handler.Assembly, handler.FullType, handler.MethodName, handler.ParamTypeArray, 0, 0, 0, 65535, 65535, 65535, assemblyName, integrationType)
};

LifetimeManager.Instance.AddShutdownTask(RunShutdown);
}

return callTargetDefinitions;
}
catch (Exception ex)
{
Error("Impossible to get Serverless Definitions", ex);
return Array.Empty<NativeCallTargetDefinition>();
}
}

internal static string GetIntegrationType(string returnType, int paramCount)
{
var inputParamCount = paramCount - 1; // since the return type is in the array
Expand Down Expand Up @@ -144,22 +121,57 @@ private static void RunShutdown()
callTargetDefinitions = null;
}

private static NativeCallTargetDefinition[] GetServerlessDefinitions(string handlerName)
{
try
{
if (callTargetDefinitions == null)
{
LambdaHandler handler = new LambdaHandler(handlerName);
var assemblyName = typeof(InstrumentationDefinitions).Assembly.FullName;
var paramCount = handler.ParamTypeArray.Length;

var integrationType = GetIntegrationType(handler.ParamTypeArray[0], paramCount);
callTargetDefinitions = new NativeCallTargetDefinition[]
{
new(handler.Assembly, handler.FullType, handler.MethodName, handler.ParamTypeArray, 0, 0, 0, 65535, 65535, 65535, assemblyName, integrationType)
};

LifetimeManager.Instance.AddShutdownTask(RunShutdown);
}

return callTargetDefinitions;
}
catch (Exception ex)
{
Error("Impossible to get Serverless Definitions", ex);
return Array.Empty<NativeCallTargetDefinition>();
}
}

internal class LambdaMetadata
{
private const string ExtensionEnvName = "_DD_EXTENSION_PATH";
private const string ExtensionFullPath = "/opt/extensions/datadog-agent";
private const string FunctionEnvame = "AWS_LAMBDA_FUNCTION_NAME";
private const string HandlerEnvName = "_HANDLER";

public LambdaMetadata(bool isRunningInLambda, string functionName)
private LambdaMetadata(bool isRunningInLambda, string functionName, string handlerName, string serviceName)
{
IsRunningInLambda = isRunningInLambda;
FunctionName = functionName;
HandlerName = handlerName;
ServiceName = serviceName;
}

public bool IsRunningInLambda { get; }

public string FunctionName { get; }

public string HandlerName { get; }

public string ServiceName { get; }

/// <summary>
/// Gets the paths we don't want to trace when running in Lambda
/// </summary>
Expand All @@ -173,7 +185,23 @@ public static LambdaMetadata Create(string extensionPath = ExtensionFullPath)
&& File.Exists(
EnvironmentHelpers.GetEnvironmentVariable(ExtensionEnvName)
?? extensionPath);
return new LambdaMetadata(isRunningInLambda, functionName);

if (!isRunningInLambda)
{
// the other values are irrelevant, so don't bother setting them
return new LambdaMetadata(isRunningInLambda: false, functionName, handlerName: null, serviceName: null);
}

var handlerName = EnvironmentHelpers.GetEnvironmentVariable(HandlerEnvName);
var serviceName = handlerName?.IndexOf(LambdaHandler.Separator, StringComparison.Ordinal) switch
{
null => null, // not provided
0 => null, // invalid handler name (no assembly)
-1 => handlerName, // top level function style
{ } i => handlerName.Substring(0, i), // three part function style
};

return new LambdaMetadata(isRunningInLambda: true, functionName, handlerName, serviceName);
}
}
}
Expand Down
Loading

0 comments on commit 1e50298

Please sign in to comment.