From 2e8d92f43fd4f47537f9769151ee2a52930c8710 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Tue, 7 Jun 2022 18:03:21 +0200 Subject: [PATCH 01/24] #403 - added optional parent context and tags parameters to tracing methods of AWSLambdaWrapper - changed parent related behaviour of OnFunctionStart method - added option flag for ignoring X-Ray propagation --- .../AWSLambdaInstrumentationOptions.cs | 31 +++ .../Implementation/AWSLambdaWrapper.cs | 213 ++++++++++++++---- .../TracerProviderBuilderExtensions.cs | 12 +- 3 files changed, 208 insertions(+), 48 deletions(-) create mode 100644 src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs new file mode 100644 index 0000000000..f2b61bc231 --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs @@ -0,0 +1,31 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Contrib.Instrumentation.AWSLambda +{ + /// + /// Options for AWS lambda instrumentation. + /// + public class AWSLambdaInstrumentationOptions + { + /// + /// Gets or sets a value indicating whether AWS X-Ray propagation is ignored. + /// This option has to be used as a workaround until resolution of the issue + /// https://github.com/open-telemetry/opentelemetry-dotnet/issues/3290. + /// + public bool IgnoreAWSXRayPropagation { get; set; } + } +} diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index cab174c835..6b5c584dde 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -15,6 +15,7 @@ // using System; +using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using Amazon.Lambda.Core; @@ -27,7 +28,12 @@ namespace OpenTelemetry.Contrib.Instrumentation.AWSLambda.Implementation /// public class AWSLambdaWrapper { - private static readonly ActivitySource AWSLambdaActivitySource = new ActivitySource(AWSLambdaUtils.ActivitySourceName); + private static readonly ActivitySource AWSLambdaActivitySource = new(AWSLambdaUtils.ActivitySourceName); + + /// + /// Gets or sets a value indicating whether AWS X-Ray propagation is ignored. + /// + internal static bool IgnoreAWSXRayPropagation { get; set; } /// /// Tracing wrapper for Lambda handler without Lambda context. @@ -37,10 +43,21 @@ public class AWSLambdaWrapper /// TracerProvider passed in. /// Lambda handler function passed in. /// Instance of input. + /// + /// The optional parent context used for Activity object creation. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent + /// if configuration flag is not set to true. + /// + /// The optional tags list to initialize the created Activity object with. /// Instance of output result. - public static TResult Trace(TracerProvider tracerProvider, Func lambdaHandler, TInput input) + public static TResult Trace( + TracerProvider tracerProvider, + Func lambdaHandler, + TInput input, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - return Intercept(tracerProvider, () => lambdaHandler(input)); + return Intercept(tracerProvider, () => lambdaHandler(input), default, parentContext, tags); } /// @@ -50,9 +67,20 @@ public static TResult Trace(TracerProvider tracerProvider, Func /// TracerProvider passed in. /// Lambda handler function passed in. /// Instance of input. - public static void Trace(TracerProvider tracerProvider, Action lambdaHandler, TInput input) + /// + /// The optional parent context used for Activity object creation. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent + /// if configuration flag is not set to true. + /// + /// The optional tags list to initialize the created Activity object with. + public static void Trace( + TracerProvider tracerProvider, + Action lambdaHandler, + TInput input, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - Intercept(tracerProvider, () => lambdaHandler(input)); + Intercept(tracerProvider, () => lambdaHandler(input), default, parentContext, tags); } /// @@ -62,10 +90,21 @@ public static void Trace(TracerProvider tracerProvider, Action l /// TracerProvider passed in. /// Lambda handler function passed in. /// Instance of input. + /// + /// The optional parent context used for Activity object creation. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent + /// if configuration flag is not set to true. + /// + /// The optional tags list to initialize the created Activity object with. /// Task. - public static async Task Trace(TracerProvider tracerProvider, Func lambdaHandler, TInput input) + public static async Task Trace( + TracerProvider tracerProvider, + Func lambdaHandler, + TInput input, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - await Intercept(tracerProvider, () => lambdaHandler(input)); + await Intercept(tracerProvider, () => lambdaHandler(input), default, parentContext, tags); } /// @@ -76,10 +115,21 @@ public static async Task Trace(TracerProvider tracerProvider, FuncTracerProvider passed in. /// Lambda handler function passed in. /// Instance of input. + /// + /// The optional parent context used for Activity object creation. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent + /// if configuration flag is not set to true. + /// + /// The optional tags list to initialize the created Activity object with. /// Task of result. - public static async Task Trace(TracerProvider tracerProvider, Func> lambdaHandler, TInput input) + public static async Task Trace( + TracerProvider tracerProvider, + Func> lambdaHandler, + TInput input, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - return await Intercept(tracerProvider, () => lambdaHandler(input)); + return await Intercept(tracerProvider, () => lambdaHandler(input), default, default, tags); } /// @@ -91,10 +141,22 @@ public static async Task Trace(TracerProvider tracerPr /// Lambda handler function passed in. /// Instance of input. /// Instance of lambda context. + /// + /// The optional parent context used for Activity object creation. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent + /// if configuration flag is not set to true. + /// + /// The optional tags list to initialize the created Activity object with. /// Instance of output result. - public static TResult Trace(TracerProvider tracerProvider, Func lambdaHandler, TInput input, ILambdaContext context) + public static TResult Trace( + TracerProvider tracerProvider, + Func lambdaHandler, + TInput input, + ILambdaContext context, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - return Intercept(tracerProvider, () => lambdaHandler(input, context), context); + return Intercept(tracerProvider, () => lambdaHandler(input, context), context, parentContext, tags); } /// @@ -105,9 +167,21 @@ public static TResult Trace(TracerProvider tracerProvider, Func /// Lambda handler function passed in. /// Instance of input. /// Instance of lambda context. - public static void Trace(TracerProvider tracerProvider, Action lambdaHandler, TInput input, ILambdaContext context) + /// + /// The optional parent context used for Activity object creation. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent + /// if configuration flag is not set to true. + /// + /// The optional tags list to initialize the created Activity object with. + public static void Trace( + TracerProvider tracerProvider, + Action lambdaHandler, + TInput input, + ILambdaContext context, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - Intercept(tracerProvider, () => lambdaHandler(input, context), context); + Intercept(tracerProvider, () => lambdaHandler(input, context), context, parentContext, tags); } /// @@ -118,10 +192,22 @@ public static void Trace(TracerProvider tracerProvider, ActionLambda handler function passed in. /// Instance of input. /// Instance of lambda context. + /// + /// The optional parent context used for Activity object creation. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent + /// if configuration flag is not set to true. + /// + /// The optional tags list to initialize the created Activity object with. /// Task. - public static async Task Trace(TracerProvider tracerProvider, Func lambdaHandler, TInput input, ILambdaContext context) + public static async Task Trace( + TracerProvider tracerProvider, + Func lambdaHandler, + TInput input, + ILambdaContext context, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - await Intercept(tracerProvider, () => lambdaHandler(input, context), context); + await Intercept(tracerProvider, () => lambdaHandler(input, context), context, parentContext, tags); } /// @@ -133,15 +219,32 @@ public static async Task Trace(TracerProvider tracerProvider, FuncLambda handler function passed in. /// Instance of input. /// Instance of lambda context. + /// + /// The optional parent context used for Activity object creation. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent + /// if configuration flag is not set to true. + /// + /// The optional tags list to initialize the created Activity object with. /// Task of result. - public static async Task Trace(TracerProvider tracerProvider, Func> lambdaHandler, TInput input, ILambdaContext context) + public static async Task Trace( + TracerProvider tracerProvider, + Func> lambdaHandler, + TInput input, + ILambdaContext context, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - return await Intercept(tracerProvider, () => lambdaHandler(input, context), context); + return await Intercept(tracerProvider, () => lambdaHandler(input, context), context, parentContext, tags); } - private static TResult Intercept(TracerProvider tracerProvider, Func method, ILambdaContext context = null) + private static TResult Intercept( + TracerProvider tracerProvider, + Func method, + ILambdaContext context = null, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - var lambdaActivity = OnFunctionStart(context); + var lambdaActivity = OnFunctionStart(context, parentContext, tags); try { return method(); @@ -158,9 +261,14 @@ private static TResult Intercept(TracerProvider tracerProvider, Func> tags = null) { - var lambdaActivity = OnFunctionStart(context); + var lambdaActivity = OnFunctionStart(context, parentContext, tags); try { method(); @@ -177,9 +285,14 @@ private static void Intercept(TracerProvider tracerProvider, Action method, ILam } } - private static async Task Intercept(TracerProvider tracerProvider, Func> method, ILambdaContext context = null) + private static async Task Intercept( + TracerProvider tracerProvider, + Func> method, + ILambdaContext context = null, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - var lambdaActivity = OnFunctionStart(context); + var lambdaActivity = OnFunctionStart(context, parentContext, tags); try { return await method(); @@ -196,9 +309,14 @@ private static async Task Intercept(TracerProvider tracerProvi } } - private static async Task Intercept(TracerProvider tracerProvider, Func method, ILambdaContext context = null) + private static async Task Intercept( + TracerProvider tracerProvider, + Func method, + ILambdaContext context = null, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - var lambdaActivity = OnFunctionStart(context); + var lambdaActivity = OnFunctionStart(context, parentContext, tags); try { await method(); @@ -215,35 +333,36 @@ private static async Task Intercept(TracerProvider tracerProvider, Func me } } - private static Activity OnFunctionStart(ILambdaContext context = null) + private static Activity OnFunctionStart( + ILambdaContext context = null, + ActivityContext parentContext = default, + IEnumerable> tags = null) { - Activity activity = null; - - var parentContext = AWSLambdaUtils.GetParentContext(); - if (parentContext != default) + if (parentContext == default && !IgnoreAWSXRayPropagation) { - var activityName = AWSLambdaUtils.GetFunctionName(context); - activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext); + parentContext = AWSLambdaUtils.GetParentContext(); + } - if (activity != null && context != null) + var activityName = AWSLambdaUtils.GetFunctionName(context); + var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, tags); + if (activity != null && context != null) + { + if (activity.IsAllDataRequested) { - if (activity.IsAllDataRequested) + if (context.AwsRequestId != null) { - if (context.AwsRequestId != null) - { - activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasExecution, context.AwsRequestId); - } + activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasExecution, context.AwsRequestId); + } - var functionArn = context.InvokedFunctionArn; - if (functionArn != null) - { - activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasID, functionArn); + var functionArn = context.InvokedFunctionArn; + if (functionArn != null) + { + activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasID, functionArn); - var accountId = AWSLambdaUtils.GetAccountId(functionArn); - if (accountId != null) - { - activity.SetTag(AWSLambdaSemanticConventions.AttributeCloudAccountID, accountId); - } + var accountId = AWSLambdaUtils.GetAccountId(functionArn); + if (accountId != null) + { + activity.SetTag(AWSLambdaSemanticConventions.AttributeCloudAccountID, accountId); } } } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs index 7cd573a766..40be76a6f1 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs @@ -14,6 +14,8 @@ // limitations under the License. // +using System; +using OpenTelemetry.Contrib.Instrumentation.AWSLambda; using OpenTelemetry.Contrib.Instrumentation.AWSLambda.Implementation; using OpenTelemetry.Internal; using OpenTelemetry.Resources; @@ -29,11 +31,19 @@ public static class TracerProviderBuilderExtensions /// Add AWS Lambda configurations. /// /// being configured. + /// . /// The instance of to chain the calls. - public static TracerProviderBuilder AddAWSLambdaConfigurations(this TracerProviderBuilder builder) + public static TracerProviderBuilder AddAWSLambdaConfigurations( + this TracerProviderBuilder builder, + Action configure = null) { Guard.ThrowIfNull(builder); + var options = new AWSLambdaInstrumentationOptions(); + configure?.Invoke(options); + + AWSLambdaWrapper.IgnoreAWSXRayPropagation = options.IgnoreAWSXRayPropagation; + builder.AddSource(AWSLambdaUtils.ActivitySourceName); builder.SetResourceBuilder(ResourceBuilder .CreateEmpty() From bbf6448efff74e2cee243d93974e6327b9673bfd Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Wed, 8 Jun 2022 11:50:01 +0200 Subject: [PATCH 02/24] - removed flag for ignoring x-ray propagation: x-ray is used as a fallback when parent context is not provided (#403) --- .../AWSLambdaInstrumentationOptions.cs | 31 ----------------- .../Implementation/AWSLambdaWrapper.cs | 33 ++++++------------- .../TracerProviderBuilderExtensions.cs | 10 +----- 3 files changed, 11 insertions(+), 63 deletions(-) delete mode 100644 src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs deleted file mode 100644 index f2b61bc231..0000000000 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace OpenTelemetry.Contrib.Instrumentation.AWSLambda -{ - /// - /// Options for AWS lambda instrumentation. - /// - public class AWSLambdaInstrumentationOptions - { - /// - /// Gets or sets a value indicating whether AWS X-Ray propagation is ignored. - /// This option has to be used as a workaround until resolution of the issue - /// https://github.com/open-telemetry/opentelemetry-dotnet/issues/3290. - /// - public bool IgnoreAWSXRayPropagation { get; set; } - } -} diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 6b5c584dde..acf370ea3d 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -30,11 +30,6 @@ public class AWSLambdaWrapper { private static readonly ActivitySource AWSLambdaActivitySource = new(AWSLambdaUtils.ActivitySourceName); - /// - /// Gets or sets a value indicating whether AWS X-Ray propagation is ignored. - /// - internal static bool IgnoreAWSXRayPropagation { get; set; } - /// /// Tracing wrapper for Lambda handler without Lambda context. /// @@ -45,8 +40,7 @@ public class AWSLambdaWrapper /// Instance of input. /// /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent - /// if configuration flag is not set to true. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// /// The optional tags list to initialize the created Activity object with. /// Instance of output result. @@ -69,8 +63,7 @@ public static TResult Trace( /// Instance of input. /// /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent - /// if configuration flag is not set to true. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// /// The optional tags list to initialize the created Activity object with. public static void Trace( @@ -92,8 +85,7 @@ public static void Trace( /// Instance of input. /// /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent - /// if configuration flag is not set to true. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// /// The optional tags list to initialize the created Activity object with. /// Task. @@ -117,8 +109,7 @@ public static async Task Trace( /// Instance of input. /// /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent - /// if configuration flag is not set to true. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// /// The optional tags list to initialize the created Activity object with. /// Task of result. @@ -129,7 +120,7 @@ public static async Task Trace( ActivityContext parentContext = default, IEnumerable> tags = null) { - return await Intercept(tracerProvider, () => lambdaHandler(input), default, default, tags); + return await Intercept(tracerProvider, () => lambdaHandler(input), default, parentContext, tags); } /// @@ -143,8 +134,7 @@ public static async Task Trace( /// Instance of lambda context. /// /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent - /// if configuration flag is not set to true. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// /// The optional tags list to initialize the created Activity object with. /// Instance of output result. @@ -169,8 +159,7 @@ public static TResult Trace( /// Instance of lambda context. /// /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent - /// if configuration flag is not set to true. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// /// The optional tags list to initialize the created Activity object with. public static void Trace( @@ -194,8 +183,7 @@ public static void Trace( /// Instance of lambda context. /// /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent - /// if configuration flag is not set to true. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// /// The optional tags list to initialize the created Activity object with. /// Task. @@ -221,8 +209,7 @@ public static async Task Trace( /// Instance of lambda context. /// /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent - /// if configuration flag is not set to true. + /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// /// The optional tags list to initialize the created Activity object with. /// Task of result. @@ -338,7 +325,7 @@ private static Activity OnFunctionStart( ActivityContext parentContext = default, IEnumerable> tags = null) { - if (parentContext == default && !IgnoreAWSXRayPropagation) + if (parentContext == default) { parentContext = AWSLambdaUtils.GetParentContext(); } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs index 40be76a6f1..8ff15fa489 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs @@ -31,19 +31,11 @@ public static class TracerProviderBuilderExtensions /// Add AWS Lambda configurations. /// /// being configured. - /// . /// The instance of to chain the calls. - public static TracerProviderBuilder AddAWSLambdaConfigurations( - this TracerProviderBuilder builder, - Action configure = null) + public static TracerProviderBuilder AddAWSLambdaConfigurations(this TracerProviderBuilder builder) { Guard.ThrowIfNull(builder); - var options = new AWSLambdaInstrumentationOptions(); - configure?.Invoke(options); - - AWSLambdaWrapper.IgnoreAWSXRayPropagation = options.IgnoreAWSXRayPropagation; - builder.AddSource(AWSLambdaUtils.ActivitySourceName); builder.SetResourceBuilder(ResourceBuilder .CreateEmpty() From f7a357141b352942145d5572db229504c260c3e5 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Wed, 8 Jun 2022 17:15:51 +0200 Subject: [PATCH 03/24] extended AWSLambdaWrapper unit tests (#403) --- .../Implementation/AWSLambdaWrapper.cs | 122 +++++++------- .../TracerProviderBuilderExtensions.cs | 2 - .../AWSLambdaWrapperTests.cs | 151 +++++++++++++----- 3 files changed, 172 insertions(+), 103 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index acf370ea3d..8e0c08c528 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -224,6 +224,67 @@ public static async Task Trace( return await Intercept(tracerProvider, () => lambdaHandler(input, context), context, parentContext, tags); } + internal static Activity OnFunctionStart( + ILambdaContext context = null, + ActivityContext parentContext = default, + IEnumerable> tags = null) + { + if (parentContext == default) + { + parentContext = AWSLambdaUtils.GetParentContext(); + } + + var activityName = AWSLambdaUtils.GetFunctionName(context); + var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, tags); + if (activity != null && context != null) + { + if (activity.IsAllDataRequested) + { + if (context.AwsRequestId != null) + { + activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasExecution, context.AwsRequestId); + } + + var functionArn = context.InvokedFunctionArn; + if (functionArn != null) + { + activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasID, functionArn); + + var accountId = AWSLambdaUtils.GetAccountId(functionArn); + if (accountId != null) + { + activity.SetTag(AWSLambdaSemanticConventions.AttributeCloudAccountID, accountId); + } + } + } + } + + return activity; + } + + private static void OnFunctionStop(Activity activity, TracerProvider tracerProvider) + { + if (activity != null) + { + activity.Stop(); + } + + // force flush before function quit in case of Lambda freeze. + tracerProvider.ForceFlush(); + } + + private static void OnException(Activity activity, Exception exception) + { + if (activity != null) + { + if (activity.IsAllDataRequested) + { + activity.RecordException(exception); + activity.SetStatus(Status.Error.WithDescription(exception.Message)); + } + } + } + private static TResult Intercept( TracerProvider tracerProvider, Func method, @@ -319,66 +380,5 @@ private static async Task Intercept( OnFunctionStop(lambdaActivity, tracerProvider); } } - - private static Activity OnFunctionStart( - ILambdaContext context = null, - ActivityContext parentContext = default, - IEnumerable> tags = null) - { - if (parentContext == default) - { - parentContext = AWSLambdaUtils.GetParentContext(); - } - - var activityName = AWSLambdaUtils.GetFunctionName(context); - var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, tags); - if (activity != null && context != null) - { - if (activity.IsAllDataRequested) - { - if (context.AwsRequestId != null) - { - activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasExecution, context.AwsRequestId); - } - - var functionArn = context.InvokedFunctionArn; - if (functionArn != null) - { - activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasID, functionArn); - - var accountId = AWSLambdaUtils.GetAccountId(functionArn); - if (accountId != null) - { - activity.SetTag(AWSLambdaSemanticConventions.AttributeCloudAccountID, accountId); - } - } - } - } - - return activity; - } - - private static void OnFunctionStop(Activity activity, TracerProvider tracerProvider) - { - if (activity != null) - { - activity.Stop(); - } - - // force flush before function quit in case of Lambda freeze. - tracerProvider.ForceFlush(); - } - - private static void OnException(Activity activity, Exception exception) - { - if (activity != null) - { - if (activity.IsAllDataRequested) - { - activity.RecordException(exception); - activity.SetStatus(Status.Error.WithDescription(exception.Message)); - } - } - } } } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs index 8ff15fa489..7cd573a766 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs @@ -14,8 +14,6 @@ // limitations under the License. // -using System; -using OpenTelemetry.Contrib.Instrumentation.AWSLambda; using OpenTelemetry.Contrib.Instrumentation.AWSLambda.Implementation; using OpenTelemetry.Internal; using OpenTelemetry.Resources; diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index 4971e4d761..8a8082c91e 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -15,6 +15,7 @@ // using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -28,6 +29,10 @@ namespace OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests { public class AWSLambdaWrapperTests { + private const string TraceId = "5759e988bd862e3fe1be46a994272793"; + private const string XRayParentId = "53995c3f42cd8ad8"; + private const string CustomParentId = "11195c3f42cd8222"; + private readonly SampleHandlers sampleHandlers; private readonly SampleLambdaContext sampleLambdaContext; @@ -35,14 +40,16 @@ public AWSLambdaWrapperTests() { this.sampleHandlers = new SampleHandlers(); this.sampleLambdaContext = new SampleLambdaContext(); - Environment.SetEnvironmentVariable("_X_AMZN_TRACE_ID", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1"); + Environment.SetEnvironmentVariable("_X_AMZN_TRACE_ID", $"Root=1-5759e988-bd862e3fe1be46a994272793;Parent={XRayParentId};Sampled=1"); Environment.SetEnvironmentVariable("AWS_REGION", "us-east-1"); Environment.SetEnvironmentVariable("AWS_LAMBDA_FUNCTION_NAME", "testfunction"); Environment.SetEnvironmentVariable("AWS_LAMBDA_FUNCTION_VERSION", "latest"); } - [Fact] - public void TestLambdaHandler() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestLambdaHandler(bool setCustomParent) { var processor = new Mock>(); @@ -51,7 +58,9 @@ public void TestLambdaHandler() .AddProcessor(processor.Object) .Build()) { - var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", this.sampleLambdaContext); + var tags = CreateTags(); + var parentContext = setCustomParent ? CreateParentContext() : default; + var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", this.sampleLambdaContext, parentContext, tags); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -60,12 +69,14 @@ public void TestLambdaHandler() Assert.Equal(6, processor.Invocations.Count); var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity); + this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); this.AssertSpanAttributes(activity); } - [Fact] - public void TestLambdaHandlerNoReturn() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestLambdaHandlerNoReturn(bool setCustomParent) { var processor = new Mock>(); @@ -74,7 +85,9 @@ public void TestLambdaHandlerNoReturn() .AddProcessor(processor.Object) .Build()) { - AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", this.sampleLambdaContext); + var tags = CreateTags(); + var parentContext = setCustomParent ? CreateParentContext() : default; + AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", this.sampleLambdaContext, parentContext, tags); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -83,12 +96,14 @@ public void TestLambdaHandlerNoReturn() Assert.Equal(6, processor.Invocations.Count); var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity); + this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); this.AssertSpanAttributes(activity); } - [Fact] - public async Task TestLambdaHandlerAsync() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task TestLambdaHandlerAsync(bool setCustomParent) { var processor = new Mock>(); @@ -97,7 +112,9 @@ public async Task TestLambdaHandlerAsync() .AddProcessor(processor.Object) .Build()) { - var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", this.sampleLambdaContext); + var tags = CreateTags(); + var parentContext = setCustomParent ? CreateParentContext() : default; + var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", this.sampleLambdaContext, parentContext, tags); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -106,12 +123,14 @@ public async Task TestLambdaHandlerAsync() Assert.Equal(6, processor.Invocations.Count); var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity); + this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); this.AssertSpanAttributes(activity); } - [Fact] - public async Task TestLambdaHandlerAsyncNoReturn() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task TestLambdaHandlerAsyncNoReturn(bool setCustomParent) { var processor = new Mock>(); @@ -120,7 +139,9 @@ public async Task TestLambdaHandlerAsyncNoReturn() .AddProcessor(processor.Object) .Build()) { - await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", this.sampleLambdaContext); + var tags = CreateTags(); + var parentContext = setCustomParent ? CreateParentContext() : default; + await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", this.sampleLambdaContext, parentContext, tags); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -129,12 +150,14 @@ public async Task TestLambdaHandlerAsyncNoReturn() Assert.Equal(6, processor.Invocations.Count); var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity); + this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); this.AssertSpanAttributes(activity); } - [Fact] - public void TestLambdaHandlerNoContext() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestLambdaHandlerNoContext(bool setCustomParent) { var processor = new Mock>(); @@ -143,7 +166,9 @@ public void TestLambdaHandlerNoContext() .AddProcessor(processor.Object) .Build()) { - var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream"); + var tags = CreateTags(); + var parentContext = setCustomParent ? CreateParentContext() : default; + var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", parentContext, tags); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -152,11 +177,13 @@ public void TestLambdaHandlerNoContext() Assert.Equal(6, processor.Invocations.Count); var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity); + this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); } - [Fact] - public void TestLambdaHandlerNoContextNoReturn() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestLambdaHandlerNoContextNoReturn(bool setCustomParent) { var processor = new Mock>(); @@ -165,7 +192,9 @@ public void TestLambdaHandlerNoContextNoReturn() .AddProcessor(processor.Object) .Build()) { - AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream"); + var tags = CreateTags(); + var parentContext = setCustomParent ? CreateParentContext() : default; + AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", parentContext, tags); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -174,11 +203,13 @@ public void TestLambdaHandlerNoContextNoReturn() Assert.Equal(6, processor.Invocations.Count); var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity); + this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); } - [Fact] - public async Task TestLambdaHandlerAsyncNoContext() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task TestLambdaHandlerAsyncNoContext(bool setCustomParent) { var processor = new Mock>(); @@ -187,7 +218,9 @@ public async Task TestLambdaHandlerAsyncNoContext() .AddProcessor(processor.Object) .Build()) { - var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream"); + var tags = CreateTags(); + var parentContext = setCustomParent ? CreateParentContext() : default; + var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", parentContext, tags); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -196,11 +229,13 @@ public async Task TestLambdaHandlerAsyncNoContext() Assert.Equal(6, processor.Invocations.Count); var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity); + this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); } - [Fact] - public async Task TestLambdaHandlerAsyncNoContextNoReturn() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task TestLambdaHandlerAsyncNoContextNoReturn(bool setCustomParent) { var processor = new Mock>(); @@ -209,7 +244,9 @@ public async Task TestLambdaHandlerAsyncNoContextNoReturn() .AddProcessor(processor.Object) .Build()) { - await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream"); + var tags = CreateTags(); + var parentContext = setCustomParent ? CreateParentContext() : default; + await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", parentContext, tags); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -218,11 +255,13 @@ public async Task TestLambdaHandlerAsyncNoContextNoReturn() Assert.Equal(6, processor.Invocations.Count); var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity); + this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); } - [Fact] - public void TestLambdaHandlerException() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestLambdaHandlerException(bool setCustomParent) { var processor = new Mock>(); @@ -233,7 +272,9 @@ public void TestLambdaHandlerException() { try { - AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturnException, "TestException", this.sampleLambdaContext); + var tags = CreateTags(); + var parentContext = setCustomParent ? CreateParentContext() : default; + AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturnException, "TestException", this.sampleLambdaContext, parentContext, tags); } catch { @@ -246,7 +287,7 @@ public void TestLambdaHandlerException() Assert.Equal(6, processor.Invocations.Count); var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity); + this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); this.AssertSpanAttributes(activity); this.AssertSpanException(activity); } @@ -275,10 +316,39 @@ public void TestLambdaHandlerNotSampled() Assert.True(activities.Length == 0); } - private void AssertSpanProperties(Activity activity) + [Fact] + public void OnFunctionStart_NoParent_ActivityCreated() + { + Environment.SetEnvironmentVariable("_X_AMZN_TRACE_ID", null); + + // var processor = new Mock>(); + Activity activity = null; + using (var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations() + .Build()) + { + activity = AWSLambdaWrapper.OnFunctionStart(); + } + + Assert.NotNull(activity); + } + + private static ActivityContext CreateParentContext() + { + var traceId = ActivityTraceId.CreateFromString(TraceId.AsSpan()); + var parentId = ActivitySpanId.CreateFromString(CustomParentId.AsSpan()); + return new ActivityContext(traceId, parentId, ActivityTraceFlags.Recorded); + } + + private static IEnumerable> CreateTags() + { + return new[] { new KeyValuePair("TestTag", "TagValue"), }; + } + + private void AssertSpanProperties(Activity activity, string parentId) { - Assert.Equal("5759e988bd862e3fe1be46a994272793", activity.TraceId.ToHexString()); - Assert.Equal("53995c3f42cd8ad8", activity.ParentSpanId.ToHexString()); + Assert.Equal(TraceId, activity.TraceId.ToHexString()); + Assert.Equal(parentId, activity.ParentSpanId.ToHexString()); Assert.Equal(ActivityTraceFlags.Recorded, activity.ActivityTraceFlags); Assert.Equal(ActivityKind.Server, activity.Kind); Assert.Equal("testfunction", activity.DisplayName); @@ -298,6 +368,7 @@ private void AssertSpanAttributes(Activity activity) Assert.Equal(this.sampleLambdaContext.AwsRequestId, activity.GetTagValue(AWSLambdaSemanticConventions.AttributeFaasExecution)); Assert.Equal(this.sampleLambdaContext.InvokedFunctionArn, activity.GetTagValue(AWSLambdaSemanticConventions.AttributeFaasID)); Assert.Equal("111111111111", activity.GetTagValue(AWSLambdaSemanticConventions.AttributeCloudAccountID)); + Assert.Equal("TagValue", activity.GetTagValue("TestTag")); } private void AssertSpanException(Activity activity) From ad6d9b24c6ac521282cdc4f8f548f56c7a156ea1 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Thu, 9 Jun 2022 15:29:00 +0200 Subject: [PATCH 04/24] Added workaround IgnoreAWSXRayPropagation flag (#403). --- .../AWSLambdaInstrumentationOptions.cs | 29 +++++++++++++++++++ .../Implementation/AWSLambdaWrapper.cs | 10 ++++++- .../TracerProviderBuilderExtensions.cs | 12 +++++++- .../AWSLambdaWrapperTests.cs | 21 +++++++++++++- 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs new file mode 100644 index 0000000000..cbcd8bc713 --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs @@ -0,0 +1,29 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Contrib.Instrumentation.AWSLambda +{ + /// + /// AWS lambda instrumentation options. + /// + public class AWSLambdaInstrumentationOptions + { + /// + /// Gets or sets a value indicating whether AWS X-Ray propagation should be ignored. + /// + public bool IgnoreAWSXRayPropagation { get; set; } + } +} diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 8e0c08c528..4629be9adc 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -30,6 +30,14 @@ public class AWSLambdaWrapper { private static readonly ActivitySource AWSLambdaActivitySource = new(AWSLambdaUtils.ActivitySourceName); + /// + /// Gets or sets a value indicating whether AWS X-Ray propagation should be ignored. Default value is false. + /// The flag was introduced as a workaround of this issue: + /// the ActivitySource.StartActivity method returns null if sampling decision of DROP (Sampled=0). + /// Flag can be removed as soon as the bug https://github.com/open-telemetry/opentelemetry-dotnet/issues/3290 is resolved. + /// + internal static bool IgnoreAWSXRayPropagation { get; set; } + /// /// Tracing wrapper for Lambda handler without Lambda context. /// @@ -229,7 +237,7 @@ internal static Activity OnFunctionStart( ActivityContext parentContext = default, IEnumerable> tags = null) { - if (parentContext == default) + if (parentContext == default && !IgnoreAWSXRayPropagation) { parentContext = AWSLambdaUtils.GetParentContext(); } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs index 7cd573a766..54eaf63fcd 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs @@ -14,6 +14,8 @@ // limitations under the License. // +using System; +using OpenTelemetry.Contrib.Instrumentation.AWSLambda; using OpenTelemetry.Contrib.Instrumentation.AWSLambda.Implementation; using OpenTelemetry.Internal; using OpenTelemetry.Resources; @@ -29,11 +31,19 @@ public static class TracerProviderBuilderExtensions /// Add AWS Lambda configurations. /// /// being configured. + /// AWS lambda instrumentation options. /// The instance of to chain the calls. - public static TracerProviderBuilder AddAWSLambdaConfigurations(this TracerProviderBuilder builder) + public static TracerProviderBuilder AddAWSLambdaConfigurations( + this TracerProviderBuilder builder, + Action configure = null) { Guard.ThrowIfNull(builder); + var options = new AWSLambdaInstrumentationOptions(); + configure?.Invoke(options); + + AWSLambdaWrapper.IgnoreAWSXRayPropagation = options.IgnoreAWSXRayPropagation; + builder.AddSource(AWSLambdaUtils.ActivitySourceName); builder.SetResourceBuilder(ResourceBuilder .CreateEmpty() diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index 8a8082c91e..9532bb6b47 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -321,7 +321,6 @@ public void OnFunctionStart_NoParent_ActivityCreated() { Environment.SetEnvironmentVariable("_X_AMZN_TRACE_ID", null); - // var processor = new Mock>(); Activity activity = null; using (var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddAWSLambdaConfigurations() @@ -333,6 +332,26 @@ public void OnFunctionStart_NoParent_ActivityCreated() Assert.NotNull(activity); } + [Fact] + public void OnFunctionStart_NoSampledAndXRayPropagationIgnored_ActivityCreated() + { + Environment.SetEnvironmentVariable("_X_AMZN_TRACE_ID", $"Root=1-5759e988-bd862e3fe1be46a994272793;Parent={XRayParentId};Sampled=0"); + + Activity activity = null; + + // The IgnoreAWSXRayPropagation flag was introduced as a workaround of this issue: + // the ActivitySource.StartActivity method returns null if sampling decision of DROP (Sampled=0). + // Flag can be removed as soon as the bug https://github.com/open-telemetry/opentelemetry-dotnet/issues/3290 is resolved. + using (var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations(c => c.IgnoreAWSXRayPropagation = true) + .Build()) + { + activity = AWSLambdaWrapper.OnFunctionStart(); + } + + Assert.NotNull(activity); + } + private static ActivityContext CreateParentContext() { var traceId = ActivityTraceId.CreateFromString(TraceId.AsSpan()); From 2ca5828e39863bc5f01596cbd6bb91a034c1eaaf Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Mon, 20 Jun 2022 17:49:54 +0200 Subject: [PATCH 05/24] 1. removed tags parameter: default function tags are derived from type function trigger and lambda context 2. added parent context extraction for http triggered AWS Lambdas 3. aligned unit tests accordingly (#403) --- .../AWSLambdaSemanticConventions.cs | 1 + .../Implementation/AWSLambdaUtils.cs | 58 ++++ .../Implementation/AWSLambdaWrapper.cs | 272 +++++++++--------- ...y.Contrib.Instrumentation.AWSLambda.csproj | 1 + .../AWSLambdaWrapperTests.cs | 41 +-- 5 files changed, 213 insertions(+), 160 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs index 4a174094cd..a3fcdb6977 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs @@ -28,5 +28,6 @@ internal static class AWSLambdaSemanticConventions public const string AttributeFaasID = "faas.id"; public const string AttributeFaasName = "faas.name"; public const string AttributeFaasVersion = "faas.version"; + public const string AttributeFaasTrigger = "faas.trigger"; } } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index 1e859dcaee..58f61cdc00 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -17,7 +17,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using Amazon.Lambda.APIGatewayEvents; using Amazon.Lambda.Core; +using OpenTelemetry.Context.Propagation; using OpenTelemetry.Contrib.Extensions.AWSXRay.Trace; namespace OpenTelemetry.Contrib.Instrumentation.AWSLambda.Implementation @@ -61,6 +63,21 @@ internal static ActivityContext GetParentContext() return activityContext; } + internal static ActivityContext ExtractParentContext(TInput input) + { + ActivityContext parentContext = default; + if (input is APIGatewayProxyRequest request) + { + var propagationContext = Propagators.DefaultTextMapPropagator.Extract(default, request, GetHeaderValues); + if (propagationContext != default) + { + parentContext = propagationContext.ActivityContext; + } + } + + return parentContext; + } + internal static string GetCloudProvider() { return CloudProvider; @@ -100,6 +117,36 @@ internal static string GetAccountId(string functionArn) return null; } + internal static IEnumerable> GetFunctionDefaultTags(TInput input, ILambdaContext context) + { + var trigger = "other"; + if (input is APIGatewayProxyRequest) + { + trigger = "http"; + } + + var tags = new List> + { + new(AWSLambdaSemanticConventions.AttributeFaasTrigger, trigger), + }; + + if (context == null) + { + return tags; + } + + tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasName, context.FunctionName)); + tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasID, context.InvokedFunctionArn)); + + var functionParts = context.InvokedFunctionArn?.Split(':'); + if (functionParts != null && functionParts.Length >= 5) + { + tags.Add(new(AWSLambdaSemanticConventions.AttributeCloudAccountID, functionParts[4])); + } + + return tags; + } + private static ActivityContext ParseXRayTraceHeader(string rawHeader) { var xrayPropagator = new AWSXRayPropagator(); @@ -112,5 +159,16 @@ private static ActivityContext ParseXRayTraceHeader(string rawHeader) var propagationContext = xrayPropagator.Extract(default, carrier, Getter); return propagationContext.ActivityContext; } + + private static IEnumerable GetHeaderValues(APIGatewayProxyRequest request, string name) + { + if (request.MultiValueHeaders != null && + request.MultiValueHeaders.TryGetValue(name, out var values)) + { + return values; + } + + return null; + } } } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 4629be9adc..1378e1b626 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -50,16 +50,28 @@ public class AWSLambdaWrapper /// The optional parent context used for Activity object creation. /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// - /// The optional tags list to initialize the created Activity object with. /// Instance of output result. public static TResult Trace( TracerProvider tracerProvider, Func lambdaHandler, TInput input, - ActivityContext parentContext = default, - IEnumerable> tags = null) + ActivityContext parentContext = default) { - return Intercept(tracerProvider, () => lambdaHandler(input), default, parentContext, tags); + var lambdaActivity = OnFunctionStart(input, default, parentContext); + try + { + return lambdaHandler(input); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } } /// @@ -73,15 +85,27 @@ public static TResult Trace( /// The optional parent context used for Activity object creation. /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// - /// The optional tags list to initialize the created Activity object with. public static void Trace( TracerProvider tracerProvider, Action lambdaHandler, TInput input, - ActivityContext parentContext = default, - IEnumerable> tags = null) + ActivityContext parentContext = default) { - Intercept(tracerProvider, () => lambdaHandler(input), default, parentContext, tags); + var lambdaActivity = OnFunctionStart(input, default, parentContext); + try + { + lambdaHandler(input); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } } /// @@ -95,16 +119,28 @@ public static void Trace( /// The optional parent context used for Activity object creation. /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// - /// The optional tags list to initialize the created Activity object with. /// Task. public static async Task Trace( TracerProvider tracerProvider, Func lambdaHandler, TInput input, - ActivityContext parentContext = default, - IEnumerable> tags = null) + ActivityContext parentContext = default) { - await Intercept(tracerProvider, () => lambdaHandler(input), default, parentContext, tags); + var lambdaActivity = OnFunctionStart(input, default, parentContext); + try + { + await lambdaHandler(input); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } } /// @@ -119,16 +155,28 @@ public static async Task Trace( /// The optional parent context used for Activity object creation. /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// - /// The optional tags list to initialize the created Activity object with. /// Task of result. public static async Task Trace( TracerProvider tracerProvider, Func> lambdaHandler, TInput input, - ActivityContext parentContext = default, - IEnumerable> tags = null) + ActivityContext parentContext = default) { - return await Intercept(tracerProvider, () => lambdaHandler(input), default, parentContext, tags); + var lambdaActivity = OnFunctionStart(input, default, parentContext); + try + { + return await lambdaHandler(input); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } } /// @@ -144,17 +192,29 @@ public static async Task Trace( /// The optional parent context used for Activity object creation. /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// - /// The optional tags list to initialize the created Activity object with. /// Instance of output result. public static TResult Trace( TracerProvider tracerProvider, Func lambdaHandler, TInput input, ILambdaContext context, - ActivityContext parentContext = default, - IEnumerable> tags = null) + ActivityContext parentContext = default) { - return Intercept(tracerProvider, () => lambdaHandler(input, context), context, parentContext, tags); + var lambdaActivity = OnFunctionStart(input, context, parentContext); + try + { + return lambdaHandler(input, context); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } } /// @@ -169,16 +229,28 @@ public static TResult Trace( /// The optional parent context used for Activity object creation. /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// - /// The optional tags list to initialize the created Activity object with. public static void Trace( TracerProvider tracerProvider, Action lambdaHandler, TInput input, ILambdaContext context, - ActivityContext parentContext = default, - IEnumerable> tags = null) + ActivityContext parentContext = default) { - Intercept(tracerProvider, () => lambdaHandler(input, context), context, parentContext, tags); + var lambdaActivity = OnFunctionStart(input, context, parentContext); + try + { + lambdaHandler(input, context); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } } /// @@ -193,17 +265,29 @@ public static void Trace( /// The optional parent context used for Activity object creation. /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// - /// The optional tags list to initialize the created Activity object with. /// Task. public static async Task Trace( TracerProvider tracerProvider, Func lambdaHandler, TInput input, ILambdaContext context, - ActivityContext parentContext = default, - IEnumerable> tags = null) + ActivityContext parentContext = default) { - await Intercept(tracerProvider, () => lambdaHandler(input, context), context, parentContext, tags); + var lambdaActivity = OnFunctionStart(input, context, parentContext); + try + { + await lambdaHandler(input, context); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } } /// @@ -219,31 +303,49 @@ public static async Task Trace( /// The optional parent context used for Activity object creation. /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. /// - /// The optional tags list to initialize the created Activity object with. /// Task of result. public static async Task Trace( TracerProvider tracerProvider, Func> lambdaHandler, TInput input, ILambdaContext context, - ActivityContext parentContext = default, - IEnumerable> tags = null) + ActivityContext parentContext = default) { - return await Intercept(tracerProvider, () => lambdaHandler(input, context), context, parentContext, tags); + var lambdaActivity = OnFunctionStart(input, context, parentContext); + try + { + return await lambdaHandler(input, context); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } } - internal static Activity OnFunctionStart( + internal static Activity OnFunctionStart( + TInput input = default, ILambdaContext context = null, - ActivityContext parentContext = default, - IEnumerable> tags = null) + ActivityContext parentContext = default) { - if (parentContext == default && !IgnoreAWSXRayPropagation) + if (parentContext == default) { - parentContext = AWSLambdaUtils.GetParentContext(); + parentContext = AWSLambdaUtils.ExtractParentContext(input); + if (parentContext == default && !IgnoreAWSXRayPropagation) + { + parentContext = AWSLambdaUtils.GetParentContext(); + } } + var tags = AWSLambdaUtils.GetFunctionDefaultTags(input, context); var activityName = AWSLambdaUtils.GetFunctionName(context); var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, tags); + if (activity != null && context != null) { if (activity.IsAllDataRequested) @@ -292,101 +394,5 @@ private static void OnException(Activity activity, Exception exception) } } } - - private static TResult Intercept( - TracerProvider tracerProvider, - Func method, - ILambdaContext context = null, - ActivityContext parentContext = default, - IEnumerable> tags = null) - { - var lambdaActivity = OnFunctionStart(context, parentContext, tags); - try - { - return method(); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } - } - - private static void Intercept( - TracerProvider tracerProvider, - Action method, - ILambdaContext context = null, - ActivityContext parentContext = default, - IEnumerable> tags = null) - { - var lambdaActivity = OnFunctionStart(context, parentContext, tags); - try - { - method(); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } - } - - private static async Task Intercept( - TracerProvider tracerProvider, - Func> method, - ILambdaContext context = null, - ActivityContext parentContext = default, - IEnumerable> tags = null) - { - var lambdaActivity = OnFunctionStart(context, parentContext, tags); - try - { - return await method(); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } - } - - private static async Task Intercept( - TracerProvider tracerProvider, - Func method, - ILambdaContext context = null, - ActivityContext parentContext = default, - IEnumerable> tags = null) - { - var lambdaActivity = OnFunctionStart(context, parentContext, tags); - try - { - await method(); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } - } } } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/OpenTelemetry.Contrib.Instrumentation.AWSLambda.csproj b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/OpenTelemetry.Contrib.Instrumentation.AWSLambda.csproj index a4ed849310..93b001d29b 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/OpenTelemetry.Contrib.Instrumentation.AWSLambda.csproj +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/OpenTelemetry.Contrib.Instrumentation.AWSLambda.csproj @@ -8,6 +8,7 @@ + diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index 9532bb6b47..4581b88218 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -15,10 +15,10 @@ // using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using Amazon.Lambda.APIGatewayEvents; using Moq; using OpenTelemetry.Contrib.Instrumentation.AWSLambda.Implementation; using OpenTelemetry.Resources; @@ -58,9 +58,8 @@ public void TestLambdaHandler(bool setCustomParent) .AddProcessor(processor.Object) .Build()) { - var tags = CreateTags(); var parentContext = setCustomParent ? CreateParentContext() : default; - var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", this.sampleLambdaContext, parentContext, tags); + var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -85,9 +84,8 @@ public void TestLambdaHandlerNoReturn(bool setCustomParent) .AddProcessor(processor.Object) .Build()) { - var tags = CreateTags(); var parentContext = setCustomParent ? CreateParentContext() : default; - AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", this.sampleLambdaContext, parentContext, tags); + AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -112,9 +110,8 @@ public async Task TestLambdaHandlerAsync(bool setCustomParent) .AddProcessor(processor.Object) .Build()) { - var tags = CreateTags(); var parentContext = setCustomParent ? CreateParentContext() : default; - var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", this.sampleLambdaContext, parentContext, tags); + var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -139,9 +136,8 @@ public async Task TestLambdaHandlerAsyncNoReturn(bool setCustomParent) .AddProcessor(processor.Object) .Build()) { - var tags = CreateTags(); var parentContext = setCustomParent ? CreateParentContext() : default; - await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", this.sampleLambdaContext, parentContext, tags); + await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -166,9 +162,8 @@ public void TestLambdaHandlerNoContext(bool setCustomParent) .AddProcessor(processor.Object) .Build()) { - var tags = CreateTags(); var parentContext = setCustomParent ? CreateParentContext() : default; - var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", parentContext, tags); + var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -192,9 +187,8 @@ public void TestLambdaHandlerNoContextNoReturn(bool setCustomParent) .AddProcessor(processor.Object) .Build()) { - var tags = CreateTags(); var parentContext = setCustomParent ? CreateParentContext() : default; - AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", parentContext, tags); + AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -218,9 +212,8 @@ public async Task TestLambdaHandlerAsyncNoContext(bool setCustomParent) .AddProcessor(processor.Object) .Build()) { - var tags = CreateTags(); var parentContext = setCustomParent ? CreateParentContext() : default; - var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", parentContext, tags); + var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -244,9 +237,8 @@ public async Task TestLambdaHandlerAsyncNoContextNoReturn(bool setCustomParent) .AddProcessor(processor.Object) .Build()) { - var tags = CreateTags(); var parentContext = setCustomParent ? CreateParentContext() : default; - await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", parentContext, tags); + await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -272,9 +264,8 @@ public void TestLambdaHandlerException(bool setCustomParent) { try { - var tags = CreateTags(); var parentContext = setCustomParent ? CreateParentContext() : default; - AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturnException, "TestException", this.sampleLambdaContext, parentContext, tags); + AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturnException, "TestException", this.sampleLambdaContext, parentContext); } catch { @@ -326,7 +317,7 @@ public void OnFunctionStart_NoParent_ActivityCreated() .AddAWSLambdaConfigurations() .Build()) { - activity = AWSLambdaWrapper.OnFunctionStart(); + activity = AWSLambdaWrapper.OnFunctionStart(); } Assert.NotNull(activity); @@ -346,7 +337,7 @@ public void OnFunctionStart_NoSampledAndXRayPropagationIgnored_ActivityCreated() .AddAWSLambdaConfigurations(c => c.IgnoreAWSXRayPropagation = true) .Build()) { - activity = AWSLambdaWrapper.OnFunctionStart(); + activity = AWSLambdaWrapper.OnFunctionStart(); } Assert.NotNull(activity); @@ -359,11 +350,6 @@ private static ActivityContext CreateParentContext() return new ActivityContext(traceId, parentId, ActivityTraceFlags.Recorded); } - private static IEnumerable> CreateTags() - { - return new[] { new KeyValuePair("TestTag", "TagValue"), }; - } - private void AssertSpanProperties(Activity activity, string parentId) { Assert.Equal(TraceId, activity.TraceId.ToHexString()); @@ -386,8 +372,9 @@ private void AssertSpanAttributes(Activity activity) { Assert.Equal(this.sampleLambdaContext.AwsRequestId, activity.GetTagValue(AWSLambdaSemanticConventions.AttributeFaasExecution)); Assert.Equal(this.sampleLambdaContext.InvokedFunctionArn, activity.GetTagValue(AWSLambdaSemanticConventions.AttributeFaasID)); + Assert.Equal(this.sampleLambdaContext.FunctionName, activity.GetTagValue(AWSLambdaSemanticConventions.AttributeFaasName)); + Assert.Equal("other", activity.GetTagValue(AWSLambdaSemanticConventions.AttributeFaasTrigger)); Assert.Equal("111111111111", activity.GetTagValue(AWSLambdaSemanticConventions.AttributeCloudAccountID)); - Assert.Equal("TagValue", activity.GetTagValue("TestTag")); } private void AssertSpanException(Activity activity) From 13c47cdf5e174a9706d26e069ea558f02b402c3a Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Tue, 21 Jun 2022 09:12:49 +0200 Subject: [PATCH 06/24] Removed unused using (#403) --- .../Implementation/AWSLambdaWrapper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 1378e1b626..e25874dedb 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -15,7 +15,6 @@ // using System; -using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using Amazon.Lambda.Core; From 40b808767c24fb59d653ea810e9c37bf39107df7 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Wed, 29 Jun 2022 16:03:44 +0200 Subject: [PATCH 07/24] Added support of API Gateway HTTP API version 2 payload proxy format (#403) --- .../Implementation/AWSLambdaUtils.cs | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index 58f61cdc00..7b6b412d40 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -65,17 +65,23 @@ internal static ActivityContext GetParentContext() internal static ActivityContext ExtractParentContext(TInput input) { - ActivityContext parentContext = default; - if (input is APIGatewayProxyRequest request) + PropagationContext propagationContext = default; + switch (input) { - var propagationContext = Propagators.DefaultTextMapPropagator.Extract(default, request, GetHeaderValues); - if (propagationContext != default) - { - parentContext = propagationContext.ActivityContext; - } + case APIGatewayProxyRequest apiGatewayProxyRequest: + propagationContext = Propagators.DefaultTextMapPropagator.Extract(default, apiGatewayProxyRequest, GetHeaderValues); + break; + case APIGatewayHttpApiV2ProxyRequest apiGatewayHttpApiV2ProxyRequest: + propagationContext = Propagators.DefaultTextMapPropagator.Extract(default, apiGatewayHttpApiV2ProxyRequest, GetHeaderValues); + break; } - return parentContext; + if (propagationContext != default) + { + return propagationContext.ActivityContext; + } + + return default; } internal static string GetCloudProvider() @@ -120,7 +126,7 @@ internal static string GetAccountId(string functionArn) internal static IEnumerable> GetFunctionDefaultTags(TInput input, ILambdaContext context) { var trigger = "other"; - if (input is APIGatewayProxyRequest) + if (input is APIGatewayProxyRequest || input is APIGatewayHttpApiV2ProxyRequest) { trigger = "http"; } @@ -170,5 +176,20 @@ private static IEnumerable GetHeaderValues(APIGatewayProxyRequest reques return null; } + + private static IEnumerable GetHeaderValues(APIGatewayHttpApiV2ProxyRequest request, string name) + { + if (request.Headers != null && + request.Headers.TryGetValue(name, out var header)) + { + // Multiple values for the same header will be separated by a comma. + if (!string.IsNullOrEmpty(header)) + { + return header.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); + } + } + + return null; + } } } From 3ae0b9f1eda0045c1c83a54b65a9a30c77423667 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Mon, 11 Jul 2022 17:36:27 +0200 Subject: [PATCH 08/24] - moved setting of function tags from OnFunctionStart to AWSLambdaUtils.GetFunctionDefaultTags and used them for Activity creation - refactored AWSLambdaWrapper.Trace methods: removed duplicate code - extended Trace methods xml-doc (#403) --- .../Implementation/AWSLambdaUtils.cs | 40 ++- .../Implementation/AWSLambdaWrapper.cs | 255 +++++++----------- 2 files changed, 123 insertions(+), 172 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index 7b6b412d40..3152df0e35 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -96,12 +96,7 @@ internal static string GetAWSRegion() internal static string GetFunctionName(ILambdaContext context = null) { - if (context != null) - { - return context.FunctionName; - } - - return Environment.GetEnvironmentVariable(FunctionName); + return context?.FunctionName ?? Environment.GetEnvironmentVariable(FunctionName); } internal static string GetFunctionVersion() @@ -123,7 +118,7 @@ internal static string GetAccountId(string functionArn) return null; } - internal static IEnumerable> GetFunctionDefaultTags(TInput input, ILambdaContext context) + internal static string GetFaasTrigger(TInput input) { var trigger = "other"; if (input is APIGatewayProxyRequest || input is APIGatewayHttpApiV2ProxyRequest) @@ -131,23 +126,42 @@ internal static IEnumerable> GetFunctionDefaultTags trigger = "http"; } + return trigger; + } + + internal static IEnumerable> GetFunctionDefaultTags(TInput input, ILambdaContext context) + { var tags = new List> { - new(AWSLambdaSemanticConventions.AttributeFaasTrigger, trigger), + new(AWSLambdaSemanticConventions.AttributeFaasTrigger, GetFaasTrigger(input)), }; + var functionName = GetFunctionName(context); + if (functionName != null) + { + tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasName, functionName)); + } + if (context == null) { return tags; } - tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasName, context.FunctionName)); - tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasID, context.InvokedFunctionArn)); + if (context.AwsRequestId != null) + { + tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasExecution, context.AwsRequestId)); + } - var functionParts = context.InvokedFunctionArn?.Split(':'); - if (functionParts != null && functionParts.Length >= 5) + var functionArn = context.InvokedFunctionArn; + if (functionArn != null) { - tags.Add(new(AWSLambdaSemanticConventions.AttributeCloudAccountID, functionParts[4])); + tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasID, functionArn)); + + var accountId = GetAccountId(functionArn); + if (accountId != null) + { + tags.Add(new(AWSLambdaSemanticConventions.AttributeCloudAccountID, accountId)); + } } return tags; diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index e25874dedb..0edceba3c8 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -46,8 +46,9 @@ public class AWSLambdaWrapper /// Lambda handler function passed in. /// Instance of input. /// - /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. + /// The optional parent context is used for Activity object creation. + /// If the parent context parameter is not provided then incoming request is used for the parent extraction. + /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. /// /// Instance of output result. public static TResult Trace( @@ -56,21 +57,10 @@ public static TResult Trace( TInput input, ActivityContext parentContext = default) { - var lambdaActivity = OnFunctionStart(input, default, parentContext); - try - { - return lambdaHandler(input); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } + TResult result = default; + Action action = () => result = lambdaHandler(input); + TraceInternal(tracerProvider, action, input, default, parentContext); + return result; } /// @@ -81,8 +71,9 @@ public static TResult Trace( /// Lambda handler function passed in. /// Instance of input. /// - /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. + /// The optional parent context is used for Activity object creation. + /// If the parent context parameter is not provided then incoming request is used for the parent extraction. + /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. /// public static void Trace( TracerProvider tracerProvider, @@ -90,21 +81,8 @@ public static void Trace( TInput input, ActivityContext parentContext = default) { - var lambdaActivity = OnFunctionStart(input, default, parentContext); - try - { - lambdaHandler(input); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } + Action action = () => lambdaHandler(input); + TraceInternal(tracerProvider, action, input, default, parentContext); } /// @@ -115,8 +93,9 @@ public static void Trace( /// Lambda handler function passed in. /// Instance of input. /// - /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. + /// The optional parent context is used for Activity object creation. + /// If the parent context parameter is not provided then incoming request is used for the parent extraction. + /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. /// /// Task. public static async Task Trace( @@ -125,21 +104,8 @@ public static async Task Trace( TInput input, ActivityContext parentContext = default) { - var lambdaActivity = OnFunctionStart(input, default, parentContext); - try - { - await lambdaHandler(input); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } + Func action = async () => await lambdaHandler(input); + await TraceInternalAsync(tracerProvider, action, input, default, parentContext); } /// @@ -151,8 +117,9 @@ public static async Task Trace( /// Lambda handler function passed in. /// Instance of input. /// - /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. + /// The optional parent context is used for Activity object creation. + /// If the parent context parameter is not provided then incoming request is used for the parent extraction. + /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. /// /// Task of result. public static async Task Trace( @@ -161,21 +128,10 @@ public static async Task Trace( TInput input, ActivityContext parentContext = default) { - var lambdaActivity = OnFunctionStart(input, default, parentContext); - try - { - return await lambdaHandler(input); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } + TResult result = default; + Func action = async () => result = await lambdaHandler(input); + await TraceInternalAsync(tracerProvider, action, input, default, parentContext); + return result; } /// @@ -188,8 +144,9 @@ public static async Task Trace( /// Instance of input. /// Instance of lambda context. /// - /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. + /// The optional parent context is used for Activity object creation. + /// If the parent context parameter is not provided then incoming request is used for the parent extraction. + /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. /// /// Instance of output result. public static TResult Trace( @@ -199,21 +156,10 @@ public static TResult Trace( ILambdaContext context, ActivityContext parentContext = default) { - var lambdaActivity = OnFunctionStart(input, context, parentContext); - try - { - return lambdaHandler(input, context); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } + TResult result = default; + Action action = () => result = lambdaHandler(input, context); + TraceInternal(tracerProvider, action, input, context, parentContext); + return result; } /// @@ -225,8 +171,9 @@ public static TResult Trace( /// Instance of input. /// Instance of lambda context. /// - /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. + /// The optional parent context is used for Activity object creation. + /// If the parent context parameter is not provided then incoming request is used for the parent extraction. + /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. /// public static void Trace( TracerProvider tracerProvider, @@ -235,21 +182,8 @@ public static void Trace( ILambdaContext context, ActivityContext parentContext = default) { - var lambdaActivity = OnFunctionStart(input, context, parentContext); - try - { - lambdaHandler(input, context); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } + Action action = () => lambdaHandler(input, context); + TraceInternal(tracerProvider, action, input, context, parentContext); } /// @@ -261,8 +195,9 @@ public static void Trace( /// Instance of input. /// Instance of lambda context. /// - /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. + /// The optional parent context is used for Activity object creation. + /// If the parent context parameter is not provided then incoming request is used for the parent extraction. + /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. /// /// Task. public static async Task Trace( @@ -272,21 +207,8 @@ public static async Task Trace( ILambdaContext context, ActivityContext parentContext = default) { - var lambdaActivity = OnFunctionStart(input, context, parentContext); - try - { - await lambdaHandler(input, context); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } + Func action = async () => await lambdaHandler(input, context); + await TraceInternalAsync(tracerProvider, action, input, context, parentContext); } /// @@ -299,8 +221,9 @@ public static async Task Trace( /// Instance of input. /// Instance of lambda context. /// - /// The optional parent context used for Activity object creation. - /// If the parent context parametere is not provided then X-Ray propagation is used to extract the parent. + /// The optional parent context is used for Activity object creation. + /// If the parent context parameter is not provided then incoming request is used for the parent extraction. + /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. /// /// Task of result. public static async Task Trace( @@ -310,21 +233,10 @@ public static async Task Trace( ILambdaContext context, ActivityContext parentContext = default) { - var lambdaActivity = OnFunctionStart(input, context, parentContext); - try - { - return await lambdaHandler(input, context); - } - catch (Exception ex) - { - OnException(lambdaActivity, ex); - - throw; - } - finally - { - OnFunctionStop(lambdaActivity, tracerProvider); - } + TResult result = default; + Func action = async () => result = await lambdaHandler(input, context); + await TraceInternalAsync(tracerProvider, action, input, context, parentContext); + return result; } internal static Activity OnFunctionStart( @@ -345,29 +257,6 @@ internal static Activity OnFunctionStart( var activityName = AWSLambdaUtils.GetFunctionName(context); var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, tags); - if (activity != null && context != null) - { - if (activity.IsAllDataRequested) - { - if (context.AwsRequestId != null) - { - activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasExecution, context.AwsRequestId); - } - - var functionArn = context.InvokedFunctionArn; - if (functionArn != null) - { - activity.SetTag(AWSLambdaSemanticConventions.AttributeFaasID, functionArn); - - var accountId = AWSLambdaUtils.GetAccountId(functionArn); - if (accountId != null) - { - activity.SetTag(AWSLambdaSemanticConventions.AttributeCloudAccountID, accountId); - } - } - } - } - return activity; } @@ -393,5 +282,53 @@ private static void OnException(Activity activity, Exception exception) } } } + + private static void TraceInternal( + TracerProvider tracerProvider, + Action handler, + TInput input, + ILambdaContext context, + ActivityContext parentContext = default) + { + var lambdaActivity = OnFunctionStart(input, context, parentContext); + try + { + handler(); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } + } + + private static async Task TraceInternalAsync( + TracerProvider tracerProvider, + Func handlerAsync, + TInput input, + ILambdaContext context, + ActivityContext parentContext = default) + { + var lambdaActivity = OnFunctionStart(input, context, parentContext); + try + { + await handlerAsync(); + } + catch (Exception ex) + { + OnException(lambdaActivity, ex); + + throw; + } + finally + { + OnFunctionStop(lambdaActivity, tracerProvider); + } + } } } From 746c1e5a1c97539725acb7b285f4c0ab0f3cc2a1 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Mon, 11 Jul 2022 17:42:50 +0200 Subject: [PATCH 09/24] - updated phrasing in xml-doc (#403) --- .../Implementation/AWSLambdaWrapper.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 0edceba3c8..6199d915c4 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -47,8 +47,8 @@ public class AWSLambdaWrapper /// Instance of input. /// /// The optional parent context is used for Activity object creation. - /// If the parent context parameter is not provided then incoming request is used for the parent extraction. - /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. + /// If no parent context provided, incoming request is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// /// Instance of output result. public static TResult Trace( @@ -72,8 +72,8 @@ public static TResult Trace( /// Instance of input. /// /// The optional parent context is used for Activity object creation. - /// If the parent context parameter is not provided then incoming request is used for the parent extraction. - /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. + /// If no parent context provided, incoming request is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// public static void Trace( TracerProvider tracerProvider, @@ -94,8 +94,8 @@ public static void Trace( /// Instance of input. /// /// The optional parent context is used for Activity object creation. - /// If the parent context parameter is not provided then incoming request is used for the parent extraction. - /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. + /// If no parent context provided, incoming request is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// /// Task. public static async Task Trace( @@ -118,8 +118,8 @@ public static async Task Trace( /// Instance of input. /// /// The optional parent context is used for Activity object creation. - /// If the parent context parameter is not provided then incoming request is used for the parent extraction. - /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. + /// If no parent context provided, incoming request is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// /// Task of result. public static async Task Trace( @@ -145,8 +145,8 @@ public static async Task Trace( /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. - /// If the parent context parameter is not provided then incoming request is used for the parent extraction. - /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. + /// If no parent context provided, incoming request is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// /// Instance of output result. public static TResult Trace( @@ -172,8 +172,8 @@ public static TResult Trace( /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. - /// If the parent context parameter is not provided then incoming request is used for the parent extraction. - /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. + /// If no parent context provided, incoming request is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// public static void Trace( TracerProvider tracerProvider, @@ -196,8 +196,8 @@ public static void Trace( /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. - /// If the parent context parameter is not provided then incoming request is used for the parent extraction. - /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. + /// If no parent context provided, incoming request is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// /// Task. public static async Task Trace( @@ -222,8 +222,8 @@ public static async Task Trace( /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. - /// If the parent context parameter is not provided then incoming request is used for the parent extraction. - /// If the parent is not extracted from incoming request then X-Ray propagation is used to extract it. + /// If no parent context provided, incoming request is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// /// Task of result. public static async Task Trace( From 6591210cf45a79d350c762a4c49c206596b9ae89 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Wed, 20 Jul 2022 15:06:03 +0200 Subject: [PATCH 10/24] (#403) - made ILambdaContext argument mandatory - removed Trace methods without ILambdaContext - added Trace overloads without input argument (input only with ILambdaContext) --- .../Implementation/AWSLambdaWrapper.cs | 123 +++++------------- .../AWSLambdaWrapperTests.cs | 14 +- 2 files changed, 40 insertions(+), 97 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 6199d915c4..24ac081c11 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -38,13 +38,14 @@ public class AWSLambdaWrapper internal static bool IgnoreAWSXRayPropagation { get; set; } /// - /// Tracing wrapper for Lambda handler without Lambda context. + /// Tracing wrapper for Lambda handler. /// /// Input. /// Output result. /// TracerProvider passed in. /// Lambda handler function passed in. /// Instance of input. + /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. @@ -53,23 +54,25 @@ public class AWSLambdaWrapper /// Instance of output result. public static TResult Trace( TracerProvider tracerProvider, - Func lambdaHandler, + Func lambdaHandler, TInput input, + ILambdaContext context, ActivityContext parentContext = default) { TResult result = default; - Action action = () => result = lambdaHandler(input); - TraceInternal(tracerProvider, action, input, default, parentContext); + Action action = () => result = lambdaHandler(input, context); + TraceInternal(tracerProvider, action, input, context, parentContext); return result; } /// - /// Tracing wrapper for Lambda handler without Lambda context. + /// Tracing wrapper for Lambda handler. /// /// Input. /// TracerProvider passed in. /// Lambda handler function passed in. /// Instance of input. + /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. @@ -77,21 +80,23 @@ public static TResult Trace( /// public static void Trace( TracerProvider tracerProvider, - Action lambdaHandler, + Action lambdaHandler, TInput input, + ILambdaContext context, ActivityContext parentContext = default) { - Action action = () => lambdaHandler(input); - TraceInternal(tracerProvider, action, input, default, parentContext); + Action action = () => lambdaHandler(input, context); + TraceInternal(tracerProvider, action, input, context, parentContext); } /// - /// Tracing wrapper for async Lambda handler without Lambda context. + /// Tracing wrapper for async Lambda handler. /// /// Input. /// TracerProvider passed in. /// Lambda handler function passed in. /// Instance of input. + /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. @@ -100,22 +105,24 @@ public static void Trace( /// Task. public static async Task Trace( TracerProvider tracerProvider, - Func lambdaHandler, + Func lambdaHandler, TInput input, + ILambdaContext context, ActivityContext parentContext = default) { - Func action = async () => await lambdaHandler(input); - await TraceInternalAsync(tracerProvider, action, input, default, parentContext); + Func action = async () => await lambdaHandler(input, context); + await TraceInternalAsync(tracerProvider, action, input, context, parentContext); } /// - /// Tracing wrapper for async Lambda handler without Lambda context. + /// Tracing wrapper for async Lambda handler. /// /// Input. /// Output result. /// TracerProvider passed in. /// Lambda handler function passed in. /// Instance of input. + /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. @@ -124,75 +131,43 @@ public static async Task Trace( /// Task of result. public static async Task Trace( TracerProvider tracerProvider, - Func> lambdaHandler, - TInput input, - ActivityContext parentContext = default) - { - TResult result = default; - Func action = async () => result = await lambdaHandler(input); - await TraceInternalAsync(tracerProvider, action, input, default, parentContext); - return result; - } - - /// - /// Tracing wrapper for Lambda handler. - /// - /// Input. - /// Output result. - /// TracerProvider passed in. - /// Lambda handler function passed in. - /// Instance of input. - /// Instance of lambda context. - /// - /// The optional parent context is used for Activity object creation. - /// If no parent context provided, incoming request is used to extract one. - /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. - /// - /// Instance of output result. - public static TResult Trace( - TracerProvider tracerProvider, - Func lambdaHandler, + Func> lambdaHandler, TInput input, ILambdaContext context, ActivityContext parentContext = default) { TResult result = default; - Action action = () => result = lambdaHandler(input, context); - TraceInternal(tracerProvider, action, input, context, parentContext); + Func action = async () => result = await lambdaHandler(input, context); + await TraceInternalAsync(tracerProvider, action, input, context, parentContext); return result; } /// /// Tracing wrapper for Lambda handler. /// - /// Input. /// TracerProvider passed in. /// Lambda handler function passed in. - /// Instance of input. /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// - public static void Trace( + public static void Trace( TracerProvider tracerProvider, - Action lambdaHandler, - TInput input, + Action lambdaHandler, ILambdaContext context, ActivityContext parentContext = default) { - Action action = () => lambdaHandler(input, context); - TraceInternal(tracerProvider, action, input, context, parentContext); + Action action = () => lambdaHandler(context); + TraceInternal(tracerProvider, action, null, context, parentContext); } /// /// Tracing wrapper for async Lambda handler. /// - /// Input. /// TracerProvider passed in. /// Lambda handler function passed in. - /// Instance of input. /// Instance of lambda context. /// /// The optional parent context is used for Activity object creation. @@ -200,49 +175,17 @@ public static void Trace( /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. /// /// Task. - public static async Task Trace( - TracerProvider tracerProvider, - Func lambdaHandler, - TInput input, - ILambdaContext context, - ActivityContext parentContext = default) - { - Func action = async () => await lambdaHandler(input, context); - await TraceInternalAsync(tracerProvider, action, input, context, parentContext); - } - - /// - /// Tracing wrapper for async Lambda handler. - /// - /// Input. - /// Output result. - /// TracerProvider passed in. - /// Lambda handler function passed in. - /// Instance of input. - /// Instance of lambda context. - /// - /// The optional parent context is used for Activity object creation. - /// If no parent context provided, incoming request is used to extract one. - /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. - /// - /// Task of result. - public static async Task Trace( + public static async Task Trace( TracerProvider tracerProvider, - Func> lambdaHandler, - TInput input, + Func lambdaHandler, ILambdaContext context, ActivityContext parentContext = default) { - TResult result = default; - Func action = async () => result = await lambdaHandler(input, context); - await TraceInternalAsync(tracerProvider, action, input, context, parentContext); - return result; + Func action = async () => await lambdaHandler(context); + await TraceInternalAsync(tracerProvider, action, null, context, parentContext); } - internal static Activity OnFunctionStart( - TInput input = default, - ILambdaContext context = null, - ActivityContext parentContext = default) + internal static Activity OnFunctionStart(TInput input, ILambdaContext context, ActivityContext parentContext = default) { if (parentContext == default) { @@ -254,7 +197,7 @@ internal static Activity OnFunctionStart( } var tags = AWSLambdaUtils.GetFunctionDefaultTags(input, context); - var activityName = AWSLambdaUtils.GetFunctionName(context); + var activityName = AWSLambdaUtils.GetFunctionName(context) ?? ""; var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, tags); return activity; diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index 4581b88218..08855cc73a 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -18,7 +18,7 @@ using System.Diagnostics; using System.Linq; using System.Threading.Tasks; -using Amazon.Lambda.APIGatewayEvents; +using Amazon.Lambda.Core; using Moq; using OpenTelemetry.Contrib.Instrumentation.AWSLambda.Implementation; using OpenTelemetry.Resources; @@ -163,7 +163,7 @@ public void TestLambdaHandlerNoContext(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", parentContext); + var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", new Mock().Object, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -188,7 +188,7 @@ public void TestLambdaHandlerNoContextNoReturn(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", parentContext); + AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", new Mock().Object, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -213,7 +213,7 @@ public async Task TestLambdaHandlerAsyncNoContext(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", parentContext); + var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", new Mock().Object, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -238,7 +238,7 @@ public async Task TestLambdaHandlerAsyncNoContextNoReturn(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", parentContext); + await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", new Mock().Object, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -317,7 +317,7 @@ public void OnFunctionStart_NoParent_ActivityCreated() .AddAWSLambdaConfigurations() .Build()) { - activity = AWSLambdaWrapper.OnFunctionStart(); + activity = AWSLambdaWrapper.OnFunctionStart("test-input", new Mock().Object); } Assert.NotNull(activity); @@ -337,7 +337,7 @@ public void OnFunctionStart_NoSampledAndXRayPropagationIgnored_ActivityCreated() .AddAWSLambdaConfigurations(c => c.IgnoreAWSXRayPropagation = true) .Build()) { - activity = AWSLambdaWrapper.OnFunctionStart(); + activity = AWSLambdaWrapper.OnFunctionStart("test-input", new Mock().Object); } Assert.NotNull(activity); From 564fb28356c5042a157418da7745898b287b69ea Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Wed, 20 Jul 2022 17:05:23 +0200 Subject: [PATCH 11/24] - review suggestion: keep empty headers (#403) --- .../Implementation/AWSLambdaUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index 3152df0e35..ec695e2bfe 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -199,7 +199,7 @@ private static IEnumerable GetHeaderValues(APIGatewayHttpApiV2ProxyReque // Multiple values for the same header will be separated by a comma. if (!string.IsNullOrEmpty(header)) { - return header.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); + return header.Split(','); } } From 274e6baf37c88afdd4b9709cbf7ca1b6adc7d63d Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Mon, 25 Jul 2022 16:25:32 +0200 Subject: [PATCH 12/24] AWS Lambda unit tests refactoring: renaming, removing redundant tests (#403) --- .../AWSLambdaWrapperTests.cs | 78 ++++--------------- .../SampleHandlers.cs | 29 +++---- 2 files changed, 27 insertions(+), 80 deletions(-) diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index 08855cc73a..990181dd3f 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -49,7 +49,7 @@ public AWSLambdaWrapperTests() [Theory] [InlineData(false)] [InlineData(true)] - public void TestLambdaHandler(bool setCustomParent) + public void TraceSyncWithInputAndReturn(bool setCustomParent) { var processor = new Mock>(); @@ -59,7 +59,7 @@ public void TestLambdaHandler(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", this.sampleLambdaContext, parentContext); + var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncInputAndReturn, "TestStream", this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -75,7 +75,7 @@ public void TestLambdaHandler(bool setCustomParent) [Theory] [InlineData(false)] [InlineData(true)] - public void TestLambdaHandlerNoReturn(bool setCustomParent) + public void TraceSyncWithInputAndNoReturn(bool setCustomParent) { var processor = new Mock>(); @@ -85,7 +85,7 @@ public void TestLambdaHandlerNoReturn(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", this.sampleLambdaContext, parentContext); + AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncInputAndNoReturn, "TestStream", this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -101,7 +101,7 @@ public void TestLambdaHandlerNoReturn(bool setCustomParent) [Theory] [InlineData(false)] [InlineData(true)] - public async Task TestLambdaHandlerAsync(bool setCustomParent) + public void TraceSyncWithNoInputAndNoReturn(bool setCustomParent) { var processor = new Mock>(); @@ -111,7 +111,7 @@ public async Task TestLambdaHandlerAsync(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", this.sampleLambdaContext, parentContext); + AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoInputAndNoReturn, this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -127,7 +127,7 @@ public async Task TestLambdaHandlerAsync(bool setCustomParent) [Theory] [InlineData(false)] [InlineData(true)] - public async Task TestLambdaHandlerAsyncNoReturn(bool setCustomParent) + public async Task TraceAsyncWithInputAndReturn(bool setCustomParent) { var processor = new Mock>(); @@ -137,7 +137,7 @@ public async Task TestLambdaHandlerAsyncNoReturn(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", this.sampleLambdaContext, parentContext); + var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncInputAndReturn, "TestStream", this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -153,7 +153,7 @@ public async Task TestLambdaHandlerAsyncNoReturn(bool setCustomParent) [Theory] [InlineData(false)] [InlineData(true)] - public void TestLambdaHandlerNoContext(bool setCustomParent) + public async Task TraceAsyncWithInputAndNoReturn(bool setCustomParent) { var processor = new Mock>(); @@ -163,57 +163,7 @@ public void TestLambdaHandlerNoContext(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", new Mock().Object, parentContext); - var resource = tracerProvider.GetResource(); - this.AssertResourceAttributes(resource); - } - - // SetParentProvider -> OnStart -> OnEnd -> OnForceFlush -> OnShutdown -> Dispose - Assert.Equal(6, processor.Invocations.Count); - - var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public void TestLambdaHandlerNoContextNoReturn(bool setCustomParent) - { - var processor = new Mock>(); - - using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations() - .AddProcessor(processor.Object) - .Build()) - { - var parentContext = setCustomParent ? CreateParentContext() : default; - AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncNoReturn, "TestStream", new Mock().Object, parentContext); - var resource = tracerProvider.GetResource(); - this.AssertResourceAttributes(resource); - } - - // SetParentProvider -> OnStart -> OnEnd -> OnForceFlush -> OnShutdown -> Dispose - Assert.Equal(6, processor.Invocations.Count); - - var activity = (Activity)processor.Invocations[1].Arguments[0]; - this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task TestLambdaHandlerAsyncNoContext(bool setCustomParent) - { - var processor = new Mock>(); - - using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations() - .AddProcessor(processor.Object) - .Build()) - { - var parentContext = setCustomParent ? CreateParentContext() : default; - var result = await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncReturn, "TestStream", new Mock().Object, parentContext); + await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncInputAndNoReturn, "TestStream", this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -223,12 +173,13 @@ public async Task TestLambdaHandlerAsyncNoContext(bool setCustomParent) var activity = (Activity)processor.Invocations[1].Arguments[0]; this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); + this.AssertSpanAttributes(activity); } [Theory] [InlineData(false)] [InlineData(true)] - public async Task TestLambdaHandlerAsyncNoContextNoReturn(bool setCustomParent) + public async Task TraceAsyncWithNoInputAndNoReturn(bool setCustomParent) { var processor = new Mock>(); @@ -238,7 +189,7 @@ public async Task TestLambdaHandlerAsyncNoContextNoReturn(bool setCustomParent) .Build()) { var parentContext = setCustomParent ? CreateParentContext() : default; - await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoReturn, "TestStream", new Mock().Object, parentContext); + await AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerAsyncNoInputAndNoReturn, this.sampleLambdaContext, parentContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } @@ -248,6 +199,7 @@ public async Task TestLambdaHandlerAsyncNoContextNoReturn(bool setCustomParent) var activity = (Activity)processor.Invocations[1].Arguments[0]; this.AssertSpanProperties(activity, setCustomParent ? CustomParentId : XRayParentId); + this.AssertSpanAttributes(activity); } [Theory] @@ -295,7 +247,7 @@ public void TestLambdaHandlerNotSampled() .AddProcessor(processor.Object) .Build()) { - var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncReturn, "TestStream", this.sampleLambdaContext); + var result = AWSLambdaWrapper.Trace(tracerProvider, this.sampleHandlers.SampleHandlerSyncInputAndReturn, "TestStream", this.sampleLambdaContext); var resource = tracerProvider.GetResource(); this.AssertResourceAttributes(resource); } diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/SampleHandlers.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/SampleHandlers.cs index 30cb26ec45..85e89c4a45 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/SampleHandlers.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/SampleHandlers.cs @@ -22,44 +22,39 @@ namespace OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests { public class SampleHandlers { - public void SampleHandlerSyncNoReturn(string str, ILambdaContext context) + // Action + public void SampleHandlerSyncInputAndNoReturn(string str, ILambdaContext context) { } - public void SampleHandlerSyncNoReturn(string str) + // Action + public void SampleHandlerSyncNoInputAndNoReturn(ILambdaContext context) { } - public string SampleHandlerSyncReturn(string str, ILambdaContext context) + // Func + public string SampleHandlerSyncInputAndReturn(string str, ILambdaContext context) { return str; } - public string SampleHandlerSyncReturn(string str) - { - return str; - } - - public async Task SampleHandlerAsyncNoReturn(string str, ILambdaContext context) + // Func + public async Task SampleHandlerAsyncInputAndNoReturn(string str, ILambdaContext context) { await Task.Delay(10); } - public async Task SampleHandlerAsyncNoReturn(string str) - { - await Task.Delay(10); - } - - public async Task SampleHandlerAsyncReturn(string str, ILambdaContext context) + // Func> + public async Task SampleHandlerAsyncInputAndReturn(string str, ILambdaContext context) { await Task.Delay(10); return str; } - public async Task SampleHandlerAsyncReturn(string str) + // Func + public async Task SampleHandlerAsyncNoInputAndNoReturn(ILambdaContext context) { await Task.Delay(10); - return str; } public void SampleHandlerSyncNoReturnException(string str, ILambdaContext context) From 902a707728e69e58d59f1fc4165e7d5ffab41b22 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Thu, 28 Jul 2022 17:31:39 +0200 Subject: [PATCH 13/24] - applied review suggestions (#403) --- .../Implementation/AWSLambdaUtils.cs | 84 +++++++++++-------- .../Implementation/AWSLambdaWrapper.cs | 7 +- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index ec695e2bfe..e8b90a2058 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -76,12 +76,7 @@ internal static ActivityContext ExtractParentContext(TInput input) break; } - if (propagationContext != default) - { - return propagationContext.ActivityContext; - } - - return default; + return propagationContext.ActivityContext; } internal static string GetCloudProvider() @@ -104,32 +99,7 @@ internal static string GetFunctionVersion() return Environment.GetEnvironmentVariable(FunctionVersion); } - internal static string GetAccountId(string functionArn) - { - // The fifth item of function arn: https://github.com/open-telemetry/opentelemetry-specification/blob/86aeab1e0a7e6c67be09c7f15ff25063ee6d2b5c/specification/trace/semantic_conventions/instrumentation/aws-lambda.md#all-triggers - // Function arn format - arn:aws:lambda:::function: - - var items = functionArn.Split(':'); - if (items.Length >= 5) - { - return items[4]; - } - - return null; - } - - internal static string GetFaasTrigger(TInput input) - { - var trigger = "other"; - if (input is APIGatewayProxyRequest || input is APIGatewayHttpApiV2ProxyRequest) - { - trigger = "http"; - } - - return trigger; - } - - internal static IEnumerable> GetFunctionDefaultTags(TInput input, ILambdaContext context) + internal static IEnumerable> GetFunctionTags(TInput input, ILambdaContext context) { var tags = new List> { @@ -155,7 +125,7 @@ internal static IEnumerable> GetFunctionDefaultTags var functionArn = context.InvokedFunctionArn; if (functionArn != null) { - tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasID, functionArn)); + tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasID, GetFaasId(functionArn))); var accountId = GetAccountId(functionArn); if (accountId != null) @@ -167,6 +137,49 @@ internal static IEnumerable> GetFunctionDefaultTags return tags; } + private static string GetAccountId(string functionArn) + { + // The fifth item of function arn: https://github.com/open-telemetry/opentelemetry-specification/blob/86aeab1e0a7e6c67be09c7f15ff25063ee6d2b5c/specification/trace/semantic_conventions/instrumentation/aws-lambda.md#all-triggers + // Function arn format - arn:aws:lambda:::function: + + var items = functionArn.Split(':'); + if (items.Length >= 5) + { + return items[4]; + } + + return null; + } + + private static string GetFaasId(string functionArn) + { + 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 (version, see https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html#versioning-versions-using) + // should not be included into faas.id + var items = functionArn.Split(':'); + if (items.Length >= 8) + { + var result = new string[7]; + Array.Copy(items, result, 7); + faasId = string.Join(":", result); + } + + return faasId; + } + + private static string GetFaasTrigger(TInput input) + { + var trigger = "other"; + if (input is APIGatewayProxyRequest || input is APIGatewayHttpApiV2ProxyRequest) + { + trigger = "http"; + } + + return trigger; + } + private static ActivityContext ParseXRayTraceHeader(string rawHeader) { var xrayPropagator = new AWSXRayPropagator(); @@ -197,10 +210,7 @@ private static IEnumerable GetHeaderValues(APIGatewayHttpApiV2ProxyReque request.Headers.TryGetValue(name, out var header)) { // Multiple values for the same header will be separated by a comma. - if (!string.IsNullOrEmpty(header)) - { - return header.Split(','); - } + return header.Split(','); } return null; diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 24ac081c11..df1ac4e82c 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -31,9 +31,6 @@ public class AWSLambdaWrapper /// /// Gets or sets a value indicating whether AWS X-Ray propagation should be ignored. Default value is false. - /// The flag was introduced as a workaround of this issue: - /// the ActivitySource.StartActivity method returns null if sampling decision of DROP (Sampled=0). - /// Flag can be removed as soon as the bug https://github.com/open-telemetry/opentelemetry-dotnet/issues/3290 is resolved. /// internal static bool IgnoreAWSXRayPropagation { get; set; } @@ -196,7 +193,7 @@ internal static Activity OnFunctionStart(TInput input, ILambdaContext co } } - var tags = AWSLambdaUtils.GetFunctionDefaultTags(input, context); + var tags = AWSLambdaUtils.GetFunctionTags(input, context); var activityName = AWSLambdaUtils.GetFunctionName(context) ?? ""; var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, tags); @@ -211,7 +208,7 @@ private static void OnFunctionStop(Activity activity, TracerProvider tracerProvi } // force flush before function quit in case of Lambda freeze. - tracerProvider.ForceFlush(); + tracerProvider?.ForceFlush(); } private static void OnException(Activity activity, Exception exception) From dc06bee8e83610494757584e9316d4b27856b744 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Thu, 28 Jul 2022 17:50:36 +0200 Subject: [PATCH 14/24] - renaming of option for x-ray extraction disabling (#403) --- .../AWSLambdaInstrumentationOptions.cs | 4 ++-- .../Implementation/AWSLambdaWrapper.cs | 4 ++-- .../TracerProviderBuilderExtensions.cs | 2 +- .../AWSLambdaWrapperTests.cs | 8 ++------ 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs index cbcd8bc713..2c3b101380 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs @@ -22,8 +22,8 @@ namespace OpenTelemetry.Contrib.Instrumentation.AWSLambda public class AWSLambdaInstrumentationOptions { /// - /// Gets or sets a value indicating whether AWS X-Ray propagation should be ignored. + /// Gets or sets a value indicating whether AWS X-Ray context extraction should be disabled. /// - public bool IgnoreAWSXRayPropagation { get; set; } + public bool DisableAwsXRayContextExtraction { get; set; } } } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index df1ac4e82c..8b23ece05d 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -32,7 +32,7 @@ public class AWSLambdaWrapper /// /// Gets or sets a value indicating whether AWS X-Ray propagation should be ignored. Default value is false. /// - internal static bool IgnoreAWSXRayPropagation { get; set; } + internal static bool DisableAwsXRayContextExtraction { get; set; } /// /// Tracing wrapper for Lambda handler. @@ -187,7 +187,7 @@ internal static Activity OnFunctionStart(TInput input, ILambdaContext co if (parentContext == default) { parentContext = AWSLambdaUtils.ExtractParentContext(input); - if (parentContext == default && !IgnoreAWSXRayPropagation) + if (parentContext == default && !DisableAwsXRayContextExtraction) { parentContext = AWSLambdaUtils.GetParentContext(); } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs index 54eaf63fcd..6a984a90e7 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs @@ -42,7 +42,7 @@ public static TracerProviderBuilder AddAWSLambdaConfigurations( var options = new AWSLambdaInstrumentationOptions(); configure?.Invoke(options); - AWSLambdaWrapper.IgnoreAWSXRayPropagation = options.IgnoreAWSXRayPropagation; + AWSLambdaWrapper.DisableAwsXRayContextExtraction = options.DisableAwsXRayContextExtraction; builder.AddSource(AWSLambdaUtils.ActivitySourceName); builder.SetResourceBuilder(ResourceBuilder diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index 990181dd3f..724806bac2 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -276,17 +276,13 @@ public void OnFunctionStart_NoParent_ActivityCreated() } [Fact] - public void OnFunctionStart_NoSampledAndXRayPropagationIgnored_ActivityCreated() + public void OnFunctionStart_NoSampledAndAwsXRayContextExtractionDisabled_ActivityCreated() { Environment.SetEnvironmentVariable("_X_AMZN_TRACE_ID", $"Root=1-5759e988-bd862e3fe1be46a994272793;Parent={XRayParentId};Sampled=0"); - Activity activity = null; - // The IgnoreAWSXRayPropagation flag was introduced as a workaround of this issue: - // the ActivitySource.StartActivity method returns null if sampling decision of DROP (Sampled=0). - // Flag can be removed as soon as the bug https://github.com/open-telemetry/opentelemetry-dotnet/issues/3290 is resolved. using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations(c => c.IgnoreAWSXRayPropagation = true) + .AddAWSLambdaConfigurations(c => c.DisableAwsXRayContextExtraction = true) .Build()) { activity = AWSLambdaWrapper.OnFunctionStart("test-input", new Mock().Object); From 72bf5c04fda4fa119383af582207be51062b258c Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Fri, 29 Jul 2022 09:20:08 +0200 Subject: [PATCH 15/24] - simplification: replace array copy with linq expression (#403) --- .../Implementation/AWSLambdaUtils.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index e8b90a2058..3d928fc41c 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using Amazon.Lambda.APIGatewayEvents; using Amazon.Lambda.Core; using OpenTelemetry.Context.Propagation; @@ -161,9 +162,7 @@ private static string GetFaasId(string functionArn) var items = functionArn.Split(':'); if (items.Length >= 8) { - var result = new string[7]; - Array.Copy(items, result, 7); - faasId = string.Join(":", result); + faasId = string.Join(":", items.Take(7)); } return faasId; From aa4ec4323d0bff974fe66c57cc965c0be756c5db Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Fri, 29 Jul 2022 10:21:44 +0200 Subject: [PATCH 16/24] applied improvements from review (#403) --- .../Implementation/AWSLambdaUtils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index 3d928fc41c..32175e07f0 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -157,7 +157,7 @@ private static string GetFaasId(string functionArn) 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 (version, see https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html#versioning-versions-using) + // 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(':'); if (items.Length >= 8) @@ -209,7 +209,7 @@ private static IEnumerable GetHeaderValues(APIGatewayHttpApiV2ProxyReque request.Headers.TryGetValue(name, out var header)) { // Multiple values for the same header will be separated by a comma. - return header.Split(','); + return header?.Split(','); } return null; From 226b40598b77192d17b3b89739e5feda895ab0e1 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin <88040756+rypdal@users.noreply.github.com> Date: Fri, 29 Jul 2022 10:43:51 +0200 Subject: [PATCH 17/24] Update src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit review (#403) Co-authored-by: Christian Neumüller --- .../Implementation/AWSLambdaWrapper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 8b23ece05d..f8b90b4f3b 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -93,7 +93,7 @@ public static void Trace( /// TracerProvider passed in. /// Lambda handler function passed in. /// Instance of input. - /// Instance of lambda context. + /// Lambda context (optional, but strongly recommended). /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. From 0a304a4d0536b117c94828e96503caea70c9214b Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Fri, 29 Jul 2022 11:39:59 +0200 Subject: [PATCH 18/24] added minor suggestions (#403) --- .../Implementation/AWSLambdaWrapper.cs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 8b23ece05d..deb2c8bc04 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -46,7 +46,8 @@ public class AWSLambdaWrapper /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. - /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one + /// unless X-Ray propagation is disabled in the configuration for this wrapper. /// /// Instance of output result. public static TResult Trace( @@ -73,7 +74,8 @@ public static TResult Trace( /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. - /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one + /// unless X-Ray propagation is disabled in the configuration for this wrapper. /// public static void Trace( TracerProvider tracerProvider, @@ -97,10 +99,11 @@ public static void Trace( /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. - /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one + /// unless X-Ray propagation is disabled in the configuration for this wrapper. /// /// Task. - public static async Task Trace( + public static Task Trace( TracerProvider tracerProvider, Func lambdaHandler, TInput input, @@ -108,7 +111,7 @@ public static async Task Trace( ActivityContext parentContext = default) { Func action = async () => await lambdaHandler(input, context); - await TraceInternalAsync(tracerProvider, action, input, context, parentContext); + return TraceInternalAsync(tracerProvider, action, input, context, parentContext); } /// @@ -123,7 +126,8 @@ public static async Task Trace( /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. - /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one + /// unless X-Ray propagation is disabled in the configuration for this wrapper. /// /// Task of result. public static async Task Trace( @@ -148,7 +152,8 @@ public static async Task Trace( /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. - /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one + /// unless X-Ray propagation is disabled in the configuration for this wrapper. /// public static void Trace( TracerProvider tracerProvider, @@ -169,17 +174,18 @@ public static void Trace( /// /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. - /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one. + /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one + /// unless X-Ray propagation is disabled in the configuration for this wrapper. /// /// Task. - public static async Task Trace( + public static Task Trace( TracerProvider tracerProvider, Func lambdaHandler, ILambdaContext context, ActivityContext parentContext = default) { Func action = async () => await lambdaHandler(context); - await TraceInternalAsync(tracerProvider, action, null, context, parentContext); + return TraceInternalAsync(tracerProvider, action, null, context, parentContext); } internal static Activity OnFunctionStart(TInput input, ILambdaContext context, ActivityContext parentContext = default) From 76fc16c0cd15bb11823fad1fac9fcbb29143b719 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Fri, 29 Jul 2022 13:38:51 +0200 Subject: [PATCH 19/24] - renamed the method to avoid confusions (#403) --- .../Implementation/AWSLambdaUtils.cs | 2 +- .../Implementation/AWSLambdaWrapper.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index 32175e07f0..f387ec69a5 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -48,7 +48,7 @@ internal static class AWSLambdaUtils return new string[0]; }; - internal static ActivityContext GetParentContext() + internal static ActivityContext GetXRayParentContext() { // Currently get trace header from Lambda runtime environment variable // https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 2f69bfeb5b..8e51727b8f 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -195,7 +195,7 @@ internal static Activity OnFunctionStart(TInput input, ILambdaContext co parentContext = AWSLambdaUtils.ExtractParentContext(input); if (parentContext == default && !DisableAwsXRayContextExtraction) { - parentContext = AWSLambdaUtils.GetParentContext(); + parentContext = AWSLambdaUtils.GetXRayParentContext(); } } From c114fd0c2d6d847671beab2627bbad26d3241a11 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin <88040756+rypdal@users.noreply.github.com> Date: Fri, 29 Jul 2022 17:11:57 +0200 Subject: [PATCH 20/24] Update src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Christian Neumüller --- .../Implementation/AWSLambdaWrapper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 8e51727b8f..77582f09fc 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -175,7 +175,7 @@ public static void Trace( /// The optional parent context is used for Activity object creation. /// If no parent context provided, incoming request is used to extract one. /// If parent is not extracted from incoming request then X-Ray propagation is used to extract one - /// unless X-Ray propagation is disabled in the configuration for this wrapper. + /// unless X-Ray propagation is disabled in the configuration. /// /// Task. public static Task Trace( From a5228b93cc1f129917b4d27f1413fe4e81582a9e Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin <88040756+rypdal@users.noreply.github.com> Date: Fri, 29 Jul 2022 17:12:09 +0200 Subject: [PATCH 21/24] Update src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Christian Neumüller --- .../Implementation/AWSLambdaWrapper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs index 77582f09fc..4ca66e3c7a 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/Implementation/AWSLambdaWrapper.cs @@ -200,7 +200,7 @@ internal static Activity OnFunctionStart(TInput input, ILambdaContext co } var tags = AWSLambdaUtils.GetFunctionTags(input, context); - var activityName = AWSLambdaUtils.GetFunctionName(context) ?? ""; + var activityName = AWSLambdaUtils.GetFunctionName(context) ?? "AWS Lambda Invoke"; var activity = AWSLambdaActivitySource.StartActivity(activityName, ActivityKind.Server, parentContext, tags); return activity; From 04392cc6a2526cb9b150754fb87e23da9a789ca4 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Fri, 5 Aug 2022 10:11:10 +0200 Subject: [PATCH 22/24] Added brief changes description to CHANGELOG (#403) --- .../CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md index 8928f2bfc5..1ee7c1a04b 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog - OpenTelemetry.Contrib.Instrumentation.AWSLambda +## Unreleased + +* Added public option `AWSLambdaInstrumentationOptions.DisableAwsXRayContextExtraction`. +* Extended public API of the `AWSLambdaWrapper`: added optional parent context (`ActivityContext`) to all `Trace` methods. +* Enhanced parent extraction: if the parent context is not provided then it can be extracted from the incoming request if it's type + is either `APIGatewayProxyRequest` or `APIGatewayHttpApiV2ProxyRequest` (namespace `Amazon.Lambda.APIGatewayEvents`). + If the parent is not extracted from the incoming request then it can be extracted from the AWS X-Ray tracing header + if AWS X-Ray context extraction is not disabled (`DisableAwsXRayContextExtraction`). +* Changed behaviour of the `OnFunctionStart` method: Activity is created even if the parent context is not extracted and has default value. +* Breaking change: `AWSLambdaWrapper.Trace` overloads without `ILambdaContext` argument have been completely removed. All current AWS + lambda triggers provide `ILambdaContext` and it's always possible to pass it from customer's code. +* Two new `AWSLambdaWrapper.Trace` overloads without generic input arguments have been added. + ([#408](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/408)) + ## 1.1.0-beta1 Released 2021-May-26 From cd9ffa824dacc894ac23ded3d4bcc8e0c0aaabe2 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Fri, 5 Aug 2022 10:23:43 +0200 Subject: [PATCH 23/24] Shortened descriptions in CHANGELOG (#403) --- .../CHANGELOG.md | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md index 1ee7c1a04b..2f628445b7 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md @@ -3,15 +3,18 @@ ## Unreleased * Added public option `AWSLambdaInstrumentationOptions.DisableAwsXRayContextExtraction`. -* Extended public API of the `AWSLambdaWrapper`: added optional parent context (`ActivityContext`) to all `Trace` methods. -* Enhanced parent extraction: if the parent context is not provided then it can be extracted from the incoming request if it's type - is either `APIGatewayProxyRequest` or `APIGatewayHttpApiV2ProxyRequest` (namespace `Amazon.Lambda.APIGatewayEvents`). - If the parent is not extracted from the incoming request then it can be extracted from the AWS X-Ray tracing header - if AWS X-Ray context extraction is not disabled (`DisableAwsXRayContextExtraction`). -* Changed behaviour of the `OnFunctionStart` method: Activity is created even if the parent context is not extracted and has default value. -* Breaking change: `AWSLambdaWrapper.Trace` overloads without `ILambdaContext` argument have been completely removed. All current AWS - lambda triggers provide `ILambdaContext` and it's always possible to pass it from customer's code. -* Two new `AWSLambdaWrapper.Trace` overloads without generic input arguments have been added. +* Extended public API of the `AWSLambdaWrapper`: added optional parent + context (`ActivityContext`) to all `Trace` methods. +* Enhanced parent extraction: if the parent context is not provided + then it can be extracted from the incoming request for certain types of the request. + If the parent is not extracted from the incoming request then it can be extracted from + the AWS X-Ray tracing header if AWS X-Ray context extraction + is not disabled (`DisableAwsXRayContextExtraction`). +* Changed behaviour of the `OnFunctionStart` method: Activity is created even + if the parent context is not defined. +* Breaking change: `AWSLambdaWrapper.Trace` overloads without `ILambdaContext` argument + have been completely removed. +* Two new `AWSLambdaWrapper.Trace` overloads without generic input arguments have been added. ([#408](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/408)) ## 1.1.0-beta1 From cc51acf4168836bbe694797d22494f2607bfcb32 Mon Sep 17 00:00:00 2001 From: Oleksiy Dubinin Date: Fri, 5 Aug 2022 10:27:09 +0200 Subject: [PATCH 24/24] CHANGELOG entry lines break (#403) --- .../CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md index 2f628445b7..61ade2e4b0 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWSLambda/CHANGELOG.md @@ -7,14 +7,14 @@ context (`ActivityContext`) to all `Trace` methods. * Enhanced parent extraction: if the parent context is not provided then it can be extracted from the incoming request for certain types of the request. - If the parent is not extracted from the incoming request then it can be extracted from - the AWS X-Ray tracing header if AWS X-Ray context extraction + If the parent is not extracted from the incoming request then it can be extracted + from the AWS X-Ray tracing header if AWS X-Ray context extraction is not disabled (`DisableAwsXRayContextExtraction`). * Changed behaviour of the `OnFunctionStart` method: Activity is created even if the parent context is not defined. * Breaking change: `AWSLambdaWrapper.Trace` overloads without `ILambdaContext` argument have been completely removed. -* Two new `AWSLambdaWrapper.Trace` overloads without generic input arguments have been added. +* Added two new `AWSLambdaWrapper.Trace` overloads without generic input arguments. ([#408](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/408)) ## 1.1.0-beta1