diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md index 9e229ec742..6c27457bc7 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +* Trace instrumentation will not fail with an exception + if empty `LambdaContext` instance is passed. + ([#2457](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2457)) + ## 1.10.0-rc.1 Released 2025-Jan-06 diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index 9f9d228034..b4140eb89e 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -170,14 +170,19 @@ internal IEnumerable> GetFunctionTags(TInpu return items.Length >= 5 ? items[4] : null; } - private static string GetFaasId(string functionArn) + private static string? GetFaasId(string? functionArn) { + if (string.IsNullOrEmpty(functionArn)) + { + return null; + } + var faasId = functionArn; // According to faas.id description https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/instrumentation/aws-lambda.md#all-triggers // the 8th part of arn (function version or alias, see https://docs.aws.amazon.com/lambda/latest/dg/lambda-api-permissions-ref.html) // should not be included into faas.id - var items = functionArn.Split(':'); + var items = functionArn!.Split(':'); if (items.Length >= 8) { faasId = string.Join(":", items.Take(7)); diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index fa013b2f48..b9bce2cf47 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -264,6 +264,35 @@ public void OnFunctionStart_ColdStart_ColdStartTagHasCorrectValue(int invocation Assert.Contains(activity.TagObjects, x => x.Key == ExpectedSemanticConventions.AttributeFaasColdStart && expectedColdStartValue.Equals(x.Value)); } + [Fact] + public async Task TraceAsyncDoesNotCrashForEmptyLambdaContext() + { + var emptyLambdaContext = new SampleLambdaContext + { + AwsRequestId = null!, + ClientContext = null, + FunctionName = null!, + FunctionVersion = null!, + Identity = null!, + InvokedFunctionArn = null!, + Logger = null!, + LogGroupName = null!, + LogStreamName = null!, + MemoryLimitInMB = 0, + RemainingTime = TimeSpan.Zero, + }; + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations(opt => + { + opt.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) + .Build(); + + // We simply verify that no exception is thrown here. + await AWSLambdaWrapper.TraceAsync(tracerProvider, this.sampleHandlers.SampleHandlerAsyncInputAndNoReturn, "TestStream", emptyLambdaContext); + } + private static ActivityContext CreateParentContext() { var traceId = ActivityTraceId.CreateFromString(TraceId.AsSpan()); diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/SampleLambdaContext.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/SampleLambdaContext.cs index 792ba8d606..18bc32fc3d 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/SampleLambdaContext.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/SampleLambdaContext.cs @@ -7,25 +7,25 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Tests; internal class SampleLambdaContext : ILambdaContext { - public string AwsRequestId { get; } = "testrequestid"; + public string AwsRequestId { get; set; } = "testrequestid"; - public IClientContext? ClientContext { get; } + public IClientContext? ClientContext { get; set; } - public string FunctionName { get; } = "testfunction"; + public string FunctionName { get; set; } = "testfunction"; - public string FunctionVersion { get; } = "latest"; + public string FunctionVersion { get; set; } = "latest"; - public ICognitoIdentity? Identity { get; } + public ICognitoIdentity? Identity { get; set; } - public string InvokedFunctionArn { get; } = "arn:aws:lambda:us-east-1:111111111111:function:testfunction"; + public string InvokedFunctionArn { get; set; } = "arn:aws:lambda:us-east-1:111111111111:function:testfunction"; - public ILambdaLogger? Logger { get; } + public ILambdaLogger? Logger { get; set; } - public string? LogGroupName { get; } + public string? LogGroupName { get; set; } - public string? LogStreamName { get; } + public string? LogStreamName { get; set; } - public int MemoryLimitInMB { get; } + public int MemoryLimitInMB { get; set; } - public TimeSpan RemainingTime { get; } + public TimeSpan RemainingTime { get; set; } }