From 0d5c59b9eb88d803f1a4314900192d0777a12ec0 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Fri, 18 Oct 2024 13:24:07 -0700 Subject: [PATCH 01/35] =?UTF-8?q?=EF=BB=BFupgrade=20semantic=20convention?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Implementation/AWSSemanticConventions.cs | 24 ++---- .../OpenTelemetry.Instrumentation.AWS.csproj | 6 +- .../AWSLambdaSemanticConventions.cs | 20 +++-- ...Telemetry.Instrumentation.AWSLambda.csproj | 6 +- .../AWSECSDetector.cs | 3 +- .../AWSSemanticConventions.cs | 83 +++++++++---------- .../OpenTelemetry.Resources.AWS.csproj | 4 + 7 files changed, 75 insertions(+), 71 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSSemanticConventions.cs b/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSSemanticConventions.cs index 61d72da34e..13f96c219d 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSSemanticConventions.cs +++ b/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSSemanticConventions.cs @@ -1,17 +1,14 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.SemanticConventions; + namespace OpenTelemetry.Instrumentation.AWS.Implementation; internal static class AWSSemanticConventions { - public const string AttributeAWSServiceName = "aws.service"; - public const string AttributeAWSOperationName = "aws.operation"; - public const string AttributeAWSRegion = "aws.region"; - public const string AttributeAWSRequestId = "aws.requestId"; - - public const string AttributeAWSDynamoTableName = "aws.table_name"; - public const string AttributeAWSSQSQueueUrl = "aws.queue_url"; + public const string AttributeAWSDynamoTableName = AwsAttributes.AttributeAwsDynamodbTableNames; // todo - confirm in java; + public const string AttributeAWSSQSQueueUrl = "aws.queue_url"; // todo - confirm in java; // AWS Bedrock service attributes not yet defined in semantic conventions public const string AttributeAWSBedrockAgentId = "aws.bedrock.agent.id"; @@ -21,15 +18,10 @@ internal static class AWSSemanticConventions public const string AttributeAWSBedrock = "aws_bedrock"; // should be global convention for Gen AI attributes - public const string AttributeGenAiModelId = "gen_ai.request.model"; - public const string AttributeGenAiSystem = "gen_ai.system"; - - public const string AttributeHttpStatusCode = "http.status_code"; - public const string AttributeHttpResponseContentLength = "http.response_content_length"; + public const string AttributeGenAiModelId = GenAiAttributes.AttributeGenAiRequestModel; + public const string AttributeGenAiSystem = GenAiAttributes.AttributeGenAiSystem; - public const string AttributeValueDynamoDb = "dynamodb"; + //public const string AttributeHttpStatusCode = "http.status_code"; - public const string AttributeValueRPCSystem = "rpc.system"; - public const string AttributeValueRPCService = "rpc.service"; - public const string AttributeValueRPCMethod = "rpc.method"; + public const string AttributeValueDynamoDb = DbAttributes.DbSystemValues.Dynamodb; } diff --git a/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj b/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj index b4b422dd49..ea3b04818c 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj +++ b/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj @@ -1,4 +1,4 @@ - + @@ -30,4 +30,8 @@ + + + + diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs index 6cfad894bb..17d6ac2732 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.SemanticConventions; + namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation; /// @@ -8,13 +10,13 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation; /// internal static class AWSLambdaSemanticConventions { - public const string AttributeCloudAccountID = "cloud.account.id"; - public const string AttributeCloudProvider = "cloud.provider"; - public const string AttributeCloudRegion = "cloud.region"; - public const string AttributeFaasExecution = "faas.execution"; - public const string AttributeFaasID = "faas.id"; - public const string AttributeFaasName = "faas.name"; - public const string AttributeFaasVersion = "faas.version"; - public const string AttributeFaasTrigger = "faas.trigger"; - public const string AttributeFaasColdStart = "faas.coldstart"; + public const string AttributeCloudAccountID = CloudAttributes.AttributeCloudAccountId; + public const string AttributeCloudProvider = CloudAttributes.AttributeCloudProvider; + public const string AttributeCloudRegion = CloudAttributes.AttributeCloudRegion; + public const string AttributeFaasExecution = FaasAttributes.AttributeFaasInvocationId; + public const string AttributeFaasID = CloudAttributes.AttributeCloudResourceId; + public const string AttributeFaasName = FaasAttributes.AttributeFaasName; + public const string AttributeFaasVersion = FaasAttributes.AttributeFaasVersion; + public const string AttributeFaasTrigger = FaasAttributes.AttributeFaasTrigger; + public const string AttributeFaasColdStart = FaasAttributes.AttributeFaasColdstart; } diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj b/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj index 3c3147cc76..fbfa37a584 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj @@ -29,7 +29,11 @@ - + + + + + diff --git a/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs b/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs index 0f527f6a84..54285c9bd1 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs @@ -4,6 +4,7 @@ #if NET using System.Text.Json; using System.Text.RegularExpressions; +using OpenTelemetry.SemanticConventions; namespace OpenTelemetry.Resources.AWS; @@ -38,7 +39,7 @@ public Resource Detect() var containerId = GetECSContainerId(AWSECSMetadataPath); if (containerId != null) { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeContainerID, containerId)); + resourceAttributes.Add(new KeyValuePair(ContainerAttributes.AttributeContainerId, containerId)); } } catch (Exception ex) diff --git a/src/OpenTelemetry.Resources.AWS/AWSSemanticConventions.cs b/src/OpenTelemetry.Resources.AWS/AWSSemanticConventions.cs index 049047ea70..01006f49b4 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSSemanticConventions.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSSemanticConventions.cs @@ -1,52 +1,49 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.SemanticConventions; + namespace OpenTelemetry.Resources.AWS; internal static class AWSSemanticConventions { - public const string AttributeCloudAccountID = "cloud.account.id"; - public const string AttributeCloudAvailabilityZone = "cloud.availability_zone"; - public const string AttributeCloudPlatform = "cloud.platform"; - public const string AttributeCloudProvider = "cloud.provider"; - public const string AttributeCloudRegion = "cloud.region"; - public const string AttributeCloudResourceId = "cloud.resource_id"; - public const string CloudPlatformValuesAwsEc2 = "aws_ec2"; - public const string CloudPlatformValuesAwsEcs = "aws_ecs"; - public const string CloudPlatformValuesAwsEks = "aws_eks"; - public const string CloudPlatformValuesAwsElasticBeanstalk = "aws_elastic_beanstalk"; - public const string CloudProviderValuesAws = "aws"; - - public const string AttributeContainerID = "container.id"; - - public const string AttributeEcsContainerArn = "aws.ecs.container.arn"; - public const string AttributeEcsClusterArn = "aws.ecs.cluster.arn"; - public const string AttributeEcsLaunchtype = "aws.ecs.launchtype"; - public const string ValueEcsLaunchTypeEc2 = "ec2"; - public const string ValueEcsLaunchTypeFargate = "fargate"; - public const string AttributeEcsTaskArn = "aws.ecs.task.arn"; - public const string AttributeEcsTaskFamily = "aws.ecs.task.family"; - public const string AttributeEcsTaskRevision = "aws.ecs.task.revision"; - - public const string AttributeFaasExecution = "faas.execution"; - public const string AttributeFaasID = "faas.id"; - public const string AttributeFaasName = "faas.name"; - public const string AttributeFaasVersion = "faas.version"; - - public const string AttributeHostID = "host.id"; - public const string AttributeHostType = "host.type"; - public const string AttributeHostName = "host.name"; - - public const string AttributeK8SClusterName = "k8s.cluster.name"; - - public const string AttributeLogGroupNames = "aws.log.group.names"; - public const string AttributeLogGroupArns = "aws.log.group.arns"; - public const string AttributeLogStreamNames = "aws.log.stream.names"; - public const string AttributeLogStreamArns = "aws.log.stream.arns"; - - public const string AttributeServiceName = "service.name"; - public const string AttributeServiceNamespace = "service.namespace"; - public const string AttributeServiceInstanceID = "service.instance.id"; - public const string AttributeServiceVersion = "service.version"; + public const string AttributeCloudAccountID = CloudAttributes.AttributeCloudAccountId; + public const string AttributeCloudAvailabilityZone = CloudAttributes.AttributeCloudAvailabilityZone; + public const string AttributeCloudPlatform = CloudAttributes.AttributeCloudPlatform; + public const string AttributeCloudProvider = CloudAttributes.AttributeCloudProvider; + public const string AttributeCloudRegion = CloudAttributes.AttributeCloudRegion; + public const string AttributeCloudResourceId = CloudAttributes.AttributeCloudResourceId; + public const string CloudPlatformValuesAwsEc2 = CloudAttributes.CloudPlatformValues.AwsEc2; + public const string CloudPlatformValuesAwsEcs = CloudAttributes.CloudPlatformValues.AwsEcs; + public const string CloudPlatformValuesAwsEks = CloudAttributes.CloudPlatformValues.AwsEks; + public const string CloudPlatformValuesAwsElasticBeanstalk = CloudAttributes.CloudPlatformValues.AwsElasticBeanstalk; + public const string CloudProviderValuesAws = CloudAttributes.CloudProviderValues.Aws; + + public const string AttributeContainerID = ContainerAttributes.AttributeContainerId; + + public const string AttributeEcsContainerArn = AwsAttributes.AttributeAwsEcsContainerArn; + public const string AttributeEcsClusterArn = AwsAttributes.AttributeAwsEcsClusterArn; + public const string AttributeEcsLaunchtype = AwsAttributes.AttributeAwsEcsLaunchtype; + public const string ValueEcsLaunchTypeEc2 = AwsAttributes.AwsEcsLaunchtypeValues.Ec2; + public const string ValueEcsLaunchTypeFargate = AwsAttributes.AwsEcsLaunchtypeValues.Fargate; + public const string AttributeEcsTaskArn = AwsAttributes.AttributeAwsEcsTaskArn; + public const string AttributeEcsTaskFamily = AwsAttributes.AttributeAwsEcsTaskFamily; + public const string AttributeEcsTaskRevision = AwsAttributes.AttributeAwsEcsTaskRevision; + + public const string AttributeHostID = HostAttributes.AttributeHostId; + public const string AttributeHostType = HostAttributes.AttributeHostType; + public const string AttributeHostName = HostAttributes.AttributeHostName; + + public const string AttributeK8SClusterName = K8sAttributes.AttributeK8sClusterName; + + public const string AttributeLogGroupNames = AwsAttributes.AttributeAwsLogGroupNames; + public const string AttributeLogGroupArns = AwsAttributes.AttributeAwsLogGroupArns; + public const string AttributeLogStreamNames = AwsAttributes.AttributeAwsLogStreamArns; + public const string AttributeLogStreamArns = AwsAttributes.AttributeAwsLogStreamNames; + + public const string AttributeServiceName = ServiceAttributes.AttributeServiceName; + public const string AttributeServiceNamespace = ServiceAttributes.AttributeServiceNamespace; + public const string AttributeServiceInstanceID = ServiceAttributes.AttributeServiceInstanceId; + public const string AttributeServiceVersion = ServiceAttributes.AttributeServiceVersion; public const string ServiceNameValuesAwsElasticBeanstalk = "aws_elastic_beanstalk"; } diff --git a/src/OpenTelemetry.Resources.AWS/OpenTelemetry.Resources.AWS.csproj b/src/OpenTelemetry.Resources.AWS/OpenTelemetry.Resources.AWS.csproj index 6c9fe6bf60..2c29ec41cc 100644 --- a/src/OpenTelemetry.Resources.AWS/OpenTelemetry.Resources.AWS.csproj +++ b/src/OpenTelemetry.Resources.AWS/OpenTelemetry.Resources.AWS.csproj @@ -31,4 +31,8 @@ + + + + From 4e8d2659c3102c618fd55f9354722f4a3e25a4f4 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Mon, 4 Nov 2024 21:32:12 -0800 Subject: [PATCH 02/35] Use a builder pattern for resource attributes --- .../AWSClientInstrumentationOptions.cs | 5 + .../Implementation/AWSSemanticConventions.cs | 27 -- .../Implementation/AWSServiceHelper.cs | 20 +- .../AWSTracingPipelineHandler.cs | 5 +- .../OpenTelemetry.Instrumentation.AWS.csproj | 3 +- .../AWSLambdaInstrumentationOptions.cs | 5 + .../Implementation/AWSLambdaHttpUtils.cs | 20 +- .../AWSLambdaResourceDetector.cs | 26 +- .../AWSLambdaSemanticConventions.cs | 22 -- .../Implementation/AWSLambdaUtils.cs | 47 +-- ...Telemetry.Instrumentation.AWSLambda.csproj | 1 + .../TracerProviderBuilderExtensions.cs | 3 + .../AWSEBSDetector.cs | 33 +- .../AWSEC2Detector.cs | 45 +-- .../AWSECSDetector.cs | 55 ++- .../AWSEKSDetector.cs | 19 +- .../AWSResourceBuilderExtensions.cs | 33 +- .../AWSResourceBuilderOptions.cs | 15 + .../AWSSemanticConventions.cs | 49 --- .../OpenTelemetry.Resources.AWS.csproj | 1 + src/Shared/AWS/AWSSemanticConventions.cs | 348 ++++++++++++++++++ .../AWSLambdaWrapperTests.cs | 34 +- .../AWSEBSDetectorTests.cs | 10 + .../AWSEC2DetectorTests.cs | 28 +- .../AWSECSDetectorTests.cs | 83 +++-- .../AWSEKSDetectorTests.cs | 28 +- 26 files changed, 626 insertions(+), 339 deletions(-) delete mode 100644 src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSSemanticConventions.cs delete mode 100644 src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs create mode 100644 src/OpenTelemetry.Resources.AWS/AWSResourceBuilderOptions.cs delete mode 100644 src/OpenTelemetry.Resources.AWS/AWSSemanticConventions.cs create mode 100644 src/Shared/AWS/AWSSemanticConventions.cs diff --git a/src/OpenTelemetry.Instrumentation.AWS/AWSClientInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.AWS/AWSClientInstrumentationOptions.cs index f476d1915d..aaa5bd8d9a 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/AWSClientInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.AWS/AWSClientInstrumentationOptions.cs @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AWS; + namespace OpenTelemetry.Instrumentation.AWS; /// @@ -12,4 +14,7 @@ public class AWSClientInstrumentationOptions /// Gets or sets a value indicating whether downstream instrumentation is suppressed. /// public bool SuppressDownstreamInstrumentation { get; set; } + + /// + public SemanticConventionVersion SemanticConventionVersion { get; set; } = AWSSemanticConventions.DefaultSemanticConventionVersion; } diff --git a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSSemanticConventions.cs b/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSSemanticConventions.cs deleted file mode 100644 index 13f96c219d..0000000000 --- a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSSemanticConventions.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -using OpenTelemetry.SemanticConventions; - -namespace OpenTelemetry.Instrumentation.AWS.Implementation; - -internal static class AWSSemanticConventions -{ - public const string AttributeAWSDynamoTableName = AwsAttributes.AttributeAwsDynamodbTableNames; // todo - confirm in java; - public const string AttributeAWSSQSQueueUrl = "aws.queue_url"; // todo - confirm in java; - - // AWS Bedrock service attributes not yet defined in semantic conventions - public const string AttributeAWSBedrockAgentId = "aws.bedrock.agent.id"; - public const string AttributeAWSBedrockDataSourceId = "aws.bedrock.data_source.id"; - public const string AttributeAWSBedrockGuardrailId = "aws.bedrock.guardrail.id"; - public const string AttributeAWSBedrockKnowledgeBaseId = "aws.bedrock.knowledge_base.id"; - public const string AttributeAWSBedrock = "aws_bedrock"; - - // should be global convention for Gen AI attributes - public const string AttributeGenAiModelId = GenAiAttributes.AttributeGenAiRequestModel; - public const string AttributeGenAiSystem = GenAiAttributes.AttributeGenAiSystem; - - //public const string AttributeHttpStatusCode = "http.status_code"; - - public const string AttributeValueDynamoDb = DbAttributes.DbSystemValues.Dynamodb; -} diff --git a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSServiceHelper.cs b/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSServiceHelper.cs index 7e87865b3c..bb0b3aa1f3 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSServiceHelper.cs +++ b/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSServiceHelper.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using Amazon.Runtime; +using OpenTelemetry.AWS; namespace OpenTelemetry.Instrumentation.AWS.Implementation; @@ -22,16 +23,15 @@ internal class AWSServiceHelper { AWSServiceType.BedrockAgentService, ["AgentId", "DataSourceId"] }, }; - internal static IReadOnlyDictionary ParameterAttributeMap = new Dictionary() - { - { "TableName", AWSSemanticConventions.AttributeAWSDynamoTableName }, - { "QueueUrl", AWSSemanticConventions.AttributeAWSSQSQueueUrl }, - { "ModelId", AWSSemanticConventions.AttributeGenAiModelId }, - { "AgentId", AWSSemanticConventions.AttributeAWSBedrockAgentId }, - { "DataSourceId", AWSSemanticConventions.AttributeAWSBedrockDataSourceId }, - { "GuardrailId", AWSSemanticConventions.AttributeAWSBedrockGuardrailId }, - { "KnowledgeBaseId", AWSSemanticConventions.AttributeAWSBedrockKnowledgeBaseId }, - }; + internal static IDictionary ParameterAttributeMap = + new Dictionary() + .AddAttributeAWSDynamoTableName("TableName") + .AddAttributeAWSSQSQueueUrl("QueueUrl") + .AddAttributeGenAiModelId("ModelId") + .AddAttributeAWSBedrockAgentId("AgentId") + .AddAttributeAWSBedrockDataSourceId("DataSourceId") + .AddAttributeAWSBedrockGuardrailId("GuardrailId") + .AddAttributeAWSBedrockKnowledgeBaseId("KnowledgeBaseId"); // for Bedrock Agent operations, we map each supported operation to one resource: Agent, DataSource, or KnowledgeBase internal static List BedrockAgentAgentOps = diff --git a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs b/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs index 2a13fed2ba..6497c569e9 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs +++ b/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs @@ -5,6 +5,7 @@ using Amazon.Runtime; using Amazon.Runtime.Internal; using Amazon.Runtime.Telemetry; +using OpenTelemetry.AWS; using OpenTelemetry.Context.Propagation; using OpenTelemetry.Trace; @@ -161,7 +162,7 @@ private static void AddRequestSpecificInformation(Activity activity, IRequestCon if (AWSServiceType.IsDynamoDbService(service)) { - activity.SetTag(SemanticConventions.AttributeDbSystem, AWSSemanticConventions.AttributeValueDynamoDb); + activity.SetTagAttributeDbSystemToDynamoDb(); } else if (AWSServiceType.IsSqsService(service)) { @@ -175,7 +176,7 @@ private static void AddRequestSpecificInformation(Activity activity, IRequestCon } else if (AWSServiceType.IsBedrockRuntimeService(service)) { - activity.SetTag(AWSSemanticConventions.AttributeGenAiSystem, AWSSemanticConventions.AttributeAWSBedrock); + activity.SetTagAttributeGenAiSystemToBedrock(); } } diff --git a/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj b/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj index ea3b04818c..3c394a43c5 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj +++ b/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj @@ -1,4 +1,4 @@ - + @@ -25,6 +25,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs index df3f8befc6..457175d389 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AWS; + namespace OpenTelemetry.Instrumentation.AWSLambda; /// @@ -21,4 +23,7 @@ public class AWSLambdaInstrumentationOptions /// Currently, the only event type to which this applies is SQS. /// public bool SetParentFromBatch { get; set; } + + /// + public SemanticConventionVersion SemanticConventionVersion { get; set; } = AWSSemanticConventions.DefaultSemanticConventionVersion; } diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs index 958f3923c1..1d9a73f7ac 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs @@ -6,7 +6,8 @@ using System.Web; using Amazon.Lambda.APIGatewayEvents; using Amazon.Lambda.ApplicationLoadBalancerEvents; -using OpenTelemetry.Trace; +using OpenTelemetry.AWS; +using OpenTelemetry.Internal; namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation; @@ -54,11 +55,12 @@ internal static IEnumerable> GetHttpTags(TI return tags; } - tags.AddTagIfNotNull(SemanticConventions.AttributeHttpScheme, httpScheme); - tags.AddTagIfNotNull(SemanticConventions.AttributeHttpTarget, httpTarget); - tags.AddTagIfNotNull(SemanticConventions.AttributeHttpMethod, httpMethod); - tags.AddTagIfNotNull(SemanticConventions.AttributeNetHostName, hostName); - tags.AddTagIfNotNull(SemanticConventions.AttributeNetHostPort, hostPort); + tags + .AddAttributeHttpScheme(httpScheme) + .AddAttributeHttpTarget(httpTarget) + .AddAttributeHttpMethod(httpMethod) + .AddAttributeNetHostName(hostName) + .AddAttributeNetHostPort(hostPort); return tags; } @@ -73,13 +75,13 @@ internal static void SetHttpTagsFromResult(Activity? activity, object? result) switch (result) { case APIGatewayProxyResponse response: - activity.SetTag(SemanticConventions.AttributeHttpStatusCode, response.StatusCode); + activity.SetTagAttributeHttpStatusCode(response.StatusCode); break; case APIGatewayHttpApiV2ProxyResponse responseV2: - activity.SetTag(SemanticConventions.AttributeHttpStatusCode, responseV2.StatusCode); + activity.SetTagAttributeHttpStatusCode(responseV2.StatusCode); break; case ApplicationLoadBalancerResponse albResponse: - activity.SetTag(SemanticConventions.AttributeHttpStatusCode, albResponse.StatusCode); + activity.SetTagAttributeHttpStatusCode(albResponse.StatusCode); break; default: break; diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaResourceDetector.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaResourceDetector.cs index c3f43a55b9..45cc6d4c8c 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaResourceDetector.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaResourceDetector.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AWS; using OpenTelemetry.Resources; namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation; @@ -13,25 +14,12 @@ internal sealed class AWSLambdaResourceDetector : IResourceDetector /// Detected resource. public Resource Detect() { - var resourceAttributes = new List>(4) - { - new(AWSLambdaSemanticConventions.AttributeCloudProvider, AWSLambdaUtils.GetCloudProvider()), - }; - - if (AWSLambdaUtils.GetAWSRegion() is { } region) - { - resourceAttributes.Add(new(AWSLambdaSemanticConventions.AttributeCloudRegion, region)); - } - - if (AWSLambdaUtils.GetFunctionName() is { } functionName) - { - resourceAttributes.Add(new(AWSLambdaSemanticConventions.AttributeFaasName, functionName)); - } - - if (AWSLambdaUtils.GetFunctionVersion() is { } functionVersion) - { - resourceAttributes.Add(new(AWSLambdaSemanticConventions.AttributeFaasVersion, functionVersion)); - } + var resourceAttributes = + new List>(4) + .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) + .AddAttributeCloudRegion(AWSLambdaUtils.GetAWSRegion()) + .AddAttributeFaasName(AWSLambdaUtils.GetFunctionName()) + .AddAttributeFaasVersion(AWSLambdaUtils.GetFunctionVersion()); return new Resource(resourceAttributes); } diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs deleted file mode 100644 index 17d6ac2732..0000000000 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaSemanticConventions.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -using OpenTelemetry.SemanticConventions; - -namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation; - -/// -/// Semantic conventions for AWS Lambda. -/// -internal static class AWSLambdaSemanticConventions -{ - public const string AttributeCloudAccountID = CloudAttributes.AttributeCloudAccountId; - public const string AttributeCloudProvider = CloudAttributes.AttributeCloudProvider; - public const string AttributeCloudRegion = CloudAttributes.AttributeCloudRegion; - public const string AttributeFaasExecution = FaasAttributes.AttributeFaasInvocationId; - public const string AttributeFaasID = CloudAttributes.AttributeCloudResourceId; - public const string AttributeFaasName = FaasAttributes.AttributeFaasName; - public const string AttributeFaasVersion = FaasAttributes.AttributeFaasVersion; - public const string AttributeFaasTrigger = FaasAttributes.AttributeFaasTrigger; - public const string AttributeFaasColdStart = FaasAttributes.AttributeFaasColdstart; -} diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index 56902fa909..31aabeb321 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -7,6 +7,7 @@ using Amazon.Lambda.Core; using Amazon.Lambda.SNSEvents; using Amazon.Lambda.SQSEvents; +using OpenTelemetry.AWS; using OpenTelemetry.Context.Propagation; using OpenTelemetry.Extensions.AWS.Trace; @@ -17,7 +18,6 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation; /// internal static class AWSLambdaUtils { - private const string CloudProvider = "aws"; private const string AWSRegion = "AWS_REGION"; private const string AWSXRayLambdaTraceHeaderKey = "_X_AMZN_TRACE_ID"; private const string AWSXRayTraceHeaderKey = "X-Amzn-Trace-Id"; @@ -79,11 +79,6 @@ internal static (ActivityContext ParentContext, IEnumerable? Links return (parentContext.ActivityContext, links); } - internal static string GetCloudProvider() - { - return CloudProvider; - } - internal static string? GetAWSRegion() { return Environment.GetEnvironmentVariable(AWSRegion); @@ -101,34 +96,15 @@ internal static string GetCloudProvider() internal static IEnumerable> GetFunctionTags(TInput input, ILambdaContext context, bool isColdStart) { - var tags = new List> - { - new(AWSLambdaSemanticConventions.AttributeFaasTrigger, GetFaasTrigger(input)), - new(AWSLambdaSemanticConventions.AttributeFaasColdStart, isColdStart), - }; - - var functionName = GetFunctionName(context); - if (functionName != null) - { - tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasName, functionName)); - } - - if (context.AwsRequestId != null) - { - tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasExecution, context.AwsRequestId)); - } - var functionArn = context.InvokedFunctionArn; - if (functionArn != null) - { - tags.Add(new(AWSLambdaSemanticConventions.AttributeFaasID, GetFaasId(functionArn))); - var accountId = GetAccountId(functionArn); - if (accountId != null) - { - tags.Add(new(AWSLambdaSemanticConventions.AttributeCloudAccountID, accountId)); - } - } + var tags = new List>() + .AddAttributeFaasTrigger(GetFaasTrigger(input)) + .AddAttributeFaasColdStart(isColdStart) + .AddAttributeFaasName(GetFunctionName(context)) + .AddAttributeFaasExecution(context.AwsRequestId) + .AddAttributeFaasID(GetFaasId(functionArn)) + .AddAttributeCloudAccountID(GetAccountId(functionArn)); return tags; } @@ -170,8 +146,13 @@ internal static IEnumerable> GetFunctionTags request.Headers?.GetValueByKeyIgnoringCase(name); - private static string? GetAccountId(string functionArn) + private static string? GetAccountId(string? functionArn) { + if (string.IsNullOrEmpty(functionArn)) + { + return null; + } + // 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: diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj b/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj index fbfa37a584..1ab124503b 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/OpenTelemetry.Instrumentation.AWSLambda.csproj @@ -27,6 +27,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs index af51d60881..7ff05baf9c 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/TracerProviderBuilderExtensions.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AWS; using OpenTelemetry.Instrumentation.AWSLambda.Implementation; using OpenTelemetry.Internal; using OpenTelemetry.Trace; @@ -35,6 +36,8 @@ public static TracerProviderBuilder AddAWSLambdaConfigurations( var options = new AWSLambdaInstrumentationOptions(); configure?.Invoke(options); + AWSSemanticConventions.SemanticConventionVersion = options.SemanticConventionVersion; + AWSLambdaWrapper.DisableAwsXRayContextExtraction = options.DisableAwsXRayContextExtraction; AWSMessagingUtils.SetParentFromMessageBatch = options.SetParentFromBatch; diff --git a/src/OpenTelemetry.Resources.AWS/AWSEBSDetector.cs b/src/OpenTelemetry.Resources.AWS/AWSEBSDetector.cs index be18b19080..2acc505a19 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSEBSDetector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSEBSDetector.cs @@ -4,6 +4,7 @@ #if NET using System.Runtime.InteropServices; #endif +using OpenTelemetry.AWS; using OpenTelemetry.Resources.AWS.Models; namespace OpenTelemetry.Resources.AWS; @@ -54,30 +55,14 @@ public Resource Detect() internal static List> ExtractResourceAttributes(AWSEBSMetadataModel? metadata) { - var resourceAttributes = new List>() - { - new(AWSSemanticConventions.AttributeCloudProvider, AWSSemanticConventions.CloudProviderValuesAws), - new(AWSSemanticConventions.AttributeCloudPlatform, AWSSemanticConventions.CloudPlatformValuesAwsElasticBeanstalk), - new(AWSSemanticConventions.AttributeServiceName, AWSSemanticConventions.ServiceNameValuesAwsElasticBeanstalk), - }; - - if (metadata != null) - { - if (metadata.EnvironmentName != null) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeServiceNamespace, metadata.EnvironmentName)); - } - - if (metadata.DeploymentId != null) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeServiceInstanceID, metadata.DeploymentId)); - } - - if (metadata.VersionLabel != null) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeServiceVersion, metadata.VersionLabel)); - } - } + var resourceAttributes = + new List>() + .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) + .AddAttributeCloudPlatform(AWSSemanticConventions.CloudPlatformValuesAwsElasticBeanstalk) + .AddAttributeServiceName(AWSSemanticConventions.ServiceNameValuesAwsElasticBeanstalk) + .AddAttributeServiceNamespace(metadata?.EnvironmentName) + .AddAttributeServiceInstanceID(metadata?.DeploymentId) + .AddAttributeServiceVersion(metadata?.VersionLabel); return resourceAttributes; } diff --git a/src/OpenTelemetry.Resources.AWS/AWSEC2Detector.cs b/src/OpenTelemetry.Resources.AWS/AWSEC2Detector.cs index d93ed52611..93b3f14ce2 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSEC2Detector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSEC2Detector.cs @@ -4,6 +4,7 @@ #if NETFRAMEWORK using System.Net.Http; #endif +using OpenTelemetry.AWS; using OpenTelemetry.Resources.AWS.Models; namespace OpenTelemetry.Resources.AWS; @@ -43,40 +44,16 @@ public Resource Detect() internal static List> ExtractResourceAttributes(AWSEC2IdentityDocumentModel? identity, string hostName) { - var resourceAttributes = new List>() - { - new(AWSSemanticConventions.AttributeCloudProvider, AWSSemanticConventions.CloudProviderValuesAws), - new(AWSSemanticConventions.AttributeCloudPlatform, AWSSemanticConventions.CloudPlatformValuesAwsEc2), - new(AWSSemanticConventions.AttributeHostName, hostName), - }; - - if (identity != null) - { - if (identity.AccountId != null) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeCloudAccountID, identity.AccountId)); - } - - if (identity.AvailabilityZone != null) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeCloudAvailabilityZone, identity.AvailabilityZone)); - } - - if (identity.InstanceId != null) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeHostID, identity.InstanceId)); - } - - if (identity.InstanceType != null) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeHostType, identity.InstanceType)); - } - - if (identity.Region != null) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeCloudRegion, identity.Region)); - } - } + var resourceAttributes = + new List>() + .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) + .AddAttributeCloudPlatform(AWSSemanticConventions.CloudPlatformValuesAwsEc2) + .AddAttributeHostName(hostName) + .AddAttributeCloudAccountID(identity?.AccountId) + .AddAttributeCloudAvailabilityZone(identity?.AvailabilityZone) + .AddAttributeHostID(identity?.InstanceId) + .AddAttributeHostType(identity?.InstanceType) + .AddAttributeCloudRegion(identity?.Region); return resourceAttributes; } diff --git a/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs b/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs index 54285c9bd1..550103ce2c 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs @@ -4,6 +4,7 @@ #if NET using System.Text.Json; using System.Text.RegularExpressions; +using OpenTelemetry.AWS; using OpenTelemetry.SemanticConventions; namespace OpenTelemetry.Resources.AWS; @@ -28,18 +29,16 @@ public Resource Detect() return Resource.Empty; } - var resourceAttributes = new List>() - { - new(AWSSemanticConventions.AttributeCloudProvider, AWSSemanticConventions.CloudProviderValuesAws), - new(AWSSemanticConventions.AttributeCloudPlatform, AWSSemanticConventions.CloudPlatformValuesAwsEcs), - }; - + var resourceAttributes = + new List>() + .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) + .AddAttributeCloudPlatform(AWSSemanticConventions.CloudPlatformValuesAwsEcs); try { var containerId = GetECSContainerId(AWSECSMetadataPath); if (containerId != null) { - resourceAttributes.Add(new KeyValuePair(ContainerAttributes.AttributeContainerId, containerId)); + resourceAttributes.AddAttributeContainerId(containerId); } } catch (Exception ex) @@ -95,15 +94,13 @@ internal static List> ExtractMetadataV4ResourceAttr } var resourceAttributes = new List>() - { - new(AWSSemanticConventions.AttributeCloudResourceId, containerArn), - new(AWSSemanticConventions.AttributeEcsContainerArn, containerArn), - new(AWSSemanticConventions.AttributeEcsClusterArn, clusterArn), - }; + .AddAttributeCloudResourceId(containerArn) + .AddAttributeEcsContainerArn(containerArn) + .AddAttributeEcsClusterArn(clusterArn); if (taskResponse.RootElement.TryGetProperty("AvailabilityZone", out var availabilityZoneElement) && availabilityZoneElement.ValueKind == JsonValueKind.String) { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeCloudAvailabilityZone, availabilityZoneElement.GetString()!)); + resourceAttributes.AddAttributeCloudAvailabilityZone(availabilityZoneElement.GetString()!); } if (!taskResponse.RootElement.TryGetProperty("LaunchType", out var launchTypeElement)) @@ -111,16 +108,13 @@ internal static List> ExtractMetadataV4ResourceAttr launchTypeElement = default; } - var launchType = launchTypeElement switch + if (string.Equals("ec2", launchTypeElement.GetString(), StringComparison.OrdinalIgnoreCase)) { - { ValueKind: JsonValueKind.String } when string.Equals("ec2", launchTypeElement.GetString(), StringComparison.OrdinalIgnoreCase) => AWSSemanticConventions.ValueEcsLaunchTypeEc2, - { ValueKind: JsonValueKind.String } when string.Equals("fargate", launchTypeElement.GetString(), StringComparison.OrdinalIgnoreCase) => AWSSemanticConventions.ValueEcsLaunchTypeFargate, - _ => null, - }; - - if (launchType != null) + resourceAttributes.AddAttributeEcsLaunchtypeIsEc2(); + } + else if (string.Equals("fargate", launchTypeElement.GetString(), StringComparison.OrdinalIgnoreCase)) { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeEcsLaunchtype, launchType)); + resourceAttributes.AddAttributeEcsLaunchtypeIsFargate(); } else { @@ -130,24 +124,25 @@ internal static List> ExtractMetadataV4ResourceAttr if (taskResponse.RootElement.TryGetProperty("TaskARN", out var taskArnElement) && taskArnElement.ValueKind == JsonValueKind.String) { var taskArn = taskArnElement.GetString()!; - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeEcsTaskArn, taskArn)); + resourceAttributes + .AddAttributeEcsTaskArn(taskArn); var arnParts = taskArn.Split(':'); if (arnParts.Length > 5) { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeCloudAccountID, arnParts[4])); - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeCloudRegion, arnParts[3])); + resourceAttributes.AddAttributeCloudAccountID(arnParts[4]); + resourceAttributes.AddAttributeCloudRegion(arnParts[3]); } } if (taskResponse.RootElement.TryGetProperty("Family", out var familyElement) && familyElement.ValueKind == JsonValueKind.String) { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeEcsTaskFamily, familyElement.GetString()!)); + resourceAttributes.AddAttributeEcsTaskFamily(familyElement.GetString()!); } if (taskResponse.RootElement.TryGetProperty("Revision", out var revisionElement) && revisionElement.ValueKind == JsonValueKind.String) { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeEcsTaskRevision, revisionElement.GetString()!)); + resourceAttributes.AddAttributeEcsTaskRevision(revisionElement.GetString()!); } if (containerResponse.RootElement.TryGetProperty("LogDriver", out var logDriverElement) @@ -170,14 +165,14 @@ internal static List> ExtractMetadataV4ResourceAttr if (logOptionsElement.TryGetProperty("awslogs-group", out var logGroupElement) && logGroupElement.ValueKind == JsonValueKind.String) { var logGroupName = logGroupElement.GetString()!; - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeLogGroupNames, new[] { logGroupName })); - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeLogGroupArns, new[] { $"arn:aws:logs:{logsRegion}:{logsAccount}:log-group:{logGroupName}:*" })); + resourceAttributes.AddAttributeLogGroupNames(new[] { logGroupName }); + resourceAttributes.AddAttributeLogGroupArns(new[] { $"arn:aws:logs:{logsRegion}:{logsAccount}:log-group:{logGroupName}:*" }); if (logOptionsElement.TryGetProperty("awslogs-stream", out var logStreamElement) && logStreamElement.ValueKind == JsonValueKind.String) { var logStreamName = logStreamElement.GetString()!; - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeLogStreamNames, new[] { logStreamName })); - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeLogStreamArns, new[] { $"arn:aws:logs:{logsRegion}:{logsAccount}:log-group:{logGroupName}:log-stream:{logStreamName}" })); + resourceAttributes.AddAttributeLogStreamNames(new[] { logStreamName }); + resourceAttributes.AddAttributeLogStreamArns(new[] { $"arn:aws:logs:{logsRegion}:{logsAccount}:log-group:{logGroupName}:log-stream:{logStreamName}" }); } } } diff --git a/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs b/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs index 8d0860c4af..ec1f3b3669 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs @@ -3,6 +3,7 @@ #if NET using System.Text; +using OpenTelemetry.AWS; using OpenTelemetry.Resources.AWS.Models; namespace OpenTelemetry.Resources.AWS; @@ -37,20 +38,10 @@ public Resource Detect() internal static List> ExtractResourceAttributes(string? clusterName, string? containerId) { var resourceAttributes = new List>() - { - new(AWSSemanticConventions.AttributeCloudProvider, AWSSemanticConventions.CloudProviderValuesAws), - new(AWSSemanticConventions.AttributeCloudPlatform, AWSSemanticConventions.CloudPlatformValuesAwsEks), - }; - - if (!string.IsNullOrEmpty(clusterName)) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeK8SClusterName, clusterName!)); - } - - if (!string.IsNullOrEmpty(containerId)) - { - resourceAttributes.Add(new KeyValuePair(AWSSemanticConventions.AttributeContainerID, containerId!)); - } + .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) + .AddAttributeCloudPlatform(AWSSemanticConventions.CloudPlatformValuesAwsEks) + .AddAttributeK8SClusterName(clusterName) + .AddAttributeContainerID(containerId); return resourceAttributes; } diff --git a/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderExtensions.cs b/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderExtensions.cs index 325f7a5b08..30bb40319a 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderExtensions.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderExtensions.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AWS; using OpenTelemetry.Internal; using OpenTelemetry.Resources.AWS; @@ -16,9 +17,15 @@ public static class AWSResourceBuilderExtensions /// /// The being configured. /// The instance of being configured. - public static ResourceBuilder AddAWSEBSDetector(this ResourceBuilder builder) + public static ResourceBuilder AddAWSEBSDetector(this ResourceBuilder builder, Action? configure = null) { Guard.ThrowIfNull(builder); + + var options = new AWSResourceBuilderOptions(); + configure?.Invoke(options); + + AWSSemanticConventions.SemanticConventionVersion = options.SemanticConventionVersion; + return builder.AddDetector(new AWSEBSDetector()); } @@ -27,9 +34,15 @@ public static ResourceBuilder AddAWSEBSDetector(this ResourceBuilder builder) /// /// The being configured. /// The instance of being configured. - public static ResourceBuilder AddAWSEC2Detector(this ResourceBuilder builder) + public static ResourceBuilder AddAWSEC2Detector(this ResourceBuilder builder, Action? configure = null) { Guard.ThrowIfNull(builder); + + var options = new AWSResourceBuilderOptions(); + configure?.Invoke(options); + + AWSSemanticConventions.SemanticConventionVersion = options.SemanticConventionVersion; + return builder.AddDetector(new AWSEC2Detector()); } @@ -39,9 +52,15 @@ public static ResourceBuilder AddAWSEC2Detector(this ResourceBuilder builder) /// /// The being configured. /// The instance of being configured. - public static ResourceBuilder AddAWSECSDetector(this ResourceBuilder builder) + public static ResourceBuilder AddAWSECSDetector(this ResourceBuilder builder, Action? configure = null) { Guard.ThrowIfNull(builder); + + var options = new AWSResourceBuilderOptions(); + configure?.Invoke(options); + + AWSSemanticConventions.SemanticConventionVersion = options.SemanticConventionVersion; + return builder.AddDetector(new AWSECSDetector()); } @@ -50,9 +69,15 @@ public static ResourceBuilder AddAWSECSDetector(this ResourceBuilder builder) /// /// The being configured. /// The instance of being configured. - public static ResourceBuilder AddAWSEKSDetector(this ResourceBuilder builder) + public static ResourceBuilder AddAWSEKSDetector(this ResourceBuilder builder, Action? configure = null) { Guard.ThrowIfNull(builder); + + var options = new AWSResourceBuilderOptions(); + configure?.Invoke(options); + + AWSSemanticConventions.SemanticConventionVersion = options.SemanticConventionVersion; + return builder.AddDetector(new AWSEKSDetector()); } #endif diff --git a/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderOptions.cs b/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderOptions.cs new file mode 100644 index 0000000000..4717574bb0 --- /dev/null +++ b/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderOptions.cs @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AWS; + +namespace OpenTelemetry.Resources.AWS; + +/// +/// AWS Resource builder options. +/// +public class AWSResourceBuilderOptions +{ + /// + public SemanticConventionVersion SemanticConventionVersion { get; set; } = AWSSemanticConventions.DefaultSemanticConventionVersion; +} diff --git a/src/OpenTelemetry.Resources.AWS/AWSSemanticConventions.cs b/src/OpenTelemetry.Resources.AWS/AWSSemanticConventions.cs deleted file mode 100644 index 01006f49b4..0000000000 --- a/src/OpenTelemetry.Resources.AWS/AWSSemanticConventions.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -using OpenTelemetry.SemanticConventions; - -namespace OpenTelemetry.Resources.AWS; - -internal static class AWSSemanticConventions -{ - public const string AttributeCloudAccountID = CloudAttributes.AttributeCloudAccountId; - public const string AttributeCloudAvailabilityZone = CloudAttributes.AttributeCloudAvailabilityZone; - public const string AttributeCloudPlatform = CloudAttributes.AttributeCloudPlatform; - public const string AttributeCloudProvider = CloudAttributes.AttributeCloudProvider; - public const string AttributeCloudRegion = CloudAttributes.AttributeCloudRegion; - public const string AttributeCloudResourceId = CloudAttributes.AttributeCloudResourceId; - public const string CloudPlatformValuesAwsEc2 = CloudAttributes.CloudPlatformValues.AwsEc2; - public const string CloudPlatformValuesAwsEcs = CloudAttributes.CloudPlatformValues.AwsEcs; - public const string CloudPlatformValuesAwsEks = CloudAttributes.CloudPlatformValues.AwsEks; - public const string CloudPlatformValuesAwsElasticBeanstalk = CloudAttributes.CloudPlatformValues.AwsElasticBeanstalk; - public const string CloudProviderValuesAws = CloudAttributes.CloudProviderValues.Aws; - - public const string AttributeContainerID = ContainerAttributes.AttributeContainerId; - - public const string AttributeEcsContainerArn = AwsAttributes.AttributeAwsEcsContainerArn; - public const string AttributeEcsClusterArn = AwsAttributes.AttributeAwsEcsClusterArn; - public const string AttributeEcsLaunchtype = AwsAttributes.AttributeAwsEcsLaunchtype; - public const string ValueEcsLaunchTypeEc2 = AwsAttributes.AwsEcsLaunchtypeValues.Ec2; - public const string ValueEcsLaunchTypeFargate = AwsAttributes.AwsEcsLaunchtypeValues.Fargate; - public const string AttributeEcsTaskArn = AwsAttributes.AttributeAwsEcsTaskArn; - public const string AttributeEcsTaskFamily = AwsAttributes.AttributeAwsEcsTaskFamily; - public const string AttributeEcsTaskRevision = AwsAttributes.AttributeAwsEcsTaskRevision; - - public const string AttributeHostID = HostAttributes.AttributeHostId; - public const string AttributeHostType = HostAttributes.AttributeHostType; - public const string AttributeHostName = HostAttributes.AttributeHostName; - - public const string AttributeK8SClusterName = K8sAttributes.AttributeK8sClusterName; - - public const string AttributeLogGroupNames = AwsAttributes.AttributeAwsLogGroupNames; - public const string AttributeLogGroupArns = AwsAttributes.AttributeAwsLogGroupArns; - public const string AttributeLogStreamNames = AwsAttributes.AttributeAwsLogStreamArns; - public const string AttributeLogStreamArns = AwsAttributes.AttributeAwsLogStreamNames; - - public const string AttributeServiceName = ServiceAttributes.AttributeServiceName; - public const string AttributeServiceNamespace = ServiceAttributes.AttributeServiceNamespace; - public const string AttributeServiceInstanceID = ServiceAttributes.AttributeServiceInstanceId; - public const string AttributeServiceVersion = ServiceAttributes.AttributeServiceVersion; - public const string ServiceNameValuesAwsElasticBeanstalk = "aws_elastic_beanstalk"; -} diff --git a/src/OpenTelemetry.Resources.AWS/OpenTelemetry.Resources.AWS.csproj b/src/OpenTelemetry.Resources.AWS/OpenTelemetry.Resources.AWS.csproj index 2c29ec41cc..301e6004d1 100644 --- a/src/OpenTelemetry.Resources.AWS/OpenTelemetry.Resources.AWS.csproj +++ b/src/OpenTelemetry.Resources.AWS/OpenTelemetry.Resources.AWS.csproj @@ -24,6 +24,7 @@ + diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs new file mode 100644 index 0000000000..f5caee4cbb --- /dev/null +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -0,0 +1,348 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma warning disable SA1124 +using System.Diagnostics; +using System.Runtime.InteropServices; +using OpenTelemetry.SemanticConventions; + +using Ver = OpenTelemetry.AWS.SemanticConventionVersion; + +namespace OpenTelemetry.AWS; + +/// +/// TODO +/// https://opentelemetry.io/docs/specs/otel/versioning-and-stability/ +/// +public enum SemanticConventionVersion +{ + /// + /// Pin to the specific state of all Semantic Conventions as of the 0.10 release + /// + v0_10_EXPERIMENTAL, + + /// + /// Pin to the specific state of all Semantic Conventions as of the 0.11 release + /// + v0_11_EXPERIMENTAL, + + /// + /// Use Experimental Conventions until they become stable and then pin to stable. + /// + EXPERIMENTAL_UNTIL_STABLE, + + /// + /// Always uwe the latest version of a Semantic Convention even if there is a stable version. + /// + ALWAYS_EXPERIMENTAL +}; + +/// +/// TODO - update documentation +/// Defines extension methods for adding attributes to a collection. +/// +/// This approach supports a forward looking with regard to experimental Attributes. If an +/// Attribute is changed, update the extension method so that it emits -both- the old and new +/// attribute names. +/// +/// On the next major version bump, cease emitting out-of-date Attributes. +/// +internal static class AWSSemanticConventions +{ + public static SemanticConventionVersion SemanticConventionVersion { get; set; } + + /// + /// TODO + /// + internal const SemanticConventionVersion DefaultSemanticConventionVersion = SemanticConventionVersion.EXPERIMENTAL_UNTIL_STABLE; + + // Cloud Attributes + private static readonly Func AttributeCloudAccountID = (_) => "cloud.account.id"; //CloudAttributes.AttributeCloudAccountId + private static readonly Func AttributeCloudAvailabilityZone = (_) => "cloud.availability_zone"; //CloudAttributes.AttributeCloudAvailabilityZone; + private static readonly Func AttributeCloudPlatform = (_) => "cloud.platform"; //CloudAttributes.AttributeCloudPlatform; + private static readonly Func AttributeCloudProvider = (_) => "cloud.provider"; //CloudAttributes.AttributeCloudProvider; + private static readonly Func AttributeCloudRegion = (_) => "cloud.region"; //CloudAttributes.AttributeCloudRegion; + private static readonly Func AttributeCloudResourceId = (_) => "cloud.resource_id"; //CloudAttributes.AttributeCloudResourceId; + public const string CloudPlatformValuesAwsEc2 = CloudAttributes.CloudPlatformValues.AwsEc2; + public const string CloudPlatformValuesAwsEcs = CloudAttributes.CloudPlatformValues.AwsEcs; + public const string CloudPlatformValuesAwsEks = CloudAttributes.CloudPlatformValues.AwsEks; + public const string CloudPlatformValuesAwsElasticBeanstalk = CloudAttributes.CloudPlatformValues.AwsElasticBeanstalk; + public const string CloudProviderValuesAws = CloudAttributes.CloudProviderValues.Aws; + + // Container Attributes + private static readonly Func AttributeContainerID = (_) => ContainerAttributes.AttributeContainerId; + + // Db Attributes + private static readonly Func AttributeDbSystem = (_) => DbAttributes.AttributeDbSystem; + + // AWS Attributes + private static readonly Func AttributeEcsContainerArn = (_) => AwsAttributes.AttributeAwsEcsContainerArn; + private static readonly Func AttributeEcsClusterArn = (_) => AwsAttributes.AttributeAwsEcsClusterArn; + private static readonly Func AttributeEcsLaunchtype = (_) => AwsAttributes.AttributeAwsEcsLaunchtype; + private static readonly Func ValueEcsLaunchTypeEc2 = (_) => AwsAttributes.AwsEcsLaunchtypeValues.Ec2; + private static readonly Func ValueEcsLaunchTypeFargate = (_) => AwsAttributes.AwsEcsLaunchtypeValues.Fargate; + private static readonly Func AttributeEcsTaskArn = (_) => AwsAttributes.AttributeAwsEcsTaskArn; + private static readonly Func AttributeEcsTaskFamily = (_) => AwsAttributes.AttributeAwsEcsTaskFamily; + private static readonly Func AttributeEcsTaskRevision = (_) => AwsAttributes.AttributeAwsEcsTaskRevision; + private static readonly Func AttributeLogGroupNames = (_) => AwsAttributes.AttributeAwsLogGroupNames; + private static readonly Func AttributeLogGroupArns = (_) => AwsAttributes.AttributeAwsLogGroupArns; + private static readonly Func AttributeLogStreamNames = (_) => AwsAttributes.AttributeAwsLogStreamArns; + private static readonly Func AttributeLogStreamArns = (_) => AwsAttributes.AttributeAwsLogStreamNames; + private static readonly Func AttributeAWSDynamoTableName = (_) => AwsAttributes.AttributeAwsDynamodbTableNames; + private static readonly Func AttributeAWSSQSQueueUrl = (_) => "aws.queue_url"; // todo - confirm in java; + + private static readonly Func AttributeAWSBedrockAgentId = (_) => "aws.bedrock.agent.id"; + private static readonly Func AttributeAWSBedrockDataSourceId = (_) => "aws.bedrock.data_source.id"; + private static readonly Func AttributeAWSBedrockGuardrailId = (_) => "aws.bedrock.guardrail.id"; + private static readonly Func AttributeAWSBedrockKnowledgeBaseId = (_) => "aws.bedrock.knowledge_base.id"; + + private static readonly Func AttributeAWSBedrock = (v) => v switch + { + SemanticConventionVersion.v0_10_EXPERIMENTAL => "aws_bedrock", + _ => "aws.bedrock", + }; + + // Faas Attributes + private static readonly Func AttributeFaasID = (_) => CloudAttributes.AttributeCloudResourceId; + private static readonly Func AttributeFaasExecution = (_) => FaasAttributes.AttributeFaasInvocationId; + private static readonly Func AttributeFaasName = (_) => FaasAttributes.AttributeFaasName; + private static readonly Func AttributeFaasVersion = (_) => FaasAttributes.AttributeFaasVersion; + private static readonly Func AttributeFaasTrigger = (_) => FaasAttributes.AttributeFaasTrigger; + private static readonly Func AttributeFaasColdStart = (_) => FaasAttributes.AttributeFaasColdstart; + + // Gen AI Attributes + private static readonly Func AttributeGenAiModelId = (_) => GenAiAttributes.AttributeGenAiRequestModel; + private static readonly Func AttributeGenAiSystem = (_) => GenAiAttributes.AttributeGenAiSystem; + + // Host Attributes + private static readonly Func AttributeHostID = (_) => HostAttributes.AttributeHostId; + private static readonly Func AttributeHostType = (_) => HostAttributes.AttributeHostType; + private static readonly Func AttributeHostName = (_) => HostAttributes.AttributeHostName; + + // Http Attributes + private static readonly Func AttributeHttpStatusCode = (_) => HttpAttributes.AttributeHttpStatusCode; + private static readonly Func AttributeHttpScheme = (_) => HttpAttributes.AttributeHttpScheme; + private static readonly Func AttributeHttpTarget = (_) => HttpAttributes.AttributeHttpTarget; + private static readonly Func AttributeHttpMethod = (_) => HttpAttributes.AttributeHttpMethod; + + // Net Attributes + private static readonly Func AttributeNetHostName = (_) => NetAttributes.AttributeNetHostName; + private static readonly Func AttributeNetHostPort = (_) => NetAttributes.AttributeNetHostPort; + + // K8s Attributes + private static readonly Func AttributeK8SClusterName = (_) => K8sAttributes.AttributeK8sClusterName; + + // Service Attributes + private static readonly Func AttributeServiceName = (_) => ServiceAttributes.AttributeServiceName; + private static readonly Func AttributeServiceNamespace = (_) => ServiceAttributes.AttributeServiceNamespace; + private static readonly Func AttributeServiceInstanceID = (_) => ServiceAttributes.AttributeServiceInstanceId; + private static readonly Func AttributeServiceVersion = (_) => ServiceAttributes.AttributeServiceVersion; + public static string ServiceNameValuesAwsElasticBeanstalk = "aws_elastic_beanstalk"; + + #region Service Parameter Mapping + + public static IDictionary AddAttributeAWSDynamoTableName(this IDictionary dict, string value) + => AddDic(dict, AttributeAWSDynamoTableName, value); + + public static IDictionary AddAttributeAWSSQSQueueUrl(this IDictionary dict, string value) + => AddDic(dict, AttributeAWSSQSQueueUrl, value); + + public static IDictionary AddAttributeGenAiModelId(this IDictionary dict, string value) + => AddDic(dict, AttributeGenAiModelId, value); + + public static IDictionary AddAttributeAWSBedrockAgentId(this IDictionary dict, string value) + => AddDic(dict, AttributeAWSBedrockAgentId, value); + + public static IDictionary AddAttributeAWSBedrockDataSourceId(this IDictionary dict, string value) + => AddDic(dict, AttributeAWSBedrockDataSourceId, value); + + public static IDictionary AddAttributeAWSBedrockGuardrailId(this IDictionary dict, string value) + => AddDic(dict, AttributeAWSBedrockGuardrailId, value); + public static IDictionary AddAttributeAWSBedrockKnowledgeBaseId(this IDictionary dict, string value) + => AddDic(dict, AttributeAWSBedrockKnowledgeBaseId, value); + #endregion + + #region Cloud Attributes + public static T AddAttributeCloudAccountID(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeCloudAccountID, value, addIfNull); + + public static T AddAttributeCloudAvailabilityZone(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeCloudAvailabilityZone, value, addIfNull); + + public static T AddAttributeCloudPlatform(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeCloudPlatform, value, addIfNull); + + public static T AddAttributeCloudProvider(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeCloudProvider, value, addIfNull); + + public static T AddAttributeCloudRegion(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeCloudRegion, value, addIfNull); + + public static T AddAttributeCloudResourceId(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeCloudResourceId, value, addIfNull); + #endregion + + #region Container + public static T AddAttributeContainerId(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeContainerID, value, addIfNull); + #endregion + + #region AWS + public static Activity? SetTagAttributeDbSystemToDynamoDb(this Activity? activity) + => SetTag(activity, AttributeDbSystem, DbAttributes.DbSystemValues.Dynamodb); // <---- todo + + public static Activity? SetTagAttributeGenAiSystemToBedrock(this Activity? activity) + => SetTag(activity, AttributeGenAiSystem, AttributeAWSBedrock(SemanticConventionVersion)); + + public static T AddAttributeEcsContainerArn(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeEcsContainerArn, value, addIfNull); + + public static T AddAttributeEcsClusterArn(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeEcsClusterArn, value, addIfNull); + + public static T AddAttributeEcsLaunchtype(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeEcsLaunchtype, value, addIfNull); + + public static T AddAttributeEcsLaunchtypeIsEc2(this T attributes) + where T : IList> => AddAttributeEcsLaunchtype(attributes, AWSSemanticConventions.ValueEcsLaunchTypeEc2); + + public static T AddAttributeEcsLaunchtypeIsFargate(this T attributes) + where T : IList> => AddAttributeEcsLaunchtype(attributes, AWSSemanticConventions.ValueEcsLaunchTypeFargate); + + public static T AddAttributeEcsTaskArn(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeEcsTaskArn, value, addIfNull); + + public static T AddAttributeEcsTaskFamily(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeEcsTaskFamily, value, addIfNull); + + public static T AddAttributeEcsTaskRevision(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeEcsTaskRevision, value, addIfNull); + + public static T AddAttributeLogGroupNames(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeLogGroupNames, value, addIfNull); + + public static T AddAttributeLogGroupArns(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeLogGroupArns, value, addIfNull); + + public static T AddAttributeLogStreamNames(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeLogStreamNames, value, addIfNull); + + public static T AddAttributeLogStreamArns(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeLogStreamArns, value, addIfNull); + #endregion + + #region Faas + public static T AddAttributeFaasID(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeFaasID, value, addIfNull); + + public static T AddAttributeFaasExecution(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeFaasExecution, value, addIfNull); + + public static T AddAttributeFaasName(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeFaasName, value, addIfNull); + + public static T AddAttributeFaasVersion(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeFaasVersion, value, addIfNull); + + public static T AddAttributeFaasTrigger(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeFaasTrigger, value, addIfNull); + + public static T AddAttributeFaasColdStart(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeFaasColdStart, value, addIfNull); + + #endregion + + #region Host + public static T AddAttributeHostID(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeHostID, value, addIfNull); + + public static T AddAttributeHostType(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeHostType, value, addIfNull); + + public static T AddAttributeHostName(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeHostName, value, addIfNull); + #endregion + + #region Http + + public static Activity? SetTagAttributeHttpStatusCode(this Activity? activity, int value) + => SetTag(activity, AttributeHttpStatusCode, value); + + public static T AddAttributeHttpScheme(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeHttpScheme, value, addIfNull); + + public static T AddAttributeHttpTarget(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeHttpTarget, value, addIfNull); + + public static T AddAttributeHttpMethod(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeHttpMethod, value, addIfNull); + #endregion + + #region Net + public static T AddAttributeNetHostName(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeNetHostName, value, addIfNull); + + public static T AddAttributeNetHostPort(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeNetHostPort, value, addIfNull); + #endregion + + #region K8s + public static T AddAttributeK8SClusterName(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeK8SClusterName, value, addIfNull); + + public static T AddAttributeContainerID(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeContainerID, value, addIfNull); + #endregion + + #region Service + public static T AddAttributeServiceName(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeServiceName, value, addIfNull); + + public static T AddAttributeServiceNamespace(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeServiceNamespace, value, addIfNull); + + public static T AddAttributeServiceInstanceID(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeServiceInstanceID, value, addIfNull); + + public static T AddAttributeServiceVersion(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeServiceVersion, value, addIfNull); + #endregion + + private static T Add(this T attributes, Func attributeNameFunc, object? value, bool addIfNull = false) + where T : IList> + { + var attributeName = attributeNameFunc(SemanticConventionVersion); + + // if attributeName is empty or there is no value, exit + if (string.IsNullOrEmpty(attributeName) || + (string.IsNullOrEmpty(value?.ToString()) && !addIfNull)) + { + return attributes; + } + + attributes.Add(new(attributeName, value)); + + return attributes; + } + + private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, object? value) + { + var attributeName = attributeNameFunc(SemanticConventionVersion); + + activity?.SetTag(attributeName, value); + + return activity; + } + + public static IDictionary AddDic(IDictionary dict, Func attributeNameFunc, string value) + { + var attributeName = attributeNameFunc(SemanticConventionVersion); + + if (!string.IsNullOrEmpty(attributeName)) + { + dict.Add(attributeName, value); + } + + return dict; + } +} diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index a63ec740b2..61f7469064 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 using System.Diagnostics; -using OpenTelemetry.Instrumentation.AWSLambda.Implementation; using OpenTelemetry.Resources; using OpenTelemetry.Trace; using Xunit; @@ -16,6 +15,19 @@ public class AWSLambdaWrapperTests private const string XRayParentId = "53995c3f42cd8ad8"; private const string CustomParentId = "11195c3f42cd8222"; + private static class ExpectedSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudAccountID = "cloud.account.id"; + public const string AttributeCloudRegion = "cloud.region"; + public const string AttributeFaasColdStart = "faas.coldstart"; + public const string AttributeFaasName = "faas.name"; + public const string AttributeFaasExecution = "faas.invocation_id"; + public const string AttributeFaasID = "cloud.resource_id"; + public const string AttributeFaasTrigger = "faas.trigger"; + public const string AttributeFaasVersion = "faas.version"; + } + private readonly SampleHandlers sampleHandlers; private readonly SampleLambdaContext sampleLambdaContext; @@ -234,7 +246,7 @@ public void OnFunctionStart_ColdStart_ColdStartTagHasCorrectValue(int invocation Assert.NotNull(activity); Assert.NotNull(activity.TagObjects); var expectedColdStartValue = invocationsCount == 1; - Assert.Contains(activity.TagObjects, x => x.Key == AWSLambdaSemanticConventions.AttributeFaasColdStart && expectedColdStartValue.Equals(x.Value)); + Assert.Contains(activity.TagObjects, x => x.Key == ExpectedSemanticConventions.AttributeFaasColdStart && expectedColdStartValue.Equals(x.Value)); } private static ActivityContext CreateParentContext() @@ -262,19 +274,19 @@ private void AssertResourceAttributes(Resource? resource) Assert.NotNull(resource); var resourceAttributes = resource.Attributes.ToDictionary(x => x.Key, x => x.Value); - Assert.Equal("aws", resourceAttributes[AWSLambdaSemanticConventions.AttributeCloudProvider]); - Assert.Equal("us-east-1", resourceAttributes[AWSLambdaSemanticConventions.AttributeCloudRegion]); - Assert.Equal("testfunction", resourceAttributes[AWSLambdaSemanticConventions.AttributeFaasName]); - Assert.Equal("latest", resourceAttributes[AWSLambdaSemanticConventions.AttributeFaasVersion]); + Assert.Equal("aws", resourceAttributes[ExpectedSemanticConventions.AttributeCloudProvider]); + Assert.Equal("us-east-1", resourceAttributes[ExpectedSemanticConventions.AttributeCloudRegion]); + Assert.Equal("testfunction", resourceAttributes[ExpectedSemanticConventions.AttributeFaasName]); + Assert.Equal("latest", resourceAttributes[ExpectedSemanticConventions.AttributeFaasVersion]); } 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(this.sampleLambdaContext.AwsRequestId, activity.GetTagValue(ExpectedSemanticConventions.AttributeFaasExecution)); + Assert.Equal(this.sampleLambdaContext.InvokedFunctionArn, activity.GetTagValue(ExpectedSemanticConventions.AttributeFaasID)); + Assert.Equal(this.sampleLambdaContext.FunctionName, activity.GetTagValue(ExpectedSemanticConventions.AttributeFaasName)); + Assert.Equal("other", activity.GetTagValue(ExpectedSemanticConventions.AttributeFaasTrigger)); + Assert.Equal("111111111111", activity.GetTagValue(ExpectedSemanticConventions.AttributeCloudAccountID)); } private void AssertSpanException(Activity activity) diff --git a/test/OpenTelemetry.Resources.AWS.Tests/AWSEBSDetectorTests.cs b/test/OpenTelemetry.Resources.AWS.Tests/AWSEBSDetectorTests.cs index e3abf543f0..e510bf3327 100644 --- a/test/OpenTelemetry.Resources.AWS.Tests/AWSEBSDetectorTests.cs +++ b/test/OpenTelemetry.Resources.AWS.Tests/AWSEBSDetectorTests.cs @@ -9,6 +9,16 @@ public class AWSEBSDetectorTests { private const string AWSEBSMetadataFilePath = "SampleMetadataFiles/environment.conf"; + private static class AWSSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudPlatform = "cloud.platform"; + public const string AttributeServiceName = "service.name"; + public const string AttributeServiceNamespace = "service.namespace"; + public const string AttributeServiceInstanceID = "service.instance.id"; + public const string AttributeServiceVersion = "service.version"; + } + [Fact] public void TestDetect() { diff --git a/test/OpenTelemetry.Resources.AWS.Tests/AWSEC2DetectorTests.cs b/test/OpenTelemetry.Resources.AWS.Tests/AWSEC2DetectorTests.cs index 249f36ed31..eedf4f8a23 100644 --- a/test/OpenTelemetry.Resources.AWS.Tests/AWSEC2DetectorTests.cs +++ b/test/OpenTelemetry.Resources.AWS.Tests/AWSEC2DetectorTests.cs @@ -7,6 +7,18 @@ namespace OpenTelemetry.Resources.AWS.Tests; public class AWSEC2DetectorTests { + private static class ExpectedSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudPlatform = "cloud.platform"; + public const string AttributeCloudAccountID = "cloud.account.id"; + public const string AttributeCloudAvailabilityZone = "cloud.availability_zone"; + public const string AttributeCloudRegion = "cloud.region"; + public const string AttributeHostID = "host.id"; + public const string AttributeHostType = "host.type"; + public const string AttributeHostName = "host.name"; + } + [Fact] public void TestDetect() { @@ -20,14 +32,14 @@ public void TestExtractResourceAttributes() var hostName = "Test host name"; var resourceAttributes = AWSEC2Detector.ExtractResourceAttributes(sampleEC2IdentityDocumentModel, hostName).ToDictionary(x => x.Key, x => x.Value); - Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); - Assert.Equal("aws_ec2", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); - Assert.Equal("Test account id", resourceAttributes[AWSSemanticConventions.AttributeCloudAccountID]); - Assert.Equal("Test availability zone", resourceAttributes[AWSSemanticConventions.AttributeCloudAvailabilityZone]); - Assert.Equal("Test instance id", resourceAttributes[AWSSemanticConventions.AttributeHostID]); - Assert.Equal("Test instance type", resourceAttributes[AWSSemanticConventions.AttributeHostType]); - Assert.Equal("Test aws region", resourceAttributes[AWSSemanticConventions.AttributeCloudRegion]); - Assert.Equal("Test host name", resourceAttributes[AWSSemanticConventions.AttributeHostName]); + Assert.Equal("aws", resourceAttributes[ExpectedSemanticConventions.AttributeCloudProvider]); + Assert.Equal("aws_ec2", resourceAttributes[ExpectedSemanticConventions.AttributeCloudPlatform]); + Assert.Equal("Test account id", resourceAttributes[ExpectedSemanticConventions.AttributeCloudAccountID]); + Assert.Equal("Test availability zone", resourceAttributes[ExpectedSemanticConventions.AttributeCloudAvailabilityZone]); + Assert.Equal("Test instance id", resourceAttributes[ExpectedSemanticConventions.AttributeHostID]); + Assert.Equal("Test instance type", resourceAttributes[ExpectedSemanticConventions.AttributeHostType]); + Assert.Equal("Test aws region", resourceAttributes[ExpectedSemanticConventions.AttributeCloudRegion]); + Assert.Equal("Test host name", resourceAttributes[ExpectedSemanticConventions.AttributeHostName]); } [Fact] diff --git a/test/OpenTelemetry.Resources.AWS.Tests/AWSECSDetectorTests.cs b/test/OpenTelemetry.Resources.AWS.Tests/AWSECSDetectorTests.cs index ae3239293d..03ff09f370 100644 --- a/test/OpenTelemetry.Resources.AWS.Tests/AWSECSDetectorTests.cs +++ b/test/OpenTelemetry.Resources.AWS.Tests/AWSECSDetectorTests.cs @@ -18,6 +18,25 @@ public class AWSECSDetectorTests : IDisposable private const string AWSECSMetadataURLKey = "ECS_CONTAINER_METADATA_URI"; private const string AWSECSMetadataURLV4Key = "ECS_CONTAINER_METADATA_URI_V4"; + private static class ExpectedSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudPlatform = "cloud.platform"; + public const string AttributeCloudAccountID = "cloud.account.id"; + public const string AttributeCloudAvailabilityZone = "cloud.availability_zone"; + public const string AttributeCloudRegion = "cloud.region"; + public const string AttributeCloudResourceId = "cloud.resource_id"; + public const string AttributeEcsContainerArn = "aws.ecs.container.arn"; + public const string AttributeEcsLaunchtype = "aws.ecs.launchtype"; + public const string AttributeEcsTaskArn = "aws.ecs.task.arn"; + public const string AttributeEcsTaskFamily = "aws.ecs.task.family"; + public const string AttributeEcsTaskRevision = "aws.ecs.task.revision"; + public const string AttributeLogGroupArns = "aws.log.group.arns"; + public const string AttributeLogGroupNames = "aws.log.group.names"; + public const string AttributeLogStreamArns = "aws.log.stream.arns"; + public const string AttributeLogStreamNames = "aws.log.stream.names"; + } + public AWSECSDetectorTests() { this.ResetEnvironment(); @@ -51,8 +70,8 @@ public void TestEcsMetadataV3() var resourceAttributes = new AWSECSDetector().Detect().Attributes.ToDictionary(x => x.Key, x => x.Value); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudProvider], "aws"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform], "aws_ecs"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudProvider], "aws"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudPlatform], "aws_ecs"); } [Fact] @@ -66,22 +85,22 @@ public async Task TestEcsMetadataV4Ec2() Environment.SetEnvironmentVariable(AWSECSMetadataURLV4Key, metadataEndpoint.Address.ToString()); var resourceAttributes = new AWSECSDetector().Detect().Attributes.ToDictionary(x => x.Key, x => x.Value); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudProvider], "aws"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform], "aws_ecs"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudAccountID], "111122223333"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudAvailabilityZone], "us-west-2d"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudRegion], "us-west-2"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudResourceId], "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsContainerArn], "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsLaunchtype], "ec2"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsTaskArn], "arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsTaskFamily], "curltest"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsTaskRevision], "26"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudProvider], "aws"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudPlatform], "aws_ecs"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudAccountID], "111122223333"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudAvailabilityZone], "us-west-2d"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudRegion], "us-west-2"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudResourceId], "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsContainerArn], "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsLaunchtype], "ec2"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsTaskArn], "arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsTaskFamily], "curltest"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsTaskRevision], "26"); #pragma warning disable CA1861 // Avoid constant arrays as arguments - Assert.NotStrictEqual(resourceAttributes[AWSSemanticConventions.AttributeLogGroupNames], new string[] { "/ecs/metadata" }); - Assert.NotStrictEqual(resourceAttributes[AWSSemanticConventions.AttributeLogGroupArns], new string[] { "arn:aws:logs:us-west-2:111122223333:log-group:/ecs/metadata" }); - Assert.NotStrictEqual(resourceAttributes[AWSSemanticConventions.AttributeLogStreamNames], new string[] { "ecs/curl/8f03e41243824aea923aca126495f665" }); - Assert.NotStrictEqual(resourceAttributes[AWSSemanticConventions.AttributeLogStreamArns], new string[] { "arn:aws:logs:us-west-2:111122223333:log-group:/ecs/metadata:log-stream:ecs/curl/8f03e41243824aea923aca126495f665" }); + Assert.NotStrictEqual(resourceAttributes[ExpectedSemanticConventions.AttributeLogGroupNames], new string[] { "/ecs/metadata" }); + Assert.NotStrictEqual(resourceAttributes[ExpectedSemanticConventions.AttributeLogGroupArns], new string[] { "arn:aws:logs:us-west-2:111122223333:log-group:/ecs/metadata" }); + Assert.NotStrictEqual(resourceAttributes[ExpectedSemanticConventions.AttributeLogStreamNames], new string[] { "ecs/curl/8f03e41243824aea923aca126495f665" }); + Assert.NotStrictEqual(resourceAttributes[ExpectedSemanticConventions.AttributeLogStreamArns], new string[] { "arn:aws:logs:us-west-2:111122223333:log-group:/ecs/metadata:log-stream:ecs/curl/8f03e41243824aea923aca126495f665" }); #pragma warning restore CA1861 // Avoid constant arrays as arguments } } @@ -98,22 +117,22 @@ public async Task TestEcsMetadataV4Fargate() var resourceAttributes = new AWSECSDetector().Detect().Attributes.ToDictionary(x => x.Key, x => x.Value); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudProvider], "aws"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform], "aws_ecs"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudAccountID], "111122223333"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudAvailabilityZone], "us-west-2a"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudRegion], "us-west-2"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeCloudResourceId], "arn:aws:ecs:us-west-2:111122223333:container/05966557-f16c-49cb-9352-24b3a0dcd0e1"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsContainerArn], "arn:aws:ecs:us-west-2:111122223333:container/05966557-f16c-49cb-9352-24b3a0dcd0e1"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsLaunchtype], "fargate"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsTaskArn], "arn:aws:ecs:us-west-2:111122223333:task/default/e9028f8d5d8e4f258373e7b93ce9a3c3"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsTaskFamily], "curltest"); - Assert.Equal(resourceAttributes[AWSSemanticConventions.AttributeEcsTaskRevision], "3"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudProvider], "aws"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudPlatform], "aws_ecs"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudAccountID], "111122223333"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudAvailabilityZone], "us-west-2a"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudRegion], "us-west-2"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeCloudResourceId], "arn:aws:ecs:us-west-2:111122223333:container/05966557-f16c-49cb-9352-24b3a0dcd0e1"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsContainerArn], "arn:aws:ecs:us-west-2:111122223333:container/05966557-f16c-49cb-9352-24b3a0dcd0e1"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsLaunchtype], "fargate"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsTaskArn], "arn:aws:ecs:us-west-2:111122223333:task/default/e9028f8d5d8e4f258373e7b93ce9a3c3"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsTaskFamily], "curltest"); + Assert.Equal(resourceAttributes[ExpectedSemanticConventions.AttributeEcsTaskRevision], "3"); #pragma warning disable CA1861 // Avoid constant arrays as arguments - Assert.NotStrictEqual(resourceAttributes[AWSSemanticConventions.AttributeLogGroupNames], new string[] { "/ecs/containerlogs" }); - Assert.NotStrictEqual(resourceAttributes[AWSSemanticConventions.AttributeLogGroupArns], new string[] { "arn:aws:logs:us-west-2:111122223333:log-group:/ecs/containerlogs" }); - Assert.NotStrictEqual(resourceAttributes[AWSSemanticConventions.AttributeLogStreamNames], new string[] { "ecs/curl/cd189a933e5849daa93386466019ab50" }); - Assert.NotStrictEqual(resourceAttributes[AWSSemanticConventions.AttributeLogStreamArns], new string[] { "arn:aws:logs:us-west-2:111122223333:log-group:/ecs/containerlogs:log-stream:ecs/curl/cd189a933e5849daa93386466019ab50" }); + Assert.NotStrictEqual(resourceAttributes[ExpectedSemanticConventions.AttributeLogGroupNames], new string[] { "/ecs/containerlogs" }); + Assert.NotStrictEqual(resourceAttributes[ExpectedSemanticConventions.AttributeLogGroupArns], new string[] { "arn:aws:logs:us-west-2:111122223333:log-group:/ecs/containerlogs" }); + Assert.NotStrictEqual(resourceAttributes[ExpectedSemanticConventions.AttributeLogStreamNames], new string[] { "ecs/curl/cd189a933e5849daa93386466019ab50" }); + Assert.NotStrictEqual(resourceAttributes[ExpectedSemanticConventions.AttributeLogStreamArns], new string[] { "arn:aws:logs:us-west-2:111122223333:log-group:/ecs/containerlogs:log-stream:ecs/curl/cd189a933e5849daa93386466019ab50" }); #pragma warning restore CA1861 // Avoid constant arrays as arguments } } diff --git a/test/OpenTelemetry.Resources.AWS.Tests/AWSEKSDetectorTests.cs b/test/OpenTelemetry.Resources.AWS.Tests/AWSEKSDetectorTests.cs index 8b8122abd4..b1a3241197 100644 --- a/test/OpenTelemetry.Resources.AWS.Tests/AWSEKSDetectorTests.cs +++ b/test/OpenTelemetry.Resources.AWS.Tests/AWSEKSDetectorTests.cs @@ -12,6 +12,14 @@ public class AWSEKSDetectorTests private const string AWSEKSCredentialsPath = "SampleMetadataFiles/testekstoken"; private const string AWSEKSMetadataFilePath = "SampleMetadataFiles/testcgroup"; + private static class ExpectedSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudPlatform = "cloud.platform"; + public const string AttributeK8SClusterName = "k8s.cluster.name"; + public const string AttributeContainerID = "container.id"; + } + [Fact] public void TestDetect() { @@ -31,10 +39,10 @@ public void TestExtractResourceAttributes() var resourceAttributes = AWSEKSDetector.ExtractResourceAttributes(clusterName, containerId).ToDictionary(x => x.Key, x => x.Value); Assert.Equal(4, resourceAttributes.Count); - Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); - Assert.Equal("aws_eks", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); - Assert.Equal("Test cluster name", resourceAttributes[AWSSemanticConventions.AttributeK8SClusterName]); - Assert.Equal("Test container id", resourceAttributes[AWSSemanticConventions.AttributeContainerID]); + Assert.Equal("aws", resourceAttributes[ExpectedSemanticConventions.AttributeCloudProvider]); + Assert.Equal("aws_eks", resourceAttributes[ExpectedSemanticConventions.AttributeCloudPlatform]); + Assert.Equal("Test cluster name", resourceAttributes[ExpectedSemanticConventions.AttributeK8SClusterName]); + Assert.Equal("Test container id", resourceAttributes[ExpectedSemanticConventions.AttributeContainerID]); } [Fact] @@ -46,9 +54,9 @@ public void TestExtractResourceAttributesWithEmptyClusterName() // Validate the count of resourceAttributes -> Excluding cluster name, there will be only three resourceAttributes Assert.Equal(3, resourceAttributes.Count); - Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); - Assert.Equal("aws_eks", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); - Assert.Equal("Test container id", resourceAttributes[AWSSemanticConventions.AttributeContainerID]); + Assert.Equal("aws", resourceAttributes[ExpectedSemanticConventions.AttributeCloudProvider]); + Assert.Equal("aws_eks", resourceAttributes[ExpectedSemanticConventions.AttributeCloudPlatform]); + Assert.Equal("Test container id", resourceAttributes[ExpectedSemanticConventions.AttributeContainerID]); } [Fact] @@ -60,9 +68,9 @@ public void TestExtractResourceAttributesWithEmptyContainerId() // Validate the count of resourceAttributes -> Excluding container id, there will be only three resourceAttributes Assert.Equal(3, resourceAttributes.Count); - Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); - Assert.Equal("aws_eks", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); - Assert.Equal("Test cluster name", resourceAttributes[AWSSemanticConventions.AttributeK8SClusterName]); + Assert.Equal("aws", resourceAttributes[ExpectedSemanticConventions.AttributeCloudProvider]); + Assert.Equal("aws_eks", resourceAttributes[ExpectedSemanticConventions.AttributeCloudPlatform]); + Assert.Equal("Test cluster name", resourceAttributes[ExpectedSemanticConventions.AttributeK8SClusterName]); } [Fact] From 59a6a9f453c1137b718f463f53a076d5bcb1a24c Mon Sep 17 00:00:00 2001 From: philip pittle Date: Mon, 2 Dec 2024 17:06:47 -0800 Subject: [PATCH 03/35] improve documentation --- .../AWSEKSDetector.cs | 2 +- src/Shared/AWS/AWSSemanticConventions.cs | 245 +++++++++++++----- 2 files changed, 175 insertions(+), 72 deletions(-) diff --git a/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs b/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs index ec1f3b3669..c86a6b7c20 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs @@ -41,7 +41,7 @@ internal static List> ExtractResourceAttributes(str .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) .AddAttributeCloudPlatform(AWSSemanticConventions.CloudPlatformValuesAwsEks) .AddAttributeK8SClusterName(clusterName) - .AddAttributeContainerID(containerId); + .AddAttributeContainerId(containerId); return resourceAttributes; } diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index f5caee4cbb..ed801d9130 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -1,13 +1,17 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#pragma warning disable SA1124 using System.Diagnostics; -using System.Runtime.InteropServices; using OpenTelemetry.SemanticConventions; using Ver = OpenTelemetry.AWS.SemanticConventionVersion; +// disable Style Warnings to improve readability of this specific file. +#pragma warning disable SA1124 +#pragma warning disable SA1005 +#pragma warning disable SA1514 +#pragma warning disable SA1201 + namespace OpenTelemetry.AWS; /// @@ -17,12 +21,14 @@ namespace OpenTelemetry.AWS; public enum SemanticConventionVersion { /// - /// Pin to the specific state of all Semantic Conventions as of the 0.10 release + /// Pin to the specific state of all Semantic Conventions as of the 0.10 release of this library. + /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.27.0 /// v0_10_EXPERIMENTAL, /// - /// Pin to the specific state of all Semantic Conventions as of the 0.11 release + /// Pin to the specific state of all Semantic Conventions as of the 0.11 release of this library. + /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.29.0 /// v0_11_EXPERIMENTAL, @@ -54,260 +60,357 @@ internal static class AWSSemanticConventions /// /// TODO /// - internal const SemanticConventionVersion DefaultSemanticConventionVersion = SemanticConventionVersion.EXPERIMENTAL_UNTIL_STABLE; - - // Cloud Attributes - private static readonly Func AttributeCloudAccountID = (_) => "cloud.account.id"; //CloudAttributes.AttributeCloudAccountId - private static readonly Func AttributeCloudAvailabilityZone = (_) => "cloud.availability_zone"; //CloudAttributes.AttributeCloudAvailabilityZone; - private static readonly Func AttributeCloudPlatform = (_) => "cloud.platform"; //CloudAttributes.AttributeCloudPlatform; - private static readonly Func AttributeCloudProvider = (_) => "cloud.provider"; //CloudAttributes.AttributeCloudProvider; - private static readonly Func AttributeCloudRegion = (_) => "cloud.region"; //CloudAttributes.AttributeCloudRegion; - private static readonly Func AttributeCloudResourceId = (_) => "cloud.resource_id"; //CloudAttributes.AttributeCloudResourceId; + internal const SemanticConventionVersion DefaultSemanticConventionVersion = Ver.EXPERIMENTAL_UNTIL_STABLE; + + // CLOUD Attributes + /// + private static readonly Func AttributeCloudAccountID = (_) => "cloud.account.id"; + /// + private static readonly Func AttributeCloudAvailabilityZone = (_) => "cloud.availability_zone"; + /// + private static readonly Func AttributeCloudPlatform = (_) => "cloud.platform"; + /// + private static readonly Func AttributeCloudProvider = (_) => "cloud.provider"; + /// + private static readonly Func AttributeCloudRegion = (_) => "cloud.region"; + /// + private static readonly Func AttributeCloudResourceId = (_) => "cloud.resource_id"; public const string CloudPlatformValuesAwsEc2 = CloudAttributes.CloudPlatformValues.AwsEc2; public const string CloudPlatformValuesAwsEcs = CloudAttributes.CloudPlatformValues.AwsEcs; public const string CloudPlatformValuesAwsEks = CloudAttributes.CloudPlatformValues.AwsEks; public const string CloudPlatformValuesAwsElasticBeanstalk = CloudAttributes.CloudPlatformValues.AwsElasticBeanstalk; public const string CloudProviderValuesAws = CloudAttributes.CloudProviderValues.Aws; - // Container Attributes - private static readonly Func AttributeContainerID = (_) => ContainerAttributes.AttributeContainerId; + // CONTAINER Attributes + /// + private static readonly Func AttributeContainerID = (_) => "container.id"; - // Db Attributes - private static readonly Func AttributeDbSystem = (_) => DbAttributes.AttributeDbSystem; + // DB Attributes + /// + private static readonly Func AttributeDbSystem = (_) => "db.system"; // AWS Attributes + /// private static readonly Func AttributeEcsContainerArn = (_) => AwsAttributes.AttributeAwsEcsContainerArn; + /// private static readonly Func AttributeEcsClusterArn = (_) => AwsAttributes.AttributeAwsEcsClusterArn; + /// private static readonly Func AttributeEcsLaunchtype = (_) => AwsAttributes.AttributeAwsEcsLaunchtype; + /// private static readonly Func ValueEcsLaunchTypeEc2 = (_) => AwsAttributes.AwsEcsLaunchtypeValues.Ec2; + /// private static readonly Func ValueEcsLaunchTypeFargate = (_) => AwsAttributes.AwsEcsLaunchtypeValues.Fargate; + /// private static readonly Func AttributeEcsTaskArn = (_) => AwsAttributes.AttributeAwsEcsTaskArn; + /// private static readonly Func AttributeEcsTaskFamily = (_) => AwsAttributes.AttributeAwsEcsTaskFamily; + /// private static readonly Func AttributeEcsTaskRevision = (_) => AwsAttributes.AttributeAwsEcsTaskRevision; + /// private static readonly Func AttributeLogGroupNames = (_) => AwsAttributes.AttributeAwsLogGroupNames; + /// private static readonly Func AttributeLogGroupArns = (_) => AwsAttributes.AttributeAwsLogGroupArns; + /// private static readonly Func AttributeLogStreamNames = (_) => AwsAttributes.AttributeAwsLogStreamArns; + /// private static readonly Func AttributeLogStreamArns = (_) => AwsAttributes.AttributeAwsLogStreamNames; + /// private static readonly Func AttributeAWSDynamoTableName = (_) => AwsAttributes.AttributeAwsDynamodbTableNames; + /// private static readonly Func AttributeAWSSQSQueueUrl = (_) => "aws.queue_url"; // todo - confirm in java; - + /// private static readonly Func AttributeAWSBedrockAgentId = (_) => "aws.bedrock.agent.id"; + /// private static readonly Func AttributeAWSBedrockDataSourceId = (_) => "aws.bedrock.data_source.id"; + /// private static readonly Func AttributeAWSBedrockGuardrailId = (_) => "aws.bedrock.guardrail.id"; + /// private static readonly Func AttributeAWSBedrockKnowledgeBaseId = (_) => "aws.bedrock.knowledge_base.id"; - + /// private static readonly Func AttributeAWSBedrock = (v) => v switch { SemanticConventionVersion.v0_10_EXPERIMENTAL => "aws_bedrock", - _ => "aws.bedrock", + _ => "aws.bedrock", //v1.29 }; - // Faas Attributes + // FAAS Attributes + /// private static readonly Func AttributeFaasID = (_) => CloudAttributes.AttributeCloudResourceId; + /// private static readonly Func AttributeFaasExecution = (_) => FaasAttributes.AttributeFaasInvocationId; + /// private static readonly Func AttributeFaasName = (_) => FaasAttributes.AttributeFaasName; + /// private static readonly Func AttributeFaasVersion = (_) => FaasAttributes.AttributeFaasVersion; + /// private static readonly Func AttributeFaasTrigger = (_) => FaasAttributes.AttributeFaasTrigger; + /// private static readonly Func AttributeFaasColdStart = (_) => FaasAttributes.AttributeFaasColdstart; - // Gen AI Attributes + // GEN AI Attributes + /// private static readonly Func AttributeGenAiModelId = (_) => GenAiAttributes.AttributeGenAiRequestModel; + /// private static readonly Func AttributeGenAiSystem = (_) => GenAiAttributes.AttributeGenAiSystem; - // Host Attributes + // HOST Attributes + /// private static readonly Func AttributeHostID = (_) => HostAttributes.AttributeHostId; + /// private static readonly Func AttributeHostType = (_) => HostAttributes.AttributeHostType; + /// private static readonly Func AttributeHostName = (_) => HostAttributes.AttributeHostName; // Http Attributes - private static readonly Func AttributeHttpStatusCode = (_) => HttpAttributes.AttributeHttpStatusCode; - private static readonly Func AttributeHttpScheme = (_) => HttpAttributes.AttributeHttpScheme; - private static readonly Func AttributeHttpTarget = (_) => HttpAttributes.AttributeHttpTarget; + /// + private static readonly Func AttributeHttpStatusCode = (v) => v switch + { + Ver.v0_10_EXPERIMENTAL => "http.status_code", + _ => AttributeHttpResponseStatusCode(v), // replaced with http response status code + }; + /// + private static readonly Func AttributeHttpResponseStatusCode = (_) => HttpAttributes.AttributeHttpResponseStatusCode; + /// + private static readonly Func AttributeHttpScheme = (v) => v switch + { + Ver.v0_10_EXPERIMENTAL => "http.scheme", + _ => AttributeUrlScheme(v), // replaced with url scheme + }; + /// + private static readonly Func AttributeHttpTarget = (v) => v switch + { + Ver.v0_10_EXPERIMENTAL => "http.target", + _ => string.Empty, // value no longer written + }; + /// private static readonly Func AttributeHttpMethod = (_) => HttpAttributes.AttributeHttpMethod; - // Net Attributes + // NET Attributes + /// private static readonly Func AttributeNetHostName = (_) => NetAttributes.AttributeNetHostName; + /// private static readonly Func AttributeNetHostPort = (_) => NetAttributes.AttributeNetHostPort; // K8s Attributes + /// private static readonly Func AttributeK8SClusterName = (_) => K8sAttributes.AttributeK8sClusterName; - // Service Attributes + // SERVICE Attributes + /// private static readonly Func AttributeServiceName = (_) => ServiceAttributes.AttributeServiceName; + /// private static readonly Func AttributeServiceNamespace = (_) => ServiceAttributes.AttributeServiceNamespace; + /// private static readonly Func AttributeServiceInstanceID = (_) => ServiceAttributes.AttributeServiceInstanceId; + /// private static readonly Func AttributeServiceVersion = (_) => ServiceAttributes.AttributeServiceVersion; public static string ServiceNameValuesAwsElasticBeanstalk = "aws_elastic_beanstalk"; + // URL Attributes + /// + private static readonly Func AttributeUrlPath = (v) => v switch + { + Ver.v0_10_EXPERIMENTAL => string.Empty, //not used in v0.10 + _ => "url.path", + }; + /// + private static readonly Func AttributeUrlQuery = (v) => v switch + { + Ver.v0_10_EXPERIMENTAL => string.Empty, //not used in v0.10 + _ => "url.query", + }; + /// + private static readonly Func AttributeUrlScheme = (v) => v switch + { + Ver.v0_10_EXPERIMENTAL => string.Empty, //not used in v0.10 + _ => "url.scheme", + }; + #region Service Parameter Mapping + /// public static IDictionary AddAttributeAWSDynamoTableName(this IDictionary dict, string value) => AddDic(dict, AttributeAWSDynamoTableName, value); - + /// public static IDictionary AddAttributeAWSSQSQueueUrl(this IDictionary dict, string value) => AddDic(dict, AttributeAWSSQSQueueUrl, value); - + /// public static IDictionary AddAttributeGenAiModelId(this IDictionary dict, string value) => AddDic(dict, AttributeGenAiModelId, value); - + /// public static IDictionary AddAttributeAWSBedrockAgentId(this IDictionary dict, string value) => AddDic(dict, AttributeAWSBedrockAgentId, value); - + /// public static IDictionary AddAttributeAWSBedrockDataSourceId(this IDictionary dict, string value) => AddDic(dict, AttributeAWSBedrockDataSourceId, value); - + /// public static IDictionary AddAttributeAWSBedrockGuardrailId(this IDictionary dict, string value) => AddDic(dict, AttributeAWSBedrockGuardrailId, value); + /// public static IDictionary AddAttributeAWSBedrockKnowledgeBaseId(this IDictionary dict, string value) => AddDic(dict, AttributeAWSBedrockKnowledgeBaseId, value); #endregion #region Cloud Attributes + /// public static T AddAttributeCloudAccountID(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeCloudAccountID, value, addIfNull); - + /// public static T AddAttributeCloudAvailabilityZone(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeCloudAvailabilityZone, value, addIfNull); - + /// public static T AddAttributeCloudPlatform(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeCloudPlatform, value, addIfNull); - + /// public static T AddAttributeCloudProvider(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeCloudProvider, value, addIfNull); - + /// public static T AddAttributeCloudRegion(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeCloudRegion, value, addIfNull); - + /// public static T AddAttributeCloudResourceId(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeCloudResourceId, value, addIfNull); #endregion #region Container + /// public static T AddAttributeContainerId(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeContainerID, value, addIfNull); #endregion #region AWS + /// public static Activity? SetTagAttributeDbSystemToDynamoDb(this Activity? activity) => SetTag(activity, AttributeDbSystem, DbAttributes.DbSystemValues.Dynamodb); // <---- todo - + /// public static Activity? SetTagAttributeGenAiSystemToBedrock(this Activity? activity) => SetTag(activity, AttributeGenAiSystem, AttributeAWSBedrock(SemanticConventionVersion)); - + /// public static T AddAttributeEcsContainerArn(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeEcsContainerArn, value, addIfNull); - + /// public static T AddAttributeEcsClusterArn(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeEcsClusterArn, value, addIfNull); - + /// public static T AddAttributeEcsLaunchtype(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeEcsLaunchtype, value, addIfNull); - + /// public static T AddAttributeEcsLaunchtypeIsEc2(this T attributes) where T : IList> => AddAttributeEcsLaunchtype(attributes, AWSSemanticConventions.ValueEcsLaunchTypeEc2); - + /// public static T AddAttributeEcsLaunchtypeIsFargate(this T attributes) where T : IList> => AddAttributeEcsLaunchtype(attributes, AWSSemanticConventions.ValueEcsLaunchTypeFargate); - + /// public static T AddAttributeEcsTaskArn(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeEcsTaskArn, value, addIfNull); - + /// public static T AddAttributeEcsTaskFamily(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeEcsTaskFamily, value, addIfNull); - + /// public static T AddAttributeEcsTaskRevision(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeEcsTaskRevision, value, addIfNull); - + /// public static T AddAttributeLogGroupNames(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeLogGroupNames, value, addIfNull); - + /// public static T AddAttributeLogGroupArns(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeLogGroupArns, value, addIfNull); - + /// public static T AddAttributeLogStreamNames(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeLogStreamNames, value, addIfNull); - + /// public static T AddAttributeLogStreamArns(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeLogStreamArns, value, addIfNull); #endregion #region Faas + /// public static T AddAttributeFaasID(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeFaasID, value, addIfNull); - + /// public static T AddAttributeFaasExecution(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeFaasExecution, value, addIfNull); - + /// public static T AddAttributeFaasName(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeFaasName, value, addIfNull); - + /// public static T AddAttributeFaasVersion(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeFaasVersion, value, addIfNull); - + /// public static T AddAttributeFaasTrigger(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeFaasTrigger, value, addIfNull); - + /// public static T AddAttributeFaasColdStart(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeFaasColdStart, value, addIfNull); #endregion #region Host + /// public static T AddAttributeHostID(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeHostID, value, addIfNull); - + /// public static T AddAttributeHostType(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeHostType, value, addIfNull); - + /// public static T AddAttributeHostName(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeHostName, value, addIfNull); #endregion #region Http - + /// public static Activity? SetTagAttributeHttpStatusCode(this Activity? activity, int value) => SetTag(activity, AttributeHttpStatusCode, value); - + /// public static T AddAttributeHttpScheme(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeHttpScheme, value, addIfNull); - + /// public static T AddAttributeHttpTarget(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeHttpTarget, value, addIfNull); - + /// public static T AddAttributeHttpMethod(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeHttpMethod, value, addIfNull); #endregion #region Net + /// public static T AddAttributeNetHostName(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeNetHostName, value, addIfNull); - + /// public static T AddAttributeNetHostPort(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeNetHostPort, value, addIfNull); #endregion #region K8s + /// public static T AddAttributeK8SClusterName(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeK8SClusterName, value, addIfNull); - - public static T AddAttributeContainerID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeContainerID, value, addIfNull); #endregion #region Service + /// public static T AddAttributeServiceName(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeServiceName, value, addIfNull); - + /// public static T AddAttributeServiceNamespace(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeServiceNamespace, value, addIfNull); - + /// public static T AddAttributeServiceInstanceID(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeServiceInstanceID, value, addIfNull); - + /// public static T AddAttributeServiceVersion(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeServiceVersion, value, addIfNull); #endregion + #region Url + /// + public static T AddAttributeUrlPath(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeUrlPath, value, addIfNull); + /// + public static T AddAttributeUrlQuery(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, AttributeUrlQuery, value, addIfNull); + #endregion + private static T Add(this T attributes, Func attributeNameFunc, object? value, bool addIfNull = false) where T : IList> { @@ -320,7 +423,7 @@ private static T Add(this T attributes, Func attributeNameFunc, return attributes; } - attributes.Add(new(attributeName, value)); + attributes.Add(new(attributeName, value ?? string.Empty)); return attributes; } @@ -334,7 +437,7 @@ private static T Add(this T attributes, Func attributeNameFunc, return activity; } - public static IDictionary AddDic(IDictionary dict, Func attributeNameFunc, string value) + private static IDictionary AddDic(IDictionary dict, Func attributeNameFunc, string value) { var attributeName = attributeNameFunc(SemanticConventionVersion); From 67c2b03160d1d88bbf96f539d520c6db8c805093 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Mon, 2 Dec 2024 18:26:50 -0800 Subject: [PATCH 04/35] inline attribute strings and update obsolete attributes --- src/Shared/AWS/AWSSemanticConventions.cs | 120 ++++++++++++++--------- 1 file changed, 73 insertions(+), 47 deletions(-) diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index ed801d9130..85120cadda 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -21,16 +21,16 @@ namespace OpenTelemetry.AWS; public enum SemanticConventionVersion { /// - /// Pin to the specific state of all Semantic Conventions as of the 0.10 release of this library. + /// Pin to the specific state of all Semantic Conventions as of the 1.10 release of this library. /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.27.0 /// - v0_10_EXPERIMENTAL, + v1_10_EXPERIMENTAL, /// - /// Pin to the specific state of all Semantic Conventions as of the 0.11 release of this library. + /// Pin to the specific state of all Semantic Conventions as of the 1.11 release of this library. /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.29.0 /// - v0_11_EXPERIMENTAL, + v1_11_EXPERIMENTAL, /// /// Use Experimental Conventions until they become stable and then pin to stable. @@ -88,34 +88,36 @@ internal static class AWSSemanticConventions // DB Attributes /// private static readonly Func AttributeDbSystem = (_) => "db.system"; + /// + private static readonly Func AttributeDynamoDb = (_) => "dynamodb"; // AWS Attributes /// - private static readonly Func AttributeEcsContainerArn = (_) => AwsAttributes.AttributeAwsEcsContainerArn; + private static readonly Func AttributeEcsContainerArn = (_) => "aws.ecs.container.arn"; /// - private static readonly Func AttributeEcsClusterArn = (_) => AwsAttributes.AttributeAwsEcsClusterArn; + private static readonly Func AttributeEcsClusterArn = (_) => "aws.ecs.cluster.arn"; /// - private static readonly Func AttributeEcsLaunchtype = (_) => AwsAttributes.AttributeAwsEcsLaunchtype; + private static readonly Func AttributeEcsLaunchtype = (_) => "aws.ecs.launchtype"; /// - private static readonly Func ValueEcsLaunchTypeEc2 = (_) => AwsAttributes.AwsEcsLaunchtypeValues.Ec2; + private static readonly Func ValueEcsLaunchTypeEc2 = (_) => "ec2"; /// - private static readonly Func ValueEcsLaunchTypeFargate = (_) => AwsAttributes.AwsEcsLaunchtypeValues.Fargate; + private static readonly Func ValueEcsLaunchTypeFargate = (_) => "fargate"; /// - private static readonly Func AttributeEcsTaskArn = (_) => AwsAttributes.AttributeAwsEcsTaskArn; + private static readonly Func AttributeEcsTaskArn = (_) => "aws.ecs.task.arn"; /// - private static readonly Func AttributeEcsTaskFamily = (_) => AwsAttributes.AttributeAwsEcsTaskFamily; + private static readonly Func AttributeEcsTaskFamily = (_) => "aws.ecs.task.family"; /// - private static readonly Func AttributeEcsTaskRevision = (_) => AwsAttributes.AttributeAwsEcsTaskRevision; + private static readonly Func AttributeEcsTaskRevision = (_) => "aws.ecs.task.revision"; /// - private static readonly Func AttributeLogGroupNames = (_) => AwsAttributes.AttributeAwsLogGroupNames; + private static readonly Func AttributeLogGroupNames = (_) => "aws.log.group.names"; /// - private static readonly Func AttributeLogGroupArns = (_) => AwsAttributes.AttributeAwsLogGroupArns; + private static readonly Func AttributeLogGroupArns = (_) => "aws.log.group.arns"; /// - private static readonly Func AttributeLogStreamNames = (_) => AwsAttributes.AttributeAwsLogStreamArns; + private static readonly Func AttributeLogStreamNames = (_) => "aws.log.stream.arns"; /// - private static readonly Func AttributeLogStreamArns = (_) => AwsAttributes.AttributeAwsLogStreamNames; + private static readonly Func AttributeLogStreamArns = (_) => "aws.log.stream.names"; /// - private static readonly Func AttributeAWSDynamoTableName = (_) => AwsAttributes.AttributeAwsDynamodbTableNames; + private static readonly Func AttributeAWSDynamoTableName = (_) => "aws.dynamodb.table_names"; /// private static readonly Func AttributeAWSSQSQueueUrl = (_) => "aws.queue_url"; // todo - confirm in java; /// @@ -129,100 +131,121 @@ internal static class AWSSemanticConventions /// private static readonly Func AttributeAWSBedrock = (v) => v switch { - SemanticConventionVersion.v0_10_EXPERIMENTAL => "aws_bedrock", + SemanticConventionVersion.v1_10_EXPERIMENTAL => "aws_bedrock", _ => "aws.bedrock", //v1.29 }; // FAAS Attributes /// - private static readonly Func AttributeFaasID = (_) => CloudAttributes.AttributeCloudResourceId; + private static readonly Func AttributeFaasID = (_) => "cloud.resource_id"; /// - private static readonly Func AttributeFaasExecution = (_) => FaasAttributes.AttributeFaasInvocationId; + private static readonly Func AttributeFaasExecution = (_) => "faas.invocation_id"; /// - private static readonly Func AttributeFaasName = (_) => FaasAttributes.AttributeFaasName; + private static readonly Func AttributeFaasName = (_) => "faas.name"; /// - private static readonly Func AttributeFaasVersion = (_) => FaasAttributes.AttributeFaasVersion; + private static readonly Func AttributeFaasVersion = (_) => "faas.version"; /// - private static readonly Func AttributeFaasTrigger = (_) => FaasAttributes.AttributeFaasTrigger; + private static readonly Func AttributeFaasTrigger = (_) => "faas.trigger"; /// - private static readonly Func AttributeFaasColdStart = (_) => FaasAttributes.AttributeFaasColdstart; + private static readonly Func AttributeFaasColdStart = (_) => "faas.coldstart"; // GEN AI Attributes /// - private static readonly Func AttributeGenAiModelId = (_) => GenAiAttributes.AttributeGenAiRequestModel; + private static readonly Func AttributeGenAiModelId = (_) => "gen_ai.request.model"; /// - private static readonly Func AttributeGenAiSystem = (_) => GenAiAttributes.AttributeGenAiSystem; + private static readonly Func AttributeGenAiSystem = (_) => "gen_ai.system"; // HOST Attributes /// - private static readonly Func AttributeHostID = (_) => HostAttributes.AttributeHostId; + private static readonly Func AttributeHostID = (_) => "host.id"; /// - private static readonly Func AttributeHostType = (_) => HostAttributes.AttributeHostType; + private static readonly Func AttributeHostType = (_) => "host.type"; /// - private static readonly Func AttributeHostName = (_) => HostAttributes.AttributeHostName; + private static readonly Func AttributeHostName = (_) => "host.name"; // Http Attributes /// private static readonly Func AttributeHttpStatusCode = (v) => v switch { - Ver.v0_10_EXPERIMENTAL => "http.status_code", + Ver.v1_10_EXPERIMENTAL => "http.status_code", _ => AttributeHttpResponseStatusCode(v), // replaced with http response status code }; /// - private static readonly Func AttributeHttpResponseStatusCode = (_) => HttpAttributes.AttributeHttpResponseStatusCode; + private static readonly Func AttributeHttpResponseStatusCode = (_) => "http.response.status_code"; /// private static readonly Func AttributeHttpScheme = (v) => v switch { - Ver.v0_10_EXPERIMENTAL => "http.scheme", + Ver.v1_10_EXPERIMENTAL => "http.scheme", _ => AttributeUrlScheme(v), // replaced with url scheme }; /// private static readonly Func AttributeHttpTarget = (v) => v switch { - Ver.v0_10_EXPERIMENTAL => "http.target", + Ver.v1_10_EXPERIMENTAL => "http.target", _ => string.Empty, // value no longer written }; - /// - private static readonly Func AttributeHttpMethod = (_) => HttpAttributes.AttributeHttpMethod; + /// + private static readonly Func AttributeHttpMethod = (v) => v switch + { + Ver.v1_10_EXPERIMENTAL => "http.method", + _ => AttributeHttpRequestMethod(v), // replaced with http request method + }; + /// + private static readonly Func AttributeHttpRequestMethod = (_) => "http.request.method"; + // NET Attributes /// - private static readonly Func AttributeNetHostName = (_) => NetAttributes.AttributeNetHostName; + private static readonly Func AttributeNetHostName = (v) => v switch + { + Ver.v1_10_EXPERIMENTAL => "net.host.name", + _ => AttributeServerAddress(v), // replaced with server address + }; /// - private static readonly Func AttributeNetHostPort = (_) => NetAttributes.AttributeNetHostPort; + private static readonly Func AttributeNetHostPort = (v) => v switch + { + Ver.v1_10_EXPERIMENTAL => "net.host.port", + _ => AttributeServerPort(v), // replaced with server port + }; + + // SERVER Attributes + /// + private static readonly Func AttributeServerAddress = (_) => "server.address"; + /// + private static readonly Func AttributeServerPort = (_) => "server.port"; // K8s Attributes /// - private static readonly Func AttributeK8SClusterName = (_) => K8sAttributes.AttributeK8sClusterName; + private static readonly Func AttributeK8SClusterName = (_) => "k8s.cluster.name"; // SERVICE Attributes /// - private static readonly Func AttributeServiceName = (_) => ServiceAttributes.AttributeServiceName; + private static readonly Func AttributeServiceName = (_) => "service.name"; /// - private static readonly Func AttributeServiceNamespace = (_) => ServiceAttributes.AttributeServiceNamespace; + private static readonly Func AttributeServiceNamespace = (_) => "service.namespace"; /// - private static readonly Func AttributeServiceInstanceID = (_) => ServiceAttributes.AttributeServiceInstanceId; + private static readonly Func AttributeServiceInstanceID = (_) => "service.instance.id"; /// - private static readonly Func AttributeServiceVersion = (_) => ServiceAttributes.AttributeServiceVersion; + private static readonly Func AttributeServiceVersion = (_) => "service.version"; public static string ServiceNameValuesAwsElasticBeanstalk = "aws_elastic_beanstalk"; // URL Attributes /// private static readonly Func AttributeUrlPath = (v) => v switch { - Ver.v0_10_EXPERIMENTAL => string.Empty, //not used in v0.10 + Ver.v1_10_EXPERIMENTAL => string.Empty, //not used in v1.10 _ => "url.path", }; /// private static readonly Func AttributeUrlQuery = (v) => v switch { - Ver.v0_10_EXPERIMENTAL => string.Empty, //not used in v0.10 + Ver.v1_10_EXPERIMENTAL => string.Empty, //not used in v1.10 _ => "url.query", }; /// private static readonly Func AttributeUrlScheme = (v) => v switch { - Ver.v0_10_EXPERIMENTAL => string.Empty, //not used in v0.10 + Ver.v1_10_EXPERIMENTAL => string.Empty, //not used in v1.10 _ => "url.scheme", }; @@ -281,10 +304,10 @@ public static T AddAttributeContainerId(this T attributes, object? value, boo #region AWS /// public static Activity? SetTagAttributeDbSystemToDynamoDb(this Activity? activity) - => SetTag(activity, AttributeDbSystem, DbAttributes.DbSystemValues.Dynamodb); // <---- todo + => SetTag(activity, AttributeDbSystem, AttributeDynamoDb); /// public static Activity? SetTagAttributeGenAiSystemToBedrock(this Activity? activity) - => SetTag(activity, AttributeGenAiSystem, AttributeAWSBedrock(SemanticConventionVersion)); + => SetTag(activity, AttributeGenAiSystem, AttributeAWSBedrock); /// public static T AddAttributeEcsContainerArn(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeEcsContainerArn, value, addIfNull); @@ -428,6 +451,9 @@ private static T Add(this T attributes, Func attributeNameFunc, return attributes; } + private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, Func valueFunc) => + SetTag(activity, attributeNameFunc, valueFunc(SemanticConventionVersion)); + private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, object? value) { var attributeName = attributeNameFunc(SemanticConventionVersion); From d24827905b7d64a044f6615dfe1714194df81968 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Tue, 3 Dec 2024 23:24:45 -0800 Subject: [PATCH 05/35] Alternate strategy to simplify implementation --- .../.publicApi/PublicAPI.Unshipped.txt | 1 + .../TracerProviderBuilderExtensions.cs | 3 + .../.publicApi/PublicAPI.Unshipped.txt | 1 + .../AWSLambdaResourceDetector.cs | 2 +- .../AWSEBSDetector.cs | 6 +- .../AWSEC2Detector.cs | 4 +- .../AWSECSDetector.cs | 4 +- .../AWSEKSDetector.cs | 4 +- .../AWS/AWSSemanticConventions.Alt.Base.cs | 194 +++++++++++ src/Shared/AWS/AWSSemanticConventions.Alt.cs | 322 ++++++++++++++++++ .../AWS/AWSSemanticConventions.Alt.v1.10.cs | 102 ++++++ .../AWS/AWSSemanticConventions.Alt.v1.10_1.cs | 46 +++ src/Shared/AWS/AWSSemanticConventions.cs | 9 +- src/Shared/AWS/SemanticConventionVersion.cs | 60 ++++ 14 files changed, 745 insertions(+), 13 deletions(-) create mode 100644 src/Shared/AWS/AWSSemanticConventions.Alt.Base.cs create mode 100644 src/Shared/AWS/AWSSemanticConventions.Alt.cs create mode 100644 src/Shared/AWS/AWSSemanticConventions.Alt.v1.10.cs create mode 100644 src/Shared/AWS/AWSSemanticConventions.Alt.v1.10_1.cs create mode 100644 src/Shared/AWS/SemanticConventionVersion.cs diff --git a/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt index d8633d91a7..e89899177b 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt @@ -1,4 +1,5 @@ #nullable enable +OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.AWSClientInstrumentationOptions() -> void OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SuppressDownstreamInstrumentation.get -> bool diff --git a/src/OpenTelemetry.Instrumentation.AWS/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.AWS/TracerProviderBuilderExtensions.cs index 5cf55bcd81..4187ade6dc 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.AWS/TracerProviderBuilderExtensions.cs @@ -3,6 +3,7 @@ using Amazon; using Amazon.Runtime.Telemetry; +using OpenTelemetry.AWS; using OpenTelemetry.Instrumentation.AWS; using OpenTelemetry.Instrumentation.AWS.Implementation; using OpenTelemetry.Instrumentation.AWS.Implementation.Tracing; @@ -38,6 +39,8 @@ public static TracerProviderBuilder AddAWSInstrumentation( var awsClientOptions = new AWSClientInstrumentationOptions(); configure?.Invoke(awsClientOptions); + AWSSemanticConventions.SemanticConventionVersion = awsClientOptions.SemanticConventionVersion; + _ = new AWSClientsInstrumentation(awsClientOptions); AWSConfigs.TelemetryProvider.RegisterTracerProvider(new AWSTracerProvider()); diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt index 74efa0b2d7..c15767dc98 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt @@ -1,4 +1,5 @@ #nullable enable +OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.AWSLambdaInstrumentationOptions() -> void OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.DisableAwsXRayContextExtraction.get -> bool diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaResourceDetector.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaResourceDetector.cs index 45cc6d4c8c..e3a46ed728 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaResourceDetector.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaResourceDetector.cs @@ -16,7 +16,7 @@ public Resource Detect() { var resourceAttributes = new List>(4) - .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) + .AddAttributeCloudProviderIsAWS() .AddAttributeCloudRegion(AWSLambdaUtils.GetAWSRegion()) .AddAttributeFaasName(AWSLambdaUtils.GetFunctionName()) .AddAttributeFaasVersion(AWSLambdaUtils.GetFunctionVersion()); diff --git a/src/OpenTelemetry.Resources.AWS/AWSEBSDetector.cs b/src/OpenTelemetry.Resources.AWS/AWSEBSDetector.cs index 2acc505a19..c588cc496f 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSEBSDetector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSEBSDetector.cs @@ -57,9 +57,9 @@ internal static List> ExtractResourceAttributes(AWS { var resourceAttributes = new List>() - .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) - .AddAttributeCloudPlatform(AWSSemanticConventions.CloudPlatformValuesAwsElasticBeanstalk) - .AddAttributeServiceName(AWSSemanticConventions.ServiceNameValuesAwsElasticBeanstalk) + .AddAttributeCloudProviderIsAWS() + .AddAttributeCloudPlatformIsAwsElasticBeanstalk() + .AddAttributeServiceNameIsAwsElasticBeanstalk() .AddAttributeServiceNamespace(metadata?.EnvironmentName) .AddAttributeServiceInstanceID(metadata?.DeploymentId) .AddAttributeServiceVersion(metadata?.VersionLabel); diff --git a/src/OpenTelemetry.Resources.AWS/AWSEC2Detector.cs b/src/OpenTelemetry.Resources.AWS/AWSEC2Detector.cs index 93b3f14ce2..4375bb6b1d 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSEC2Detector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSEC2Detector.cs @@ -46,8 +46,8 @@ internal static List> ExtractResourceAttributes(AWS { var resourceAttributes = new List>() - .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) - .AddAttributeCloudPlatform(AWSSemanticConventions.CloudPlatformValuesAwsEc2) + .AddAttributeCloudProviderIsAWS() + .AddAttributeCloudPlatformIsAwsEc2() .AddAttributeHostName(hostName) .AddAttributeCloudAccountID(identity?.AccountId) .AddAttributeCloudAvailabilityZone(identity?.AvailabilityZone) diff --git a/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs b/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs index 550103ce2c..15869ad232 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs @@ -31,8 +31,8 @@ public Resource Detect() var resourceAttributes = new List>() - .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) - .AddAttributeCloudPlatform(AWSSemanticConventions.CloudPlatformValuesAwsEcs); + .AddAttributeCloudProviderIsAWS() + .AddAttributeCloudPlatformIsAwsEcs(); try { var containerId = GetECSContainerId(AWSECSMetadataPath); diff --git a/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs b/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs index c86a6b7c20..a05e615404 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSEKSDetector.cs @@ -38,8 +38,8 @@ public Resource Detect() internal static List> ExtractResourceAttributes(string? clusterName, string? containerId) { var resourceAttributes = new List>() - .AddAttributeCloudProvider(AWSSemanticConventions.CloudProviderValuesAws) - .AddAttributeCloudPlatform(AWSSemanticConventions.CloudPlatformValuesAwsEks) + .AddAttributeCloudProviderIsAWS() + .AddAttributeCloudPlatformIsAwsEks() .AddAttributeK8SClusterName(clusterName) .AddAttributeContainerId(containerId); diff --git a/src/Shared/AWS/AWSSemanticConventions.Alt.Base.cs b/src/Shared/AWS/AWSSemanticConventions.Alt.Base.cs new file mode 100644 index 0000000000..d4aa76d586 --- /dev/null +++ b/src/Shared/AWS/AWSSemanticConventions.Alt.Base.cs @@ -0,0 +1,194 @@ + +using OpenTelemetry.SemanticConventions; + + +namespace OpenTelemetry.AWS; + +// disable Style Warnings to improve readability of this specific file. +#pragma warning disable SA1124 +#pragma warning disable SA1005 +#pragma warning disable SA1514 +#pragma warning disable SA1201 +#pragma warning disable SA1623 + +internal static partial class AWSSemanticConventions +{ + /// + /// Defines all Semantic Conventions used by AWS extension projects. + /// + /// All values default to string.Empty and are then is only defined + /// in the first version specific class (ie ) + /// to use it. This helps ensure the attribute doesn't get used if the user has specified + /// a specific . + /// + /// See for details. + /// + private abstract class AWSSemanticConventionsBase + { + // CLOUD Attributes + /// + public virtual string AttributeCloudAccountID => string.Empty; + /// + public virtual string AttributeCloudAvailabilityZone => string.Empty; + /// + public virtual string AttributeCloudPlatform => string.Empty; + /// + public virtual string AttributeCloudProvider => string.Empty; + /// + public virtual string AttributeCloudRegion => string.Empty; + /// + public virtual string AttributeCloudResourceId => string.Empty; + /// + public virtual string CloudPlatformValuesAwsEc2 => string.Empty; + /// + public virtual string CloudPlatformValuesAwsEcs => string.Empty; + /// + public virtual string CloudPlatformValuesAwsEks => string.Empty; + /// + public virtual string CloudPlatformValuesAwsElasticBeanstalk => string.Empty; + /// + public virtual string CloudProviderValuesAws => string.Empty; + + // CONTAINER Attributes + /// + public virtual string AttributeContainerID => string.Empty; + + // DB Attributes + /// + public virtual string AttributeDbSystem => string.Empty; + /// + public virtual string AttributeDynamoDb => string.Empty; + + // AWS Attributes + /// + public virtual string AttributeEcsContainerArn => string.Empty; + /// + public virtual string AttributeEcsClusterArn => string.Empty; + /// + public virtual string AttributeEcsLaunchtype => string.Empty; + /// + public virtual string ValueEcsLaunchTypeEc2 => string.Empty; + /// + public virtual string ValueEcsLaunchTypeFargate => string.Empty; + /// + public virtual string AttributeEcsTaskArn => string.Empty; + /// + public virtual string AttributeEcsTaskFamily => string.Empty; + /// + public virtual string AttributeEcsTaskRevision => string.Empty; + /// + public virtual string AttributeLogGroupNames => string.Empty; + /// + public virtual string AttributeLogGroupArns => string.Empty; + /// + public virtual string AttributeLogStreamNames => string.Empty; + /// + public virtual string AttributeLogStreamArns => string.Empty; + /// + public virtual string AttributeAWSDynamoTableName => string.Empty; + /// + /// Not yet incorporated in Semantic Conventions repository. + /// + public virtual string AttributeAWSSQSQueueUrl => string.Empty; + /// + /// Not yet incorporated in Semantic Conventions repository. + /// + public virtual string AttributeAWSBedrockAgentId => string.Empty; + /// + /// Not yet incorporated in Semantic Conventions repository. + /// + public virtual string AttributeAWSBedrockDataSourceId => string.Empty; + /// + /// Not yet incorporated in Semantic Conventions repository. + /// + public virtual string AttributeAWSBedrockGuardrailId => string.Empty; + /// + /// Not yet incorporated in Semantic Conventions repository. + /// + public virtual string AttributeAWSBedrockKnowledgeBaseId => string.Empty; + /// + /// Not yet incorporated in Semantic Conventions repository. + /// + public virtual string AttributeAWSBedrock => string.Empty; + + // FAAS Attributes + /// + public virtual string AttributeFaasID => string.Empty; + /// + public virtual string AttributeFaasExecution => string.Empty; + /// + public virtual string AttributeFaasName => string.Empty; + /// + public virtual string AttributeFaasVersion => string.Empty; + /// + public virtual string AttributeFaasTrigger => string.Empty; + /// + public virtual string AttributeFaasColdStart => string.Empty; + + // GEN AI Attributes + /// + public virtual string AttributeGenAiModelId => string.Empty; + /// + public virtual string AttributeGenAiSystem => string.Empty; + + // HOST Attributes + /// + public virtual string AttributeHostID => string.Empty; + /// + public virtual string AttributeHostType => string.Empty; + /// + public virtual string AttributeHostName => string.Empty; + + // HTTP Attributes + /// + public virtual string AttributeHttpStatusCode => string.Empty; + /// + public virtual string AttributeHttpResponseStatusCode => string.Empty; + /// + public virtual string AttributeHttpScheme => string.Empty; + /// + public virtual string AttributeHttpTarget => string.Empty; + /// + public virtual string AttributeHttpMethod => string.Empty; + /// + public virtual string AttributeHttpRequestMethod => string.Empty; + + // NET Attributes + /// + public virtual string AttributeNetHostName => string.Empty; + /// + public virtual string AttributeNetHostPort => string.Empty; + + // SERVER Attributes + /// + public virtual string AttributeServerAddress => string.Empty; + /// + public virtual string AttributeServerPort => string.Empty; + + // K8s Attributes + /// + public virtual string AttributeK8SClusterName => string.Empty; + + // SERVICE Attributes + /// + public virtual string AttributeServiceName => string.Empty; + /// + public virtual string AttributeServiceNamespace => string.Empty; + /// + public virtual string AttributeServiceInstanceID => string.Empty; + /// + public virtual string AttributeServiceVersion => string.Empty; + /// + /// Not yet incorporated in Semantic Conventions repository. + /// + public virtual string ServiceNameValuesAwsElasticBeanstalk => string.Empty; + + // URL Attributes + /// + public virtual string AttributeUrlPath => string.Empty; + /// + public virtual string AttributeUrlQuery => string.Empty; + /// + public virtual string AttributeUrlScheme => string.Empty; + } +} diff --git a/src/Shared/AWS/AWSSemanticConventions.Alt.cs b/src/Shared/AWS/AWSSemanticConventions.Alt.cs new file mode 100644 index 0000000000..e63eb6de4a --- /dev/null +++ b/src/Shared/AWS/AWSSemanticConventions.Alt.cs @@ -0,0 +1,322 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.ComponentModel; +using System.Diagnostics; + +// disable Style Warnings to improve readability of this specific file. +#pragma warning disable SA1124 +#pragma warning disable SA1005 +#pragma warning disable SA1514 +#pragma warning disable SA1201 +#pragma warning disable SA1623 + +namespace OpenTelemetry.AWS; + +/// +/// Abstracts the complexities of honoring . +/// +/// Classes emitting attributes can use the extension methods in this class to build +/// a List of s containing Attribute Name and Value without +/// needing to know which version of the Semantic Convention to use. +/// +/// Below is a hypothetical example showing how attributes can be constructed. It is not necessary +/// for this consumer to accommodate differing behavior based on , +/// as that will be handled by the extension methods (ie ) themselves. +/// +/// >() +/// .AddAttributeCloudResourceId(containerArn) +/// .AddAttributeFoo("value 1") +/// .AddAttributeBar("value 2"); +/// ]]> +/// +/// +/// +internal static partial class AWSSemanticConventions +{ + /// + /// + /// Sets the that will be used to resolve attribute names. + /// + /// This should be set by an Options class. + /// + public static SemanticConventionVersion SemanticConventionVersion { get; set; } = DefaultSemanticConventionVersion; + + /// + /// Options classes should use this value for initialization. + /// + /// Example: + /// + /// + /// public SemanticConventionVersion SemanticConventionVersion { get; set; } = AWSSemanticConventions.DefaultSemanticConventionVersion; + /// } + /// ]]> + /// + /// + internal const SemanticConventionVersion DefaultSemanticConventionVersion = SemanticConventionVersion.Latest; + + #region Service Parameter Mapping + + /// + public static IDictionary AddAttributeAWSDynamoTableName(this IDictionary dict, string value) + => AddDic(dict, x => x.AttributeAWSDynamoTableName, value); + /// + public static IDictionary AddAttributeAWSSQSQueueUrl(this IDictionary dict, string value) + => AddDic(dict, x => x.AttributeAWSSQSQueueUrl, value); + /// + public static IDictionary AddAttributeGenAiModelId(this IDictionary dict, string value) + => AddDic(dict, x => x.AttributeGenAiModelId, value); + /// + public static IDictionary AddAttributeAWSBedrockAgentId(this IDictionary dict, string value) + => AddDic(dict, x => x.AttributeAWSBedrockAgentId, value); + /// + public static IDictionary AddAttributeAWSBedrockDataSourceId(this IDictionary dict, string value) + => AddDic(dict, x => x.AttributeAWSBedrockDataSourceId, value); + /// + public static IDictionary AddAttributeAWSBedrockGuardrailId(this IDictionary dict, string value) + => AddDic(dict, x => x.AttributeAWSBedrockGuardrailId, value); + /// + public static IDictionary AddAttributeAWSBedrockKnowledgeBaseId(this IDictionary dict, string value) + => AddDic(dict, x => x.AttributeAWSBedrockKnowledgeBaseId, value); + #endregion + + #region Cloud Attributes + /// + public static T AddAttributeCloudAccountID(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeCloudAccountID, value, addIfNull); + /// + public static T AddAttributeCloudAvailabilityZone(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeCloudAvailabilityZone, value, addIfNull); + /// + public static T AddAttributeCloudPlatformIsAwsEc2(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEc2); + /// + public static T AddAttributeCloudPlatformIsAwsEcs(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEcs); + /// + public static T AddAttributeCloudPlatformIsAwsEks(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEks); + /// + public static T AddAttributeCloudPlatformIsAwsElasticBeanstalk(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsElasticBeanstalk); + /// + public static T AddAttributeCloudProviderIsAWS(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudProvider, x => x.CloudProviderValuesAws); + /// + public static T AddAttributeCloudRegion(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeCloudRegion, value, addIfNull); + /// + public static T AddAttributeCloudResourceId(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeCloudResourceId, value, addIfNull); + #endregion + + #region Container + /// + public static T AddAttributeContainerId(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeContainerID, value, addIfNull); + #endregion + + #region AWS + /// + public static Activity? SetTagAttributeDbSystemToDynamoDb(this Activity? activity) + => SetTag(activity, x => x.AttributeDbSystem, x => x.AttributeDynamoDb); + /// + public static Activity? SetTagAttributeGenAiSystemToBedrock(this Activity? activity) + => SetTag(activity, x => x.AttributeGenAiSystem, x => x.AttributeAWSBedrock); + /// + public static T AddAttributeEcsContainerArn(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeEcsContainerArn, value, addIfNull); + /// + public static T AddAttributeEcsClusterArn(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeEcsClusterArn, value, addIfNull); + /// + public static T AddAttributeEcsLaunchtypeIsEc2(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeEc2); + /// + public static T AddAttributeEcsLaunchtypeIsFargate(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeFargate); + /// + public static T AddAttributeEcsTaskArn(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeEcsTaskArn, value, addIfNull); + /// + public static T AddAttributeEcsTaskFamily(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeEcsTaskFamily, value, addIfNull); + /// + public static T AddAttributeEcsTaskRevision(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeEcsTaskRevision, value, addIfNull); + /// + public static T AddAttributeLogGroupNames(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeLogGroupNames, value, addIfNull); + /// + public static T AddAttributeLogGroupArns(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeLogGroupArns, value, addIfNull); + /// + public static T AddAttributeLogStreamNames(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeLogStreamNames, value, addIfNull); + /// + public static T AddAttributeLogStreamArns(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeLogStreamArns, value, addIfNull); + #endregion + + #region Faas + /// + public static T AddAttributeFaasID(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeFaasID, value, addIfNull); + /// + public static T AddAttributeFaasExecution(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeFaasExecution, value, addIfNull); + /// + public static T AddAttributeFaasName(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeFaasName, value, addIfNull); + /// + public static T AddAttributeFaasVersion(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeFaasVersion, value, addIfNull); + /// + public static T AddAttributeFaasTrigger(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeFaasTrigger, value, addIfNull); + /// + public static T AddAttributeFaasColdStart(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeFaasColdStart, value, addIfNull); + + #endregion + + #region Host + /// + public static T AddAttributeHostID(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeHostID, value, addIfNull); + /// + public static T AddAttributeHostType(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeHostType, value, addIfNull); + /// + public static T AddAttributeHostName(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeHostName, value, addIfNull); + #endregion + + #region Http + /// + public static Activity? SetTagAttributeHttpStatusCode(this Activity? activity, int value) + => SetTag(activity, x => x.AttributeHttpStatusCode, value); + /// + public static T AddAttributeHttpScheme(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeHttpScheme, value, addIfNull); + /// + public static T AddAttributeHttpTarget(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeHttpTarget, value, addIfNull); + /// + public static T AddAttributeHttpMethod(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeHttpMethod, value, addIfNull); + #endregion + + #region Net + /// + public static T AddAttributeNetHostName(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeNetHostName, value, addIfNull); + /// + public static T AddAttributeNetHostPort(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeNetHostPort, value, addIfNull); + #endregion + + #region K8s + /// + public static T AddAttributeK8SClusterName(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeK8SClusterName, value, addIfNull); + #endregion + + #region Service + /// + public static T AddAttributeServiceNameIsAwsElasticBeanstalk(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeServiceName, x => x.ServiceNameValuesAwsElasticBeanstalk); + /// + public static T AddAttributeServiceNamespace(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeServiceNamespace, value, addIfNull); + /// + public static T AddAttributeServiceInstanceID(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeServiceInstanceID, value, addIfNull); + /// + public static T AddAttributeServiceVersion(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeServiceVersion, value, addIfNull); + #endregion + + #region Url + /// + public static T AddAttributeUrlPath(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeUrlPath, value, addIfNull); + /// + public static T AddAttributeUrlQuery(this T attributes, object? value, bool addIfNull = false) + where T : IList> => Add(attributes, x => x.AttributeUrlQuery, value, addIfNull); + #endregion + + private static T Add(this T attributes, Func attributeNameFunc, Func valueFunc) + where T : IList> => Add(attributes, attributeNameFunc, valueFunc(GetSemanticConventionVersion())); + + private static T Add(this T attributes, Func attributeNameFunc, object? value, bool addIfNull = false) + where T : IList> + { + var semanticConventionVersionImpl = GetSemanticConventionVersion(); + + var attributeName = attributeNameFunc(semanticConventionVersionImpl); + + // if attributeName is empty or there is no value, exit + if (string.IsNullOrEmpty(attributeName) || + (string.IsNullOrEmpty(value?.ToString()) && !addIfNull)) + { + return attributes; + } + + attributes.Add(new(attributeName, value ?? string.Empty)); + + return attributes; + } + + private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, Func valueFunc) => + SetTag(activity, attributeNameFunc, valueFunc(GetSemanticConventionVersion())); + + private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, object? value) + { + var semanticConventionVersionImpl = GetSemanticConventionVersion(); + + var attributeName = attributeNameFunc(semanticConventionVersionImpl); + + activity?.SetTag(attributeName, value); + + return activity; + } + + private static IDictionary AddDic(IDictionary dict, Func attributeNameFunc, string value) + { + var semanticConventionVersionImpl = GetSemanticConventionVersion(); + + var attributeName = attributeNameFunc(semanticConventionVersionImpl); + + if (!string.IsNullOrEmpty(attributeName)) + { + dict.Add(attributeName, value); + } + + return dict; + } + + private static AWSSemanticConventionsBase GetSemanticConventionVersion() + { + switch (SemanticConventionVersion) + { + case SemanticConventionVersion.Latest: + case SemanticConventionVersion.v1_10_1_Experimental: + return new AWSSemanticConventions_v1_10_1(); + + case SemanticConventionVersion.v1_10_Experimental: + return new AWSSemanticConventions_v1_10(); + + default: + throw new InvalidEnumArgumentException( + argumentName: nameof(SemanticConventionVersion), + (int)SemanticConventionVersion, + typeof(SemanticConventionVersion)); + } + } +} diff --git a/src/Shared/AWS/AWSSemanticConventions.Alt.v1.10.cs b/src/Shared/AWS/AWSSemanticConventions.Alt.v1.10.cs new file mode 100644 index 0000000000..8bd6afcae4 --- /dev/null +++ b/src/Shared/AWS/AWSSemanticConventions.Alt.v1.10.cs @@ -0,0 +1,102 @@ +namespace OpenTelemetry.AWS; + +// disable Style Warnings to improve readability of this specific file. +#pragma warning disable SA1124 +#pragma warning disable SA1005 +#pragma warning disable SA1514 +#pragma warning disable SA1516 +#pragma warning disable SA1201 + +internal static partial class AWSSemanticConventions +{ + /// + /// Open Telemetry Semantic Conventions as of the 1.10 release of this library. + /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.27.0. + /// + /// + /// This is the first version to include Semantic Conventions defined in this manner, so it + /// defines string constants for all attributes. + /// + /// Future version specific convention classes will only need to define new or changed attributes. + /// + private class AWSSemanticConventions_v1_10 : AWSSemanticConventionsBase + { + // CLOUD Attributes + public override string AttributeCloudAccountID => "cloud.account.id"; + public override string AttributeCloudAvailabilityZone => "cloud.availability_zone"; + public override string AttributeCloudPlatform => "cloud.platform"; + public override string AttributeCloudProvider => "cloud.provider"; + public override string AttributeCloudRegion => "cloud.region"; + public override string AttributeCloudResourceId => "cloud.resource_id"; + public override string CloudPlatformValuesAwsEc2 => "aws_ec2"; + public override string CloudPlatformValuesAwsEcs => "aws_ecs"; + public override string CloudPlatformValuesAwsEks => "aws_eks"; + public override string CloudPlatformValuesAwsElasticBeanstalk => "aws_elastic_beanstalk"; + public override string CloudProviderValuesAws => "aws"; + + // CONTAINER Attributes + public override string AttributeContainerID => "container.id"; + + // DB Attributes + public override string AttributeDbSystem => "db.system"; + public override string AttributeDynamoDb => "dynamodb"; + + // AWS Attributes + public override string AttributeEcsContainerArn => "aws.ecs.container.arn"; + public override string AttributeEcsClusterArn => "aws.ecs.cluster.arn"; + public override string AttributeEcsLaunchtype => "aws.ecs.launchtype"; + public override string ValueEcsLaunchTypeEc2 => "ec2"; + public override string ValueEcsLaunchTypeFargate => "fargate"; + public override string AttributeEcsTaskArn => "aws.ecs.task.arn"; + public override string AttributeEcsTaskFamily => "aws.ecs.task.family"; + public override string AttributeEcsTaskRevision => "aws.ecs.task.revision"; + public override string AttributeLogGroupNames => "aws.log.group.names"; + public override string AttributeLogGroupArns => "aws.log.group.arns"; + public override string AttributeLogStreamNames => "aws.log.stream.arns"; + public override string AttributeLogStreamArns => "aws.log.stream.names"; + public override string AttributeAWSDynamoTableName => "aws.dynamodb.table_names"; + public override string AttributeAWSSQSQueueUrl => "aws.queue_url"; // todo - confirm in java; + public override string AttributeAWSBedrockAgentId => "aws.bedrock.agent.id"; + public override string AttributeAWSBedrockDataSourceId => "aws.bedrock.data_source.id"; + public override string AttributeAWSBedrockGuardrailId => "aws.bedrock.guardrail.id"; + public override string AttributeAWSBedrockKnowledgeBaseId => "aws.bedrock.knowledge_base.id"; + public override string AttributeAWSBedrock => "aws_bedrock"; + + // FAAS Attributes + public override string AttributeFaasID => "faas.id"; + public override string AttributeFaasExecution => "faas.execution"; + public override string AttributeFaasName => "faas.name"; + public override string AttributeFaasVersion => "faas.version"; + public override string AttributeFaasTrigger => "faas.trigger"; + public override string AttributeFaasColdStart => "faas.coldstart"; + + // GEN AI Attributes + public override string AttributeGenAiModelId => "gen_ai.request.model"; + public override string AttributeGenAiSystem => "gen_ai.system"; + + // HOST Attributes + public override string AttributeHostID => "host.id"; + public override string AttributeHostType => "host.type"; + public override string AttributeHostName => "host.name"; + + // HTTP Attributes + public override string AttributeHttpStatusCode => "http.status_code"; + public override string AttributeHttpScheme => "http.scheme"; + public override string AttributeHttpTarget => "http.target"; + public override string AttributeHttpMethod => "http.method"; + + // NET Attributes + public override string AttributeNetHostName => "net.host.name"; + public override string AttributeNetHostPort => "net.host.port"; + + // K8s Attributes + public override string AttributeK8SClusterName => "k8s.cluster.name"; + + // SERVICE Attributes + public override string AttributeServiceName => "service.name"; + public override string AttributeServiceNamespace => "service.namespace"; + public override string AttributeServiceInstanceID => "service.instance.id"; + public override string AttributeServiceVersion => "service.version"; + public override string ServiceNameValuesAwsElasticBeanstalk => "aws_elastic_beanstalk"; + } +} diff --git a/src/Shared/AWS/AWSSemanticConventions.Alt.v1.10_1.cs b/src/Shared/AWS/AWSSemanticConventions.Alt.v1.10_1.cs new file mode 100644 index 0000000000..a2cf1fc001 --- /dev/null +++ b/src/Shared/AWS/AWSSemanticConventions.Alt.v1.10_1.cs @@ -0,0 +1,46 @@ +namespace OpenTelemetry.AWS; + +// disable Style Warnings to improve readability of this specific file. +#pragma warning disable SA1124 +#pragma warning disable SA1005 +#pragma warning disable SA1514 +#pragma warning disable SA1201 +#pragma warning disable SA1516 + +internal static partial class AWSSemanticConventions +{ + /// + /// Open Telemetry Semantic Conventions as of the 1.10.1 release of this library. + /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.29.0. + /// + private class AWSSemanticConventions_v1_10_1 : AWSSemanticConventions_v1_10 + { + // AWS Attributes + public override string AttributeAWSBedrock => "aws.bedrock"; + + // FAAS Attributes + public override string AttributeFaasID => "cloud.resource_id"; + public override string AttributeFaasExecution => "faas.invocation_id"; + + // HTTP Attributes + public override string AttributeHttpStatusCode => this.AttributeHttpResponseStatusCode; + public override string AttributeHttpScheme => this.AttributeUrlScheme; + public override string AttributeHttpTarget => string.Empty; // value no longer written + public override string AttributeHttpMethod => this.AttributeHttpRequestMethod; + public override string AttributeHttpResponseStatusCode => "http.response.status_code"; + public override string AttributeHttpRequestMethod => "http.request.method"; + + // NET Attributes + public override string AttributeNetHostName => this.AttributeServerAddress; + public override string AttributeNetHostPort => this.AttributeServerPort; + + // SERVER Attributes + public override string AttributeServerAddress => "server.address"; + public override string AttributeServerPort => "server.port"; + + // URL Attributes + public override string AttributeUrlPath => "url.path"; + public override string AttributeUrlQuery => "url.query"; + public override string AttributeUrlScheme => "url.scheme"; + } +} diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index 85120cadda..78b8d2c913 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using OpenTelemetry.SemanticConventions; +/* using Ver = OpenTelemetry.AWS.SemanticConventionVersion; // disable Style Warnings to improve readability of this specific file. @@ -53,6 +54,7 @@ public enum SemanticConventionVersion /// /// On the next major version bump, cease emitting out-of-date Attributes. /// + internal static class AWSSemanticConventions { public static SemanticConventionVersion SemanticConventionVersion { get; set; } @@ -319,10 +321,10 @@ public static T AddAttributeEcsLaunchtype(this T attributes, object? value, b where T : IList> => Add(attributes, AttributeEcsLaunchtype, value, addIfNull); /// public static T AddAttributeEcsLaunchtypeIsEc2(this T attributes) - where T : IList> => AddAttributeEcsLaunchtype(attributes, AWSSemanticConventions.ValueEcsLaunchTypeEc2); + where T : IList> => AddAttributeEcsLaunchtype(attributes, ValueEcsLaunchTypeEc2); /// public static T AddAttributeEcsLaunchtypeIsFargate(this T attributes) - where T : IList> => AddAttributeEcsLaunchtype(attributes, AWSSemanticConventions.ValueEcsLaunchTypeFargate); + where T : IList> => AddAttributeEcsLaunchtype(attributes, ValueEcsLaunchTypeFargate); /// public static T AddAttributeEcsTaskArn(this T attributes, object? value, bool addIfNull = false) where T : IList> => Add(attributes, AttributeEcsTaskArn, value, addIfNull); @@ -441,7 +443,7 @@ private static T Add(this T attributes, Func attributeNameFunc, // if attributeName is empty or there is no value, exit if (string.IsNullOrEmpty(attributeName) || - (string.IsNullOrEmpty(value?.ToString()) && !addIfNull)) + (value == null && !addIfNull)) { return attributes; } @@ -475,3 +477,4 @@ private static IDictionary AddDic(IDictionary di return dict; } } + */ diff --git a/src/Shared/AWS/SemanticConventionVersion.cs b/src/Shared/AWS/SemanticConventionVersion.cs new file mode 100644 index 0000000000..f67d6b6dbf --- /dev/null +++ b/src/Shared/AWS/SemanticConventionVersion.cs @@ -0,0 +1,60 @@ +namespace OpenTelemetry.AWS; + +#pragma warning disable SA1300 +#pragma warning disable CA1707 + +/// +/// +/// Collection of the Open Telemetry Semantic Conventions supported by the OpenTelemetry.*.AWS libraries. +/// Can be used to pin the version of Semantic Convention emitted. +/// +/// +/// While these libraries are intended for production use, they rely on several Semantic Conventions that are +/// still considered Experimental, meaning they may undergo additional changes before becoming Stable. This can +/// impact the aggregation and analysis of telemetry signals in environments with multiple applications or microservices. +/// For example, a microservice using an older version of the Semantic Conventions for Http Attributes may emit +/// "http.method" with a value of GET,while a different microservice, using a new version of Semantic Convention may instead emit the GET as +/// "http.request.method". +/// +/// +/// Future versions the OpenTelemetry.*.AWS libraries will include updates to the Semantic Convention, which may break compatibility with a previous version. +/// To opt-out of automatic upgrades, you can pin to a specific version: +/// +/// +/// { +/// opt.SemanticConventionVersion = SemanticConventionVersion.v1_10_EXPERIMENTAL; +/// }) +/// .Build()!) +/// ]]> +/// +/// +/// +/// For additional details, see: +/// https://opentelemetry.io/docs/specs/otel/versioning-and-stability/. +/// +/// +/// +/// Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS libraries will remain on that version until the +/// next major version bump. +/// +public enum SemanticConventionVersion +{ + /// + /// Use Experimental Conventions until they become stable and then pin to stable. + /// + Latest = 0, + + /// + /// Pin to the specific state of all Semantic Conventions as of the 1.10 release of this library. + /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.27.0. + /// + v1_10_Experimental = 1, + + /// + /// Pin to the specific state of all Semantic Conventions as of the 1.10.1 release of this library. + /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.29.0. + /// + v1_10_1_Experimental = 2, +} From 7658b78894aaa88db8eab1771b5ccb23d0a95fb3 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Thu, 5 Dec 2024 15:09:59 -0800 Subject: [PATCH 06/35] renamed files to reflect decision to user simpler model for managing semantic convention versions --- src/Shared/AWS/AWSSemanticConventions.Alt.cs | 322 ----------- ...Base.cs => AWSSemanticConventions.Base.cs} | 0 src/Shared/AWS/AWSSemanticConventions.cs | 530 ++++++------------ ....10.cs => AWSSemanticConventions.v1.10.cs} | 0 ...1.cs => AWSSemanticConventions.v1.10_1.cs} | 0 5 files changed, 186 insertions(+), 666 deletions(-) delete mode 100644 src/Shared/AWS/AWSSemanticConventions.Alt.cs rename src/Shared/AWS/{AWSSemanticConventions.Alt.Base.cs => AWSSemanticConventions.Base.cs} (100%) rename src/Shared/AWS/{AWSSemanticConventions.Alt.v1.10.cs => AWSSemanticConventions.v1.10.cs} (100%) rename src/Shared/AWS/{AWSSemanticConventions.Alt.v1.10_1.cs => AWSSemanticConventions.v1.10_1.cs} (100%) diff --git a/src/Shared/AWS/AWSSemanticConventions.Alt.cs b/src/Shared/AWS/AWSSemanticConventions.Alt.cs deleted file mode 100644 index e63eb6de4a..0000000000 --- a/src/Shared/AWS/AWSSemanticConventions.Alt.cs +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -using System.ComponentModel; -using System.Diagnostics; - -// disable Style Warnings to improve readability of this specific file. -#pragma warning disable SA1124 -#pragma warning disable SA1005 -#pragma warning disable SA1514 -#pragma warning disable SA1201 -#pragma warning disable SA1623 - -namespace OpenTelemetry.AWS; - -/// -/// Abstracts the complexities of honoring . -/// -/// Classes emitting attributes can use the extension methods in this class to build -/// a List of s containing Attribute Name and Value without -/// needing to know which version of the Semantic Convention to use. -/// -/// Below is a hypothetical example showing how attributes can be constructed. It is not necessary -/// for this consumer to accommodate differing behavior based on , -/// as that will be handled by the extension methods (ie ) themselves. -/// -/// >() -/// .AddAttributeCloudResourceId(containerArn) -/// .AddAttributeFoo("value 1") -/// .AddAttributeBar("value 2"); -/// ]]> -/// -/// -/// -internal static partial class AWSSemanticConventions -{ - /// - /// - /// Sets the that will be used to resolve attribute names. - /// - /// This should be set by an Options class. - /// - public static SemanticConventionVersion SemanticConventionVersion { get; set; } = DefaultSemanticConventionVersion; - - /// - /// Options classes should use this value for initialization. - /// - /// Example: - /// - /// - /// public SemanticConventionVersion SemanticConventionVersion { get; set; } = AWSSemanticConventions.DefaultSemanticConventionVersion; - /// } - /// ]]> - /// - /// - internal const SemanticConventionVersion DefaultSemanticConventionVersion = SemanticConventionVersion.Latest; - - #region Service Parameter Mapping - - /// - public static IDictionary AddAttributeAWSDynamoTableName(this IDictionary dict, string value) - => AddDic(dict, x => x.AttributeAWSDynamoTableName, value); - /// - public static IDictionary AddAttributeAWSSQSQueueUrl(this IDictionary dict, string value) - => AddDic(dict, x => x.AttributeAWSSQSQueueUrl, value); - /// - public static IDictionary AddAttributeGenAiModelId(this IDictionary dict, string value) - => AddDic(dict, x => x.AttributeGenAiModelId, value); - /// - public static IDictionary AddAttributeAWSBedrockAgentId(this IDictionary dict, string value) - => AddDic(dict, x => x.AttributeAWSBedrockAgentId, value); - /// - public static IDictionary AddAttributeAWSBedrockDataSourceId(this IDictionary dict, string value) - => AddDic(dict, x => x.AttributeAWSBedrockDataSourceId, value); - /// - public static IDictionary AddAttributeAWSBedrockGuardrailId(this IDictionary dict, string value) - => AddDic(dict, x => x.AttributeAWSBedrockGuardrailId, value); - /// - public static IDictionary AddAttributeAWSBedrockKnowledgeBaseId(this IDictionary dict, string value) - => AddDic(dict, x => x.AttributeAWSBedrockKnowledgeBaseId, value); - #endregion - - #region Cloud Attributes - /// - public static T AddAttributeCloudAccountID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeCloudAccountID, value, addIfNull); - /// - public static T AddAttributeCloudAvailabilityZone(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeCloudAvailabilityZone, value, addIfNull); - /// - public static T AddAttributeCloudPlatformIsAwsEc2(this T attributes) - where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEc2); - /// - public static T AddAttributeCloudPlatformIsAwsEcs(this T attributes) - where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEcs); - /// - public static T AddAttributeCloudPlatformIsAwsEks(this T attributes) - where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEks); - /// - public static T AddAttributeCloudPlatformIsAwsElasticBeanstalk(this T attributes) - where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsElasticBeanstalk); - /// - public static T AddAttributeCloudProviderIsAWS(this T attributes) - where T : IList> => Add(attributes, x => x.AttributeCloudProvider, x => x.CloudProviderValuesAws); - /// - public static T AddAttributeCloudRegion(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeCloudRegion, value, addIfNull); - /// - public static T AddAttributeCloudResourceId(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeCloudResourceId, value, addIfNull); - #endregion - - #region Container - /// - public static T AddAttributeContainerId(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeContainerID, value, addIfNull); - #endregion - - #region AWS - /// - public static Activity? SetTagAttributeDbSystemToDynamoDb(this Activity? activity) - => SetTag(activity, x => x.AttributeDbSystem, x => x.AttributeDynamoDb); - /// - public static Activity? SetTagAttributeGenAiSystemToBedrock(this Activity? activity) - => SetTag(activity, x => x.AttributeGenAiSystem, x => x.AttributeAWSBedrock); - /// - public static T AddAttributeEcsContainerArn(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsContainerArn, value, addIfNull); - /// - public static T AddAttributeEcsClusterArn(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsClusterArn, value, addIfNull); - /// - public static T AddAttributeEcsLaunchtypeIsEc2(this T attributes) - where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeEc2); - /// - public static T AddAttributeEcsLaunchtypeIsFargate(this T attributes) - where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeFargate); - /// - public static T AddAttributeEcsTaskArn(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsTaskArn, value, addIfNull); - /// - public static T AddAttributeEcsTaskFamily(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsTaskFamily, value, addIfNull); - /// - public static T AddAttributeEcsTaskRevision(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsTaskRevision, value, addIfNull); - /// - public static T AddAttributeLogGroupNames(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeLogGroupNames, value, addIfNull); - /// - public static T AddAttributeLogGroupArns(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeLogGroupArns, value, addIfNull); - /// - public static T AddAttributeLogStreamNames(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeLogStreamNames, value, addIfNull); - /// - public static T AddAttributeLogStreamArns(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeLogStreamArns, value, addIfNull); - #endregion - - #region Faas - /// - public static T AddAttributeFaasID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasID, value, addIfNull); - /// - public static T AddAttributeFaasExecution(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasExecution, value, addIfNull); - /// - public static T AddAttributeFaasName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasName, value, addIfNull); - /// - public static T AddAttributeFaasVersion(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasVersion, value, addIfNull); - /// - public static T AddAttributeFaasTrigger(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasTrigger, value, addIfNull); - /// - public static T AddAttributeFaasColdStart(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasColdStart, value, addIfNull); - - #endregion - - #region Host - /// - public static T AddAttributeHostID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHostID, value, addIfNull); - /// - public static T AddAttributeHostType(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHostType, value, addIfNull); - /// - public static T AddAttributeHostName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHostName, value, addIfNull); - #endregion - - #region Http - /// - public static Activity? SetTagAttributeHttpStatusCode(this Activity? activity, int value) - => SetTag(activity, x => x.AttributeHttpStatusCode, value); - /// - public static T AddAttributeHttpScheme(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHttpScheme, value, addIfNull); - /// - public static T AddAttributeHttpTarget(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHttpTarget, value, addIfNull); - /// - public static T AddAttributeHttpMethod(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHttpMethod, value, addIfNull); - #endregion - - #region Net - /// - public static T AddAttributeNetHostName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeNetHostName, value, addIfNull); - /// - public static T AddAttributeNetHostPort(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeNetHostPort, value, addIfNull); - #endregion - - #region K8s - /// - public static T AddAttributeK8SClusterName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeK8SClusterName, value, addIfNull); - #endregion - - #region Service - /// - public static T AddAttributeServiceNameIsAwsElasticBeanstalk(this T attributes) - where T : IList> => Add(attributes, x => x.AttributeServiceName, x => x.ServiceNameValuesAwsElasticBeanstalk); - /// - public static T AddAttributeServiceNamespace(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeServiceNamespace, value, addIfNull); - /// - public static T AddAttributeServiceInstanceID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeServiceInstanceID, value, addIfNull); - /// - public static T AddAttributeServiceVersion(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeServiceVersion, value, addIfNull); - #endregion - - #region Url - /// - public static T AddAttributeUrlPath(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeUrlPath, value, addIfNull); - /// - public static T AddAttributeUrlQuery(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeUrlQuery, value, addIfNull); - #endregion - - private static T Add(this T attributes, Func attributeNameFunc, Func valueFunc) - where T : IList> => Add(attributes, attributeNameFunc, valueFunc(GetSemanticConventionVersion())); - - private static T Add(this T attributes, Func attributeNameFunc, object? value, bool addIfNull = false) - where T : IList> - { - var semanticConventionVersionImpl = GetSemanticConventionVersion(); - - var attributeName = attributeNameFunc(semanticConventionVersionImpl); - - // if attributeName is empty or there is no value, exit - if (string.IsNullOrEmpty(attributeName) || - (string.IsNullOrEmpty(value?.ToString()) && !addIfNull)) - { - return attributes; - } - - attributes.Add(new(attributeName, value ?? string.Empty)); - - return attributes; - } - - private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, Func valueFunc) => - SetTag(activity, attributeNameFunc, valueFunc(GetSemanticConventionVersion())); - - private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, object? value) - { - var semanticConventionVersionImpl = GetSemanticConventionVersion(); - - var attributeName = attributeNameFunc(semanticConventionVersionImpl); - - activity?.SetTag(attributeName, value); - - return activity; - } - - private static IDictionary AddDic(IDictionary dict, Func attributeNameFunc, string value) - { - var semanticConventionVersionImpl = GetSemanticConventionVersion(); - - var attributeName = attributeNameFunc(semanticConventionVersionImpl); - - if (!string.IsNullOrEmpty(attributeName)) - { - dict.Add(attributeName, value); - } - - return dict; - } - - private static AWSSemanticConventionsBase GetSemanticConventionVersion() - { - switch (SemanticConventionVersion) - { - case SemanticConventionVersion.Latest: - case SemanticConventionVersion.v1_10_1_Experimental: - return new AWSSemanticConventions_v1_10_1(); - - case SemanticConventionVersion.v1_10_Experimental: - return new AWSSemanticConventions_v1_10(); - - default: - throw new InvalidEnumArgumentException( - argumentName: nameof(SemanticConventionVersion), - (int)SemanticConventionVersion, - typeof(SemanticConventionVersion)); - } - } -} diff --git a/src/Shared/AWS/AWSSemanticConventions.Alt.Base.cs b/src/Shared/AWS/AWSSemanticConventions.Base.cs similarity index 100% rename from src/Shared/AWS/AWSSemanticConventions.Alt.Base.cs rename to src/Shared/AWS/AWSSemanticConventions.Base.cs diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index 78b8d2c913..9a2ce973b3 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -1,445 +1,265 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using System.ComponentModel; using System.Diagnostics; -using OpenTelemetry.SemanticConventions; - -/* -using Ver = OpenTelemetry.AWS.SemanticConventionVersion; // disable Style Warnings to improve readability of this specific file. #pragma warning disable SA1124 #pragma warning disable SA1005 #pragma warning disable SA1514 #pragma warning disable SA1201 +#pragma warning disable SA1623 namespace OpenTelemetry.AWS; /// -/// TODO -/// https://opentelemetry.io/docs/specs/otel/versioning-and-stability/ +/// Abstracts the complexities of honoring . +/// +/// Classes emitting attributes can use the extension methods in this class to build +/// a List of s containing Attribute Name and Value without +/// needing to know which version of the Semantic Convention to use. +/// +/// Below is a hypothetical example showing how attributes can be constructed. It is not necessary +/// for this consumer to accommodate differing behavior based on , +/// as that will be handled by the extension methods (ie ) themselves. +/// +/// >() +/// .AddAttributeCloudResourceId(containerArn) +/// .AddAttributeFoo("value 1") +/// .AddAttributeBar("value 2"); +/// ]]> +/// +/// /// -public enum SemanticConventionVersion +internal static partial class AWSSemanticConventions { /// - /// Pin to the specific state of all Semantic Conventions as of the 1.10 release of this library. - /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.27.0 + /// + /// Sets the that will be used to resolve attribute names. + /// + /// This should be set by an Options class. /// - v1_10_EXPERIMENTAL, + public static SemanticConventionVersion SemanticConventionVersion { get; set; } = DefaultSemanticConventionVersion; /// - /// Pin to the specific state of all Semantic Conventions as of the 1.11 release of this library. - /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.29.0 + /// Options classes should use this value for initialization. + /// + /// Example: + /// + /// + /// public SemanticConventionVersion SemanticConventionVersion { get; set; } = AWSSemanticConventions.DefaultSemanticConventionVersion; + /// } + /// ]]> + /// /// - v1_11_EXPERIMENTAL, - - /// - /// Use Experimental Conventions until they become stable and then pin to stable. - /// - EXPERIMENTAL_UNTIL_STABLE, - - /// - /// Always uwe the latest version of a Semantic Convention even if there is a stable version. - /// - ALWAYS_EXPERIMENTAL -}; - -/// -/// TODO - update documentation -/// Defines extension methods for adding attributes to a collection. -/// -/// This approach supports a forward looking with regard to experimental Attributes. If an -/// Attribute is changed, update the extension method so that it emits -both- the old and new -/// attribute names. -/// -/// On the next major version bump, cease emitting out-of-date Attributes. -/// - -internal static class AWSSemanticConventions -{ - public static SemanticConventionVersion SemanticConventionVersion { get; set; } - - /// - /// TODO - /// - internal const SemanticConventionVersion DefaultSemanticConventionVersion = Ver.EXPERIMENTAL_UNTIL_STABLE; - - // CLOUD Attributes - /// - private static readonly Func AttributeCloudAccountID = (_) => "cloud.account.id"; - /// - private static readonly Func AttributeCloudAvailabilityZone = (_) => "cloud.availability_zone"; - /// - private static readonly Func AttributeCloudPlatform = (_) => "cloud.platform"; - /// - private static readonly Func AttributeCloudProvider = (_) => "cloud.provider"; - /// - private static readonly Func AttributeCloudRegion = (_) => "cloud.region"; - /// - private static readonly Func AttributeCloudResourceId = (_) => "cloud.resource_id"; - public const string CloudPlatformValuesAwsEc2 = CloudAttributes.CloudPlatformValues.AwsEc2; - public const string CloudPlatformValuesAwsEcs = CloudAttributes.CloudPlatformValues.AwsEcs; - public const string CloudPlatformValuesAwsEks = CloudAttributes.CloudPlatformValues.AwsEks; - public const string CloudPlatformValuesAwsElasticBeanstalk = CloudAttributes.CloudPlatformValues.AwsElasticBeanstalk; - public const string CloudProviderValuesAws = CloudAttributes.CloudProviderValues.Aws; - - // CONTAINER Attributes - /// - private static readonly Func AttributeContainerID = (_) => "container.id"; - - // DB Attributes - /// - private static readonly Func AttributeDbSystem = (_) => "db.system"; - /// - private static readonly Func AttributeDynamoDb = (_) => "dynamodb"; - - // AWS Attributes - /// - private static readonly Func AttributeEcsContainerArn = (_) => "aws.ecs.container.arn"; - /// - private static readonly Func AttributeEcsClusterArn = (_) => "aws.ecs.cluster.arn"; - /// - private static readonly Func AttributeEcsLaunchtype = (_) => "aws.ecs.launchtype"; - /// - private static readonly Func ValueEcsLaunchTypeEc2 = (_) => "ec2"; - /// - private static readonly Func ValueEcsLaunchTypeFargate = (_) => "fargate"; - /// - private static readonly Func AttributeEcsTaskArn = (_) => "aws.ecs.task.arn"; - /// - private static readonly Func AttributeEcsTaskFamily = (_) => "aws.ecs.task.family"; - /// - private static readonly Func AttributeEcsTaskRevision = (_) => "aws.ecs.task.revision"; - /// - private static readonly Func AttributeLogGroupNames = (_) => "aws.log.group.names"; - /// - private static readonly Func AttributeLogGroupArns = (_) => "aws.log.group.arns"; - /// - private static readonly Func AttributeLogStreamNames = (_) => "aws.log.stream.arns"; - /// - private static readonly Func AttributeLogStreamArns = (_) => "aws.log.stream.names"; - /// - private static readonly Func AttributeAWSDynamoTableName = (_) => "aws.dynamodb.table_names"; - /// - private static readonly Func AttributeAWSSQSQueueUrl = (_) => "aws.queue_url"; // todo - confirm in java; - /// - private static readonly Func AttributeAWSBedrockAgentId = (_) => "aws.bedrock.agent.id"; - /// - private static readonly Func AttributeAWSBedrockDataSourceId = (_) => "aws.bedrock.data_source.id"; - /// - private static readonly Func AttributeAWSBedrockGuardrailId = (_) => "aws.bedrock.guardrail.id"; - /// - private static readonly Func AttributeAWSBedrockKnowledgeBaseId = (_) => "aws.bedrock.knowledge_base.id"; - /// - private static readonly Func AttributeAWSBedrock = (v) => v switch - { - SemanticConventionVersion.v1_10_EXPERIMENTAL => "aws_bedrock", - _ => "aws.bedrock", //v1.29 - }; - - // FAAS Attributes - /// - private static readonly Func AttributeFaasID = (_) => "cloud.resource_id"; - /// - private static readonly Func AttributeFaasExecution = (_) => "faas.invocation_id"; - /// - private static readonly Func AttributeFaasName = (_) => "faas.name"; - /// - private static readonly Func AttributeFaasVersion = (_) => "faas.version"; - /// - private static readonly Func AttributeFaasTrigger = (_) => "faas.trigger"; - /// - private static readonly Func AttributeFaasColdStart = (_) => "faas.coldstart"; - - // GEN AI Attributes - /// - private static readonly Func AttributeGenAiModelId = (_) => "gen_ai.request.model"; - /// - private static readonly Func AttributeGenAiSystem = (_) => "gen_ai.system"; - - // HOST Attributes - /// - private static readonly Func AttributeHostID = (_) => "host.id"; - /// - private static readonly Func AttributeHostType = (_) => "host.type"; - /// - private static readonly Func AttributeHostName = (_) => "host.name"; - - // Http Attributes - /// - private static readonly Func AttributeHttpStatusCode = (v) => v switch - { - Ver.v1_10_EXPERIMENTAL => "http.status_code", - _ => AttributeHttpResponseStatusCode(v), // replaced with http response status code - }; - /// - private static readonly Func AttributeHttpResponseStatusCode = (_) => "http.response.status_code"; - /// - private static readonly Func AttributeHttpScheme = (v) => v switch - { - Ver.v1_10_EXPERIMENTAL => "http.scheme", - _ => AttributeUrlScheme(v), // replaced with url scheme - }; - /// - private static readonly Func AttributeHttpTarget = (v) => v switch - { - Ver.v1_10_EXPERIMENTAL => "http.target", - _ => string.Empty, // value no longer written - }; - /// - private static readonly Func AttributeHttpMethod = (v) => v switch - { - Ver.v1_10_EXPERIMENTAL => "http.method", - _ => AttributeHttpRequestMethod(v), // replaced with http request method - }; - /// - private static readonly Func AttributeHttpRequestMethod = (_) => "http.request.method"; - - - // NET Attributes - /// - private static readonly Func AttributeNetHostName = (v) => v switch - { - Ver.v1_10_EXPERIMENTAL => "net.host.name", - _ => AttributeServerAddress(v), // replaced with server address - }; - /// - private static readonly Func AttributeNetHostPort = (v) => v switch - { - Ver.v1_10_EXPERIMENTAL => "net.host.port", - _ => AttributeServerPort(v), // replaced with server port - }; - - // SERVER Attributes - /// - private static readonly Func AttributeServerAddress = (_) => "server.address"; - /// - private static readonly Func AttributeServerPort = (_) => "server.port"; - - // K8s Attributes - /// - private static readonly Func AttributeK8SClusterName = (_) => "k8s.cluster.name"; - - // SERVICE Attributes - /// - private static readonly Func AttributeServiceName = (_) => "service.name"; - /// - private static readonly Func AttributeServiceNamespace = (_) => "service.namespace"; - /// - private static readonly Func AttributeServiceInstanceID = (_) => "service.instance.id"; - /// - private static readonly Func AttributeServiceVersion = (_) => "service.version"; - public static string ServiceNameValuesAwsElasticBeanstalk = "aws_elastic_beanstalk"; - - // URL Attributes - /// - private static readonly Func AttributeUrlPath = (v) => v switch - { - Ver.v1_10_EXPERIMENTAL => string.Empty, //not used in v1.10 - _ => "url.path", - }; - /// - private static readonly Func AttributeUrlQuery = (v) => v switch - { - Ver.v1_10_EXPERIMENTAL => string.Empty, //not used in v1.10 - _ => "url.query", - }; - /// - private static readonly Func AttributeUrlScheme = (v) => v switch - { - Ver.v1_10_EXPERIMENTAL => string.Empty, //not used in v1.10 - _ => "url.scheme", - }; + internal const SemanticConventionVersion DefaultSemanticConventionVersion = SemanticConventionVersion.Latest; #region Service Parameter Mapping - /// + /// public static IDictionary AddAttributeAWSDynamoTableName(this IDictionary dict, string value) - => AddDic(dict, AttributeAWSDynamoTableName, value); - /// + => AddDic(dict, x => x.AttributeAWSDynamoTableName, value); + /// public static IDictionary AddAttributeAWSSQSQueueUrl(this IDictionary dict, string value) - => AddDic(dict, AttributeAWSSQSQueueUrl, value); - /// + => AddDic(dict, x => x.AttributeAWSSQSQueueUrl, value); + /// public static IDictionary AddAttributeGenAiModelId(this IDictionary dict, string value) - => AddDic(dict, AttributeGenAiModelId, value); - /// + => AddDic(dict, x => x.AttributeGenAiModelId, value); + /// public static IDictionary AddAttributeAWSBedrockAgentId(this IDictionary dict, string value) - => AddDic(dict, AttributeAWSBedrockAgentId, value); - /// + => AddDic(dict, x => x.AttributeAWSBedrockAgentId, value); + /// public static IDictionary AddAttributeAWSBedrockDataSourceId(this IDictionary dict, string value) - => AddDic(dict, AttributeAWSBedrockDataSourceId, value); - /// + => AddDic(dict, x => x.AttributeAWSBedrockDataSourceId, value); + /// public static IDictionary AddAttributeAWSBedrockGuardrailId(this IDictionary dict, string value) - => AddDic(dict, AttributeAWSBedrockGuardrailId, value); - /// + => AddDic(dict, x => x.AttributeAWSBedrockGuardrailId, value); + /// public static IDictionary AddAttributeAWSBedrockKnowledgeBaseId(this IDictionary dict, string value) - => AddDic(dict, AttributeAWSBedrockKnowledgeBaseId, value); + => AddDic(dict, x => x.AttributeAWSBedrockKnowledgeBaseId, value); #endregion #region Cloud Attributes - /// + /// public static T AddAttributeCloudAccountID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeCloudAccountID, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeCloudAccountID, value, addIfNull); + /// public static T AddAttributeCloudAvailabilityZone(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeCloudAvailabilityZone, value, addIfNull); - /// - public static T AddAttributeCloudPlatform(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeCloudPlatform, value, addIfNull); - /// - public static T AddAttributeCloudProvider(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeCloudProvider, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeCloudAvailabilityZone, value, addIfNull); + /// + public static T AddAttributeCloudPlatformIsAwsEc2(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEc2); + /// + public static T AddAttributeCloudPlatformIsAwsEcs(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEcs); + /// + public static T AddAttributeCloudPlatformIsAwsEks(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEks); + /// + public static T AddAttributeCloudPlatformIsAwsElasticBeanstalk(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsElasticBeanstalk); + /// + public static T AddAttributeCloudProviderIsAWS(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeCloudProvider, x => x.CloudProviderValuesAws); + /// public static T AddAttributeCloudRegion(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeCloudRegion, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeCloudRegion, value, addIfNull); + /// public static T AddAttributeCloudResourceId(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeCloudResourceId, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeCloudResourceId, value, addIfNull); #endregion #region Container - /// + /// public static T AddAttributeContainerId(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeContainerID, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeContainerID, value, addIfNull); #endregion #region AWS - /// + /// public static Activity? SetTagAttributeDbSystemToDynamoDb(this Activity? activity) - => SetTag(activity, AttributeDbSystem, AttributeDynamoDb); - /// + => SetTag(activity, x => x.AttributeDbSystem, x => x.AttributeDynamoDb); + /// public static Activity? SetTagAttributeGenAiSystemToBedrock(this Activity? activity) - => SetTag(activity, AttributeGenAiSystem, AttributeAWSBedrock); - /// + => SetTag(activity, x => x.AttributeGenAiSystem, x => x.AttributeAWSBedrock); + /// public static T AddAttributeEcsContainerArn(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeEcsContainerArn, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeEcsContainerArn, value, addIfNull); + /// public static T AddAttributeEcsClusterArn(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeEcsClusterArn, value, addIfNull); - /// - public static T AddAttributeEcsLaunchtype(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeEcsLaunchtype, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeEcsClusterArn, value, addIfNull); + /// public static T AddAttributeEcsLaunchtypeIsEc2(this T attributes) - where T : IList> => AddAttributeEcsLaunchtype(attributes, ValueEcsLaunchTypeEc2); - /// + where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeEc2); + /// public static T AddAttributeEcsLaunchtypeIsFargate(this T attributes) - where T : IList> => AddAttributeEcsLaunchtype(attributes, ValueEcsLaunchTypeFargate); - /// + where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeFargate); + /// public static T AddAttributeEcsTaskArn(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeEcsTaskArn, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeEcsTaskArn, value, addIfNull); + /// public static T AddAttributeEcsTaskFamily(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeEcsTaskFamily, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeEcsTaskFamily, value, addIfNull); + /// public static T AddAttributeEcsTaskRevision(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeEcsTaskRevision, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeEcsTaskRevision, value, addIfNull); + /// public static T AddAttributeLogGroupNames(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeLogGroupNames, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeLogGroupNames, value, addIfNull); + /// public static T AddAttributeLogGroupArns(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeLogGroupArns, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeLogGroupArns, value, addIfNull); + /// public static T AddAttributeLogStreamNames(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeLogStreamNames, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeLogStreamNames, value, addIfNull); + /// public static T AddAttributeLogStreamArns(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeLogStreamArns, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeLogStreamArns, value, addIfNull); #endregion #region Faas - /// + /// public static T AddAttributeFaasID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeFaasID, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeFaasID, value, addIfNull); + /// public static T AddAttributeFaasExecution(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeFaasExecution, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeFaasExecution, value, addIfNull); + /// public static T AddAttributeFaasName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeFaasName, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeFaasName, value, addIfNull); + /// public static T AddAttributeFaasVersion(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeFaasVersion, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeFaasVersion, value, addIfNull); + /// public static T AddAttributeFaasTrigger(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeFaasTrigger, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeFaasTrigger, value, addIfNull); + /// public static T AddAttributeFaasColdStart(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeFaasColdStart, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeFaasColdStart, value, addIfNull); #endregion #region Host - /// + /// public static T AddAttributeHostID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeHostID, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeHostID, value, addIfNull); + /// public static T AddAttributeHostType(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeHostType, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeHostType, value, addIfNull); + /// public static T AddAttributeHostName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeHostName, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeHostName, value, addIfNull); #endregion #region Http - /// + /// public static Activity? SetTagAttributeHttpStatusCode(this Activity? activity, int value) - => SetTag(activity, AttributeHttpStatusCode, value); - /// + => SetTag(activity, x => x.AttributeHttpStatusCode, value); + /// public static T AddAttributeHttpScheme(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeHttpScheme, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeHttpScheme, value, addIfNull); + /// public static T AddAttributeHttpTarget(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeHttpTarget, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeHttpTarget, value, addIfNull); + /// public static T AddAttributeHttpMethod(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeHttpMethod, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeHttpMethod, value, addIfNull); #endregion #region Net - /// + /// public static T AddAttributeNetHostName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeNetHostName, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeNetHostName, value, addIfNull); + /// public static T AddAttributeNetHostPort(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeNetHostPort, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeNetHostPort, value, addIfNull); #endregion #region K8s - /// + /// public static T AddAttributeK8SClusterName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeK8SClusterName, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeK8SClusterName, value, addIfNull); #endregion #region Service - /// - public static T AddAttributeServiceName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeServiceName, value, addIfNull); - /// + /// + public static T AddAttributeServiceNameIsAwsElasticBeanstalk(this T attributes) + where T : IList> => Add(attributes, x => x.AttributeServiceName, x => x.ServiceNameValuesAwsElasticBeanstalk); + /// public static T AddAttributeServiceNamespace(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeServiceNamespace, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeServiceNamespace, value, addIfNull); + /// public static T AddAttributeServiceInstanceID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeServiceInstanceID, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeServiceInstanceID, value, addIfNull); + /// public static T AddAttributeServiceVersion(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeServiceVersion, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeServiceVersion, value, addIfNull); #endregion #region Url - /// + /// public static T AddAttributeUrlPath(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeUrlPath, value, addIfNull); - /// + where T : IList> => Add(attributes, x => x.AttributeUrlPath, value, addIfNull); + /// public static T AddAttributeUrlQuery(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, AttributeUrlQuery, value, addIfNull); + where T : IList> => Add(attributes, x => x.AttributeUrlQuery, value, addIfNull); #endregion - private static T Add(this T attributes, Func attributeNameFunc, object? value, bool addIfNull = false) + private static T Add(this T attributes, Func attributeNameFunc, Func valueFunc) + where T : IList> => Add(attributes, attributeNameFunc, valueFunc(GetSemanticConventionVersion())); + + private static T Add(this T attributes, Func attributeNameFunc, object? value, bool addIfNull = false) where T : IList> { - var attributeName = attributeNameFunc(SemanticConventionVersion); + var semanticConventionVersionImpl = GetSemanticConventionVersion(); + + var attributeName = attributeNameFunc(semanticConventionVersionImpl); // if attributeName is empty or there is no value, exit if (string.IsNullOrEmpty(attributeName) || @@ -453,21 +273,25 @@ private static T Add(this T attributes, Func attributeNameFunc, return attributes; } - private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, Func valueFunc) => - SetTag(activity, attributeNameFunc, valueFunc(SemanticConventionVersion)); + private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, Func valueFunc) => + SetTag(activity, attributeNameFunc, valueFunc(GetSemanticConventionVersion())); - private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, object? value) + private static Activity? SetTag(this Activity? activity, Func attributeNameFunc, object? value) { - var attributeName = attributeNameFunc(SemanticConventionVersion); + var semanticConventionVersionImpl = GetSemanticConventionVersion(); + + var attributeName = attributeNameFunc(semanticConventionVersionImpl); activity?.SetTag(attributeName, value); return activity; } - private static IDictionary AddDic(IDictionary dict, Func attributeNameFunc, string value) + private static IDictionary AddDic(IDictionary dict, Func attributeNameFunc, string value) { - var attributeName = attributeNameFunc(SemanticConventionVersion); + var semanticConventionVersionImpl = GetSemanticConventionVersion(); + + var attributeName = attributeNameFunc(semanticConventionVersionImpl); if (!string.IsNullOrEmpty(attributeName)) { @@ -476,5 +300,23 @@ private static IDictionary AddDic(IDictionary di return dict; } + + private static AWSSemanticConventionsBase GetSemanticConventionVersion() + { + switch (SemanticConventionVersion) + { + case SemanticConventionVersion.Latest: + case SemanticConventionVersion.v1_10_1_Experimental: + return new AWSSemanticConventions_v1_10_1(); + + case SemanticConventionVersion.v1_10_Experimental: + return new AWSSemanticConventions_v1_10(); + + default: + throw new InvalidEnumArgumentException( + argumentName: nameof(SemanticConventionVersion), + (int)SemanticConventionVersion, + typeof(SemanticConventionVersion)); + } + } } - */ diff --git a/src/Shared/AWS/AWSSemanticConventions.Alt.v1.10.cs b/src/Shared/AWS/AWSSemanticConventions.v1.10.cs similarity index 100% rename from src/Shared/AWS/AWSSemanticConventions.Alt.v1.10.cs rename to src/Shared/AWS/AWSSemanticConventions.v1.10.cs diff --git a/src/Shared/AWS/AWSSemanticConventions.Alt.v1.10_1.cs b/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs similarity index 100% rename from src/Shared/AWS/AWSSemanticConventions.Alt.v1.10_1.cs rename to src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs From 928f4f1d525b31e32eb9580e3ee595c31da9ef59 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Thu, 5 Dec 2024 15:43:46 -0800 Subject: [PATCH 07/35] move the upgrade of AttributeHttpTarget to a new PR as this will require some additional changes in the Instrumentation.AWSLambda project to accomidate using url.path and url.query instead. --- src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs b/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs index a2cf1fc001..c0e6156fc9 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs @@ -25,7 +25,7 @@ private class AWSSemanticConventions_v1_10_1 : AWSSemanticConventions_v1_10 // HTTP Attributes public override string AttributeHttpStatusCode => this.AttributeHttpResponseStatusCode; public override string AttributeHttpScheme => this.AttributeUrlScheme; - public override string AttributeHttpTarget => string.Empty; // value no longer written + //public override string AttributeHttpTarget => string.Empty; // value no longer written ---- move to new PR public override string AttributeHttpMethod => this.AttributeHttpRequestMethod; public override string AttributeHttpResponseStatusCode => "http.response.status_code"; public override string AttributeHttpRequestMethod => "http.request.method"; From b52cbc5a08d25f6ae1886eef49f4a31ede5d25f2 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Thu, 5 Dec 2024 15:42:12 -0800 Subject: [PATCH 08/35] add new unit tests for SemanticConventionVersion switching --- .../AWSLambdaInstrumentationOptionsTests.cs | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs new file mode 100644 index 0000000000..7f53ba59cf --- /dev/null +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs @@ -0,0 +1,110 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Amazon.Lambda.APIGatewayEvents; +using OpenTelemetry.AWS; +using OpenTelemetry.Instrumentation.AWSLambda.Implementation; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.Instrumentation.AWSLambda.Tests.Implementation; + +/// +/// Tests for AWS Semantic Conversion via +/// . +/// These tests verify that the switching mechanism works rather than explicitly verifying what the +/// semantic convention should be. +/// +#if NET9_0 +[Collection("Sequential-.NET9")] +#else +[Collection("Sequential-.NET8")] +#endif +public class AWSLambdaInstrumentationOptionsTests :IDisposable +{ + [Fact] + public void CanUseSemanticConvention1_10() + { + var semanticVersion = SemanticConventionVersion.v1_10_Experimental; + + var expectedTags = new List + { + "http.scheme", + "http.target", + "net.host.name", + "net.host.port", + "http.method", + }; + + this.CheckHttpTags(semanticVersion, expectedTags); + } + + [Fact] + public void CanUseSemanticConvention1_10_1() + { + var semanticVersion = SemanticConventionVersion.v1_10_1_Experimental; + + var expectedTags = new List + { + "url.scheme", + "http.target", + "server.address", + "server.port", + "http.request.method", + }; + + this.CheckHttpTags(semanticVersion, expectedTags); + } + + private void CheckHttpTags(SemanticConventionVersion version, List expectedTags) + { + var request = new APIGatewayProxyRequest + { + MultiValueHeaders = new Dictionary> + { + { "X-Forwarded-Proto", new List { "https" } }, + { "Host", new List { "localhost:1234" } }, + }, + RequestContext = new APIGatewayProxyRequest.ProxyRequestContext + { + HttpMethod = "GET", + Path = "/path/test", + }, + }; + + using var _ = + Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations(c => + c.SemanticConventionVersion = version + ) + .Build(); + + var actualTags = AWSLambdaHttpUtils.GetHttpTags(request); + + this.AssertContainsTags(expectedTags, actualTags); + } + + private void AssertContainsTags(List expectedTags, IEnumerable>? actualTags) + where TActualValue : class + { + Assert.NotNull(actualTags); + + var keys = actualTags.Select(x => x.Key).ToList(); + + foreach (var tag in expectedTags) + { + Assert.Contains(tag, keys); + } + } + + public void Dispose() + { + // Semantic Convention is saved statically - and needs to be reset to + // Latest following these tests. + Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations(c => + c.SemanticConventionVersion = SemanticConventionVersion.Latest + ) + .Build(); + } +} From 749f5dd0886c016c9c6d51f31e56f5fa996a510f Mon Sep 17 00:00:00 2001 From: philip pittle Date: Thu, 5 Dec 2024 15:41:38 -0800 Subject: [PATCH 09/35] update AWS Lambda tests to use Semantic Convention 1.29 --- .../Implementation/AWSLambdaHttpUtilsTests.cs | 84 +++++++++++-------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs index 06a0e1dbbe..461f29e4f7 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs @@ -13,6 +13,16 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Tests.Implementation; [Collection("TracerProviderDependent")] public class AWSLambdaHttpUtilsTests { + private static class ExpectedSemanticConventions + { + public const string AttributeHttpScheme = "url.scheme"; + public const string AttributeHttpTarget = "http.target"; + public const string AttributeNetHostName = "server.address"; + public const string AttributeNetHostPort = "server.port"; + public const string AttributeHttpMethod = "http.request.method"; + public const string AttributeHttpStatusCode = "http.response.status_code"; + } + [Fact] public void GetHttpTags_APIGatewayProxyRequest_ReturnsCorrectTags() { @@ -40,11 +50,11 @@ public void GetHttpTags_APIGatewayProxyRequest_ReturnsCorrectTags() var expectedTags = new Dictionary { - { "http.scheme", "https" }, - { "http.target", "/path/test?q1=value1" }, - { "net.host.name", "localhost" }, - { "net.host.port", 1234 }, - { "http.method", "GET" }, + { ExpectedSemanticConventions.AttributeHttpScheme, "https" }, + { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeNetHostName, "localhost" }, + { ExpectedSemanticConventions.AttributeNetHostPort, 1234 }, + { ExpectedSemanticConventions.AttributeHttpMethod, "GET" }, }; AssertTags(expectedTags, actualTags); @@ -72,11 +82,11 @@ public void GetHttpTags_ApplicationLoadBalancerRequest_ReturnsCorrectTags() var expectedTags = new Dictionary { - { "http.scheme", "https" }, - { "http.target", "/path/test?q1=value1" }, - { "net.host.name", "localhost" }, - { "net.host.port", 1234 }, - { "http.method", "GET" }, + { ExpectedSemanticConventions.AttributeHttpScheme, "https" }, + { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeNetHostName, "localhost" }, + { ExpectedSemanticConventions.AttributeNetHostPort, 1234 }, + { ExpectedSemanticConventions.AttributeHttpMethod, "GET" }, }; AssertTags(expectedTags, actualTags); @@ -106,11 +116,11 @@ public void GetHttpTags_ApplicationLoadBalancerRequestWithMultiValue_ReturnsCorr var expectedTags = new Dictionary { - { "http.scheme", "https" }, - { "http.target", "/path/test?q1=value1" }, - { "net.host.name", "localhost" }, - { "net.host.port", 1234 }, - { "http.method", "GET" }, + { ExpectedSemanticConventions.AttributeHttpScheme, "https" }, + { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeNetHostName, "localhost" }, + { ExpectedSemanticConventions.AttributeNetHostPort, 1234 }, + { ExpectedSemanticConventions.AttributeHttpMethod, "GET" }, }; AssertTags(expectedTags, actualTags); @@ -132,10 +142,10 @@ public void GetHttpTags_ApplicationLoadBalancerRequestWithMultiValueHeader_UsesL var expectedTags = new Dictionary { - { "http.target", string.Empty }, - { "http.scheme", "http" }, - { "net.host.name", "myhost" }, - { "net.host.port", 432 }, + { ExpectedSemanticConventions.AttributeHttpTarget, string.Empty }, + { ExpectedSemanticConventions.AttributeHttpScheme, "http" }, + { ExpectedSemanticConventions.AttributeNetHostName, "myhost" }, + { ExpectedSemanticConventions.AttributeNetHostPort, 432 }, }; AssertTags(expectedTags, actualTags); @@ -160,7 +170,7 @@ public void SetHttpTagsFromResult_ApplicationLoadBalancerResponse_SetsCorrectTag var expectedTags = new Dictionary { - { "http.status_code", 200 }, + { ExpectedSemanticConventions.AttributeHttpStatusCode, 200 }, }; var actualTags = activity?.TagObjects @@ -237,8 +247,8 @@ public void GetHttpTags_APIGatewayProxyRequestWithEmptyContext_ReturnsTagsFromRe var expectedTags = new Dictionary { - { "http.method", "POST" }, - { "http.target", "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeHttpMethod, "POST" }, + { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, }; AssertTags(expectedTags, actualTags); @@ -260,10 +270,10 @@ public void GetHttpTags_APIGatewayProxyRequestWithMultiValueHeader_UsesLastValue var expectedTags = new Dictionary { - { "http.target", string.Empty }, - { "http.scheme", "http" }, - { "net.host.name", "myhost" }, - { "net.host.port", 432 }, + { ExpectedSemanticConventions.AttributeHttpTarget, string.Empty }, + { ExpectedSemanticConventions.AttributeHttpScheme, "http" }, + { ExpectedSemanticConventions.AttributeNetHostName, "myhost" }, + { ExpectedSemanticConventions.AttributeNetHostPort, 432 }, }; AssertTags(expectedTags, actualTags); @@ -294,11 +304,11 @@ public void GetHttpTags_APIGatewayHttpApiV2ProxyRequest_ReturnsCorrectTags() var expectedTags = new Dictionary { - { "http.scheme", "https" }, - { "http.target", "/path/test?q1=value1" }, - { "net.host.name", "localhost" }, - { "net.host.port", 1234 }, - { "http.method", "GET" }, + { ExpectedSemanticConventions.AttributeHttpScheme, "https" }, + { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeNetHostName, "localhost" }, + { ExpectedSemanticConventions.AttributeNetHostPort, 1234 }, + { ExpectedSemanticConventions.AttributeHttpMethod, "GET" }, }; AssertTags(expectedTags, actualTags); @@ -320,10 +330,10 @@ public void GetHttpTags_APIGatewayHttpApiV2ProxyRequestWithMultiValueHeader_Uses var expectedTags = new Dictionary { - { "http.target", string.Empty }, - { "http.scheme", "http" }, - { "net.host.name", "myhost" }, - { "net.host.port", 432 }, + { ExpectedSemanticConventions.AttributeHttpTarget, string.Empty }, + { ExpectedSemanticConventions.AttributeHttpScheme, "http" }, + { ExpectedSemanticConventions.AttributeNetHostName, "myhost" }, + { ExpectedSemanticConventions.AttributeNetHostPort, 432 }, }; AssertTags(expectedTags, actualTags); @@ -348,7 +358,7 @@ public void SetHttpTagsFromResult_APIGatewayProxyResponse_SetsCorrectTags() var expectedTags = new Dictionary { - { "http.status_code", 200 }, + { ExpectedSemanticConventions.AttributeHttpStatusCode, 200 }, }; Assert.NotNull(activity); @@ -377,7 +387,7 @@ public void SetHttpTagsFromResult_APIGatewayHttpApiV2ProxyResponse_SetsCorrectTa var expectedTags = new Dictionary { - { "http.status_code", 200 }, + { ExpectedSemanticConventions.AttributeHttpStatusCode, 200 }, }; var actualTags = activity?.TagObjects From 0c091f286a42c3589b529cf4fd886bfd33e1e31b Mon Sep 17 00:00:00 2001 From: philip pittle Date: Thu, 5 Dec 2024 20:00:11 -0800 Subject: [PATCH 10/35] remove obsolete code --- .../Implementation/CommonExtensions.cs | 8 ----- .../Implementation/CommonExtensionsTests.cs | 33 ------------------- 2 files changed, 41 deletions(-) delete mode 100644 test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/CommonExtensionsTests.cs diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/CommonExtensions.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/CommonExtensions.cs index 20811a0e65..458323f57d 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/CommonExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/CommonExtensions.cs @@ -5,14 +5,6 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation; internal static class CommonExtensions { - internal static void AddTagIfNotNull(this List> tags, string tagName, object? tagValue) - { - if (tagValue != null) - { - tags.Add(new(tagName, tagValue)); - } - } - internal static T? GetValueByKeyIgnoringCase(this IDictionary dict, string key) { // TODO: there may be opportunities for performance improvements of this method. diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/CommonExtensionsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/CommonExtensionsTests.cs deleted file mode 100644 index cd14e91e71..0000000000 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/CommonExtensionsTests.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -using OpenTelemetry.Instrumentation.AWSLambda.Implementation; -using Xunit; - -namespace OpenTelemetry.Instrumentation.AWSLambda.Tests.Implementation; - -public class CommonExtensionsTests -{ - [Theory] - [InlineData("test")] - [InlineData(443)] - [InlineData(null)] - public void AddTagIfNotNull_Tag_CorrectTagsList(object? tag) - { - var tags = new List>(); - - tags.AddTagIfNotNull("tagName", tag); - - if (tag != null) - { - Assert.Single(tags); - var actualTag = tags.First(); - Assert.Equal("tagName", actualTag.Key); - Assert.Equal(tag, actualTag.Value); - } - else - { - Assert.Empty(tags); - } - } -} From 5204ab7eb9259eb652e6f9ce04c341be95b2bbf6 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Thu, 5 Dec 2024 20:02:15 -0800 Subject: [PATCH 11/35] Update SetTag to be a no-op if attribute name is null or empty --- src/Shared/AWS/AWSSemanticConventions.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index 9a2ce973b3..1d6a245f77 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -282,6 +282,12 @@ private static T Add(this T attributes, Func Date: Thu, 5 Dec 2024 20:14:02 -0800 Subject: [PATCH 12/35] Update documentation and add documentation to README files --- .../README.md | 42 +++++++++++++++++++ .../README.md | 35 ++++++++++++++++ src/OpenTelemetry.Resources.AWS/README.md | 40 ++++++++++++++++++ src/Shared/AWS/SemanticConventionVersion.cs | 4 +- 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AWS/README.md b/src/OpenTelemetry.Instrumentation.AWS/README.md index 27917e6dd3..8ab85cb3a7 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/README.md +++ b/src/OpenTelemetry.Instrumentation.AWS/README.md @@ -33,3 +33,45 @@ public void ConfigureServices(IServiceCollection services) .AddOtlpExporter()); } ``` + +## Semantic Conventions + +_For an overview on Semantic Conventions, see +https://opentelemetry.io/docs/concepts/semantic-conventions/_. + +While this library is intended for production use, it relies on several +Semantic Conventions that are still considered Experimental, meaning +they may undergo additional changes before becoming Stable. This can impact +the aggregation and analysis of telemetry signals in environments with +multiple applications or microservices. + +For example, a microservice using an older version of the Semantic Conventions +for Http Attributes may emit `"http.method"` with a value of GET, while a +different microservice, using a new version of Semantic Convention may instead +emit the GET as `"http.request.method"`. + +Future versions the OpenTelemetry.*.AWS libraries will include updates to the +Semantic Convention, which may break compatibility with a previous version. + +To opt-out of automatic upgrades, you can pin to a specific version: + +```csharp +using OpenTelemetry; +using OpenTelemetry.AWS; +using OpenTelemetry.Contrib.Extensions.AWSXRay.Trace; +using OpenTelemetry.Trace; + +public void ConfigureServices(IServiceCollection services) +{ + services.AddControllers(); + services.AddOpenTelemetryTracing((builder) => builder + .AddAWSInstrumentation(opt => { + // pin to a specific Semantic Convention version + opt.SemanticConventionVersion = SemanticConventionVersion.v1_10_EXPERIMENTAL; + }); +} +``` + +__NOTE:__ Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS +libraries will remain on that version until the +next major version bump. diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/README.md b/src/OpenTelemetry.Instrumentation.AWSLambda/README.md index ad7828d792..81f26a7cdf 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/README.md +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/README.md @@ -140,6 +140,41 @@ public class Function } ``` +## Semantic Conventions + +_For an overview on Semantic Conventions, see +https://opentelemetry.io/docs/concepts/semantic-conventions/_. + +While this library is intended for production use, it relies on several +Semantic Conventions that are still considered Experimental, meaning +they may undergo additional changes before becoming Stable. This can impact +the aggregation and analysis of telemetry signals in environments with +multiple applications or microservices. + +For example, a microservice using an older version of the Semantic Conventions +for Http Attributes may emit `"http.method"` with a value of GET, while a +different microservice, using a new version of Semantic Convention may instead +emit the GET as `"http.request.method"`. + +Future versions the OpenTelemetry.*.AWS libraries will include updates to the +Semantic Convention, which may break compatibility with a previous version. + +To opt-out of automatic upgrades, you can pin to a specific version: + +```csharp + using (var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations(opt => + { + // pin to a specific Semantic Convention version + opt.SemanticConventionVersion = SemanticConventionVersion.v1_10_EXPERIMENTAL; + }) + .Build()!); +``` + +__NOTE:__ Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS +libraries will remain on that version until the +next major version bump. + ## Reference * [OpenTelemetry Project](https://opentelemetry.io/) diff --git a/src/OpenTelemetry.Resources.AWS/README.md b/src/OpenTelemetry.Resources.AWS/README.md index ef528ea2f7..689916eaa7 100644 --- a/src/OpenTelemetry.Resources.AWS/README.md +++ b/src/OpenTelemetry.Resources.AWS/README.md @@ -64,6 +64,46 @@ log group ids, log stream names, log stream ids. - **AWSEKSDetector**: cloud provider, cloud platform, cluster name, container id. +## Semantic Conventions + +_For an overview on Semantic Conventions, see +https://opentelemetry.io/docs/concepts/semantic-conventions/_. + +While this library is intended for production use, it relies on several +Semantic Conventions that are still considered Experimental, meaning +they may undergo additional changes before becoming Stable. This can impact +the aggregation and analysis of telemetry signals in environments with +multiple applications or microservices. + +For example, a microservice using an older version of the Semantic Conventions +for Http Attributes may emit `"http.method"` with a value of GET, while a +different microservice, using a new version of Semantic Convention may instead +emit the GET as `"http.request.method"`. + +Future versions the OpenTelemetry.*.AWS libraries will include updates to the +Semantic Convention, which may break compatibility with a previous version. + +To opt-out of automatic upgrades, you can pin to a specific version: + +```csharp +using OpenTelemetry; +using OpenTelemetry.Resources; + +using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .ConfigureResource(resource => resource.AddAWSEC2Detector( + opt => { + // pin to a specific Semantic Convention version + opt.SemanticConventionVersion = SemanticConventionVersion.v1_10_EXPERIMENTAL; + } + )) + // other configurations + .Build(); +``` + +__NOTE:__ Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS +libraries will remain on that version until the +next major version bump. + ## References - [OpenTelemetry Project](https://opentelemetry.io/) diff --git a/src/Shared/AWS/SemanticConventionVersion.cs b/src/Shared/AWS/SemanticConventionVersion.cs index f67d6b6dbf..b521738d79 100644 --- a/src/Shared/AWS/SemanticConventionVersion.cs +++ b/src/Shared/AWS/SemanticConventionVersion.cs @@ -13,7 +13,7 @@ namespace OpenTelemetry.AWS; /// still considered Experimental, meaning they may undergo additional changes before becoming Stable. This can /// impact the aggregation and analysis of telemetry signals in environments with multiple applications or microservices. /// For example, a microservice using an older version of the Semantic Conventions for Http Attributes may emit -/// "http.method" with a value of GET,while a different microservice, using a new version of Semantic Convention may instead emit the GET as +/// "http.method" with a value of GET, while a different microservice, using a new version of Semantic Convention may instead emit the GET as /// "http.request.method". /// /// @@ -26,7 +26,7 @@ namespace OpenTelemetry.AWS; /// { /// opt.SemanticConventionVersion = SemanticConventionVersion.v1_10_EXPERIMENTAL; /// }) -/// .Build()!) +/// .Build()!); /// ]]> /// /// From db38b54590ad4ebf3386b1e53299a052520890cd Mon Sep 17 00:00:00 2001 From: philip pittle Date: Thu, 5 Dec 2024 20:44:50 -0800 Subject: [PATCH 13/35] run dotnet format --- .../.publicApi/PublicAPI.Unshipped.txt | 5 +++ .../AWSTracingPipelineHandler.cs | 1 - .../README.md | 4 +- .../.publicApi/PublicAPI.Unshipped.txt | 5 +++ .../AWSLambdaInstrumentationOptions.cs | 2 +- .../Implementation/AWSLambdaHttpUtils.cs | 1 - .../Implementation/AWSLambdaUtils.cs | 2 +- .../README.md | 13 ++++--- .../.publicApi/PublicAPI.Unshipped.txt | 13 ++++++- .../.publicApi/net8.0/PublicAPI.Unshipped.txt | 4 +- .../AWSECSDetector.cs | 1 - .../AWSResourceBuilderExtensions.cs | 4 ++ src/OpenTelemetry.Resources.AWS/README.md | 4 +- src/Shared/AWS/AWSSemanticConventions.Base.cs | 5 ++- src/Shared/AWS/AWSSemanticConventions.cs | 7 ++-- .../AWS/AWSSemanticConventions.v1.10.cs | 3 ++ .../AWS/AWSSemanticConventions.v1.10_1.cs | 4 ++ src/Shared/AWS/SemanticConventionVersion.cs | 3 ++ .../AWSLambdaWrapperTests.cs | 26 ++++++------- .../Implementation/AWSLambdaHttpUtilsTests.cs | 20 +++++----- .../AWSLambdaInstrumentationOptionsTests.cs | 28 +++++++------- .../AWSEBSDetectorTests.cs | 20 +++++----- .../AWSEC2DetectorTests.cs | 24 ++++++------ .../AWSECSDetectorTests.cs | 38 +++++++++---------- .../AWSEKSDetectorTests.cs | 16 ++++---- 25 files changed, 142 insertions(+), 111 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt index e89899177b..c215e54797 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt @@ -1,7 +1,12 @@ #nullable enable OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.Latest = 0 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_10_1_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_10_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.AWSClientInstrumentationOptions() -> void +OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SemanticConventionVersion.get -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SemanticConventionVersion.set -> void OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SuppressDownstreamInstrumentation.get -> bool OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SuppressDownstreamInstrumentation.set -> void OpenTelemetry.Trace.TracerProviderBuilderExtensions diff --git a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs b/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs index 6497c569e9..4a95f2768a 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs +++ b/src/OpenTelemetry.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs @@ -7,7 +7,6 @@ using Amazon.Runtime.Telemetry; using OpenTelemetry.AWS; using OpenTelemetry.Context.Propagation; -using OpenTelemetry.Trace; namespace OpenTelemetry.Instrumentation.AWS.Implementation; diff --git a/src/OpenTelemetry.Instrumentation.AWS/README.md b/src/OpenTelemetry.Instrumentation.AWS/README.md index 8ab85cb3a7..31b55630e8 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/README.md +++ b/src/OpenTelemetry.Instrumentation.AWS/README.md @@ -37,7 +37,7 @@ public void ConfigureServices(IServiceCollection services) ## Semantic Conventions _For an overview on Semantic Conventions, see -https://opentelemetry.io/docs/concepts/semantic-conventions/_. +[Open Telemetery - Semantic Conventions](https://opentelemetry.io/docs/concepts/semantic-conventions/)_. While this library is intended for production use, it relies on several Semantic Conventions that are still considered Experimental, meaning @@ -72,6 +72,6 @@ public void ConfigureServices(IServiceCollection services) } ``` -__NOTE:__ Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS +**NOTE:** Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS libraries will remain on that version until the next major version bump. diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt index c15767dc98..aa2cbd314b 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt @@ -1,11 +1,16 @@ #nullable enable OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.Latest = 0 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_10_1_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_10_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.AWSLambdaInstrumentationOptions() -> void OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.DisableAwsXRayContextExtraction.get -> bool OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.DisableAwsXRayContextExtraction.set -> void OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.SetParentFromBatch.get -> bool OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.SetParentFromBatch.set -> void +OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.SemanticConventionVersion.get -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.SemanticConventionVersion.set -> void OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaWrapper OpenTelemetry.Instrumentation.AWSLambda.TracerProviderBuilderExtensions static OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaWrapper.Trace(OpenTelemetry.Trace.TracerProvider? tracerProvider, System.Func! lambdaHandler, TInput input, Amazon.Lambda.Core.ILambdaContext! context, System.Diagnostics.ActivityContext parentContext = default(System.Diagnostics.ActivityContext)) -> TResult diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs index 457175d389..3080d90335 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/AWSLambdaInstrumentationOptions.cs @@ -24,6 +24,6 @@ public class AWSLambdaInstrumentationOptions /// public bool SetParentFromBatch { get; set; } - /// + /// public SemanticConventionVersion SemanticConventionVersion { get; set; } = AWSSemanticConventions.DefaultSemanticConventionVersion; } diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs index 1d9a73f7ac..ba554d06e3 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs @@ -7,7 +7,6 @@ using Amazon.Lambda.APIGatewayEvents; using Amazon.Lambda.ApplicationLoadBalancerEvents; using OpenTelemetry.AWS; -using OpenTelemetry.Internal; namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation; diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs index 31aabeb321..a772c5f761 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaUtils.cs @@ -156,7 +156,7 @@ internal static IEnumerable> GetFunctionTags::function: - var items = functionArn.Split(':'); + var items = functionArn!.Split(':'); return items.Length >= 5 ? items[4] : null; } diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/README.md b/src/OpenTelemetry.Instrumentation.AWSLambda/README.md index 81f26a7cdf..055beaa741 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/README.md +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/README.md @@ -143,7 +143,7 @@ public class Function ## Semantic Conventions _For an overview on Semantic Conventions, see -https://opentelemetry.io/docs/concepts/semantic-conventions/_. +[Open Telemetery - Semantic Conventions](https://opentelemetry.io/docs/concepts/semantic-conventions/)_. While this library is intended for production use, it relies on several Semantic Conventions that are still considered Experimental, meaning @@ -156,8 +156,9 @@ for Http Attributes may emit `"http.method"` with a value of GET, while a different microservice, using a new version of Semantic Convention may instead emit the GET as `"http.request.method"`. -Future versions the OpenTelemetry.*.AWS libraries will include updates to the -Semantic Convention, which may break compatibility with a previous version. +Future versions of OpenTelemetry.Instrumentation.AWSLambda library will include +updates to the Semantic Convention, which may break compatibility with a +previous version. To opt-out of automatic upgrades, you can pin to a specific version: @@ -171,9 +172,9 @@ To opt-out of automatic upgrades, you can pin to a specific version: .Build()!); ``` -__NOTE:__ Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS -libraries will remain on that version until the -next major version bump. +**NOTE:** Once a Semantic Convention becomes Stable, +OpenTelemetry.Instrumentation.AWSLambda will remain on that version until +the next major version bump. ## Reference diff --git a/src/OpenTelemetry.Resources.AWS/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Resources.AWS/.publicApi/PublicAPI.Unshipped.txt index a6dd3ce0c5..abbd25c43d 100644 --- a/src/OpenTelemetry.Resources.AWS/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Resources.AWS/.publicApi/PublicAPI.Unshipped.txt @@ -1,3 +1,12 @@ +OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.Latest = 0 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_10_1_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_10_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.Resources.AWS.AWSResourceBuilderOptions +OpenTelemetry.Resources.AWS.AWSResourceBuilderOptions.AWSResourceBuilderOptions() -> void +OpenTelemetry.Resources.AWS.AWSResourceBuilderOptions.SemanticConventionVersion.get -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.Resources.AWS.AWSResourceBuilderOptions.SemanticConventionVersion.set -> void OpenTelemetry.Resources.AWSResourceBuilderExtensions -static OpenTelemetry.Resources.AWSResourceBuilderExtensions.AddAWSEBSDetector(this OpenTelemetry.Resources.ResourceBuilder! builder) -> OpenTelemetry.Resources.ResourceBuilder! -static OpenTelemetry.Resources.AWSResourceBuilderExtensions.AddAWSEC2Detector(this OpenTelemetry.Resources.ResourceBuilder! builder) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.AWSResourceBuilderExtensions.AddAWSEBSDetector(this OpenTelemetry.Resources.ResourceBuilder! builder, System.Action? configure = null) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.AWSResourceBuilderExtensions.AddAWSEC2Detector(this OpenTelemetry.Resources.ResourceBuilder! builder, System.Action? configure = null) -> OpenTelemetry.Resources.ResourceBuilder! + diff --git a/src/OpenTelemetry.Resources.AWS/.publicApi/net8.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Resources.AWS/.publicApi/net8.0/PublicAPI.Unshipped.txt index dd8d0109c1..1eb23ec46e 100644 --- a/src/OpenTelemetry.Resources.AWS/.publicApi/net8.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Resources.AWS/.publicApi/net8.0/PublicAPI.Unshipped.txt @@ -1,2 +1,2 @@ -static OpenTelemetry.Resources.AWSResourceBuilderExtensions.AddAWSECSDetector(this OpenTelemetry.Resources.ResourceBuilder! builder) -> OpenTelemetry.Resources.ResourceBuilder! -static OpenTelemetry.Resources.AWSResourceBuilderExtensions.AddAWSEKSDetector(this OpenTelemetry.Resources.ResourceBuilder! builder) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.AWSResourceBuilderExtensions.AddAWSECSDetector(this OpenTelemetry.Resources.ResourceBuilder! builder, System.Action? configure = null) -> OpenTelemetry.Resources.ResourceBuilder! +static OpenTelemetry.Resources.AWSResourceBuilderExtensions.AddAWSEKSDetector(this OpenTelemetry.Resources.ResourceBuilder! builder, System.Action? configure = null) -> OpenTelemetry.Resources.ResourceBuilder! diff --git a/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs b/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs index 15869ad232..04d546fba2 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSECSDetector.cs @@ -5,7 +5,6 @@ using System.Text.Json; using System.Text.RegularExpressions; using OpenTelemetry.AWS; -using OpenTelemetry.SemanticConventions; namespace OpenTelemetry.Resources.AWS; diff --git a/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderExtensions.cs b/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderExtensions.cs index 30bb40319a..d671ab9892 100644 --- a/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderExtensions.cs +++ b/src/OpenTelemetry.Resources.AWS/AWSResourceBuilderExtensions.cs @@ -16,6 +16,7 @@ public static class AWSResourceBuilderExtensions /// Enables AWS Elastic Beanstalk resource detector. /// /// The being configured. + /// Optional callback action for configuring . /// The instance of being configured. public static ResourceBuilder AddAWSEBSDetector(this ResourceBuilder builder, Action? configure = null) { @@ -33,6 +34,7 @@ public static ResourceBuilder AddAWSEBSDetector(this ResourceBuilder builder, Ac /// Enables AWS EC2 resource detector. /// /// The being configured. + /// Optional callback action for configuring . /// The instance of being configured. public static ResourceBuilder AddAWSEC2Detector(this ResourceBuilder builder, Action? configure = null) { @@ -51,6 +53,7 @@ public static ResourceBuilder AddAWSEC2Detector(this ResourceBuilder builder, Ac /// Enables AWS ECS resource detector. /// /// The being configured. + /// Optional callback action for configuring . /// The instance of being configured. public static ResourceBuilder AddAWSECSDetector(this ResourceBuilder builder, Action? configure = null) { @@ -68,6 +71,7 @@ public static ResourceBuilder AddAWSECSDetector(this ResourceBuilder builder, Ac /// Enables AWS EKS resource detector. /// /// The being configured. + /// Optional callback action for configuring . /// The instance of being configured. public static ResourceBuilder AddAWSEKSDetector(this ResourceBuilder builder, Action? configure = null) { diff --git a/src/OpenTelemetry.Resources.AWS/README.md b/src/OpenTelemetry.Resources.AWS/README.md index 689916eaa7..0fa8038f71 100644 --- a/src/OpenTelemetry.Resources.AWS/README.md +++ b/src/OpenTelemetry.Resources.AWS/README.md @@ -67,7 +67,7 @@ container id. ## Semantic Conventions _For an overview on Semantic Conventions, see -https://opentelemetry.io/docs/concepts/semantic-conventions/_. +[Open Telemetery - Semantic Conventions](https://opentelemetry.io/docs/concepts/semantic-conventions/)_. While this library is intended for production use, it relies on several Semantic Conventions that are still considered Experimental, meaning @@ -100,7 +100,7 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder() .Build(); ``` -__NOTE:__ Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS +**NOTE:** Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS libraries will remain on that version until the next major version bump. diff --git a/src/Shared/AWS/AWSSemanticConventions.Base.cs b/src/Shared/AWS/AWSSemanticConventions.Base.cs index d4aa76d586..370a96ac84 100644 --- a/src/Shared/AWS/AWSSemanticConventions.Base.cs +++ b/src/Shared/AWS/AWSSemanticConventions.Base.cs @@ -1,7 +1,8 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 using OpenTelemetry.SemanticConventions; - namespace OpenTelemetry.AWS; // disable Style Warnings to improve readability of this specific file. @@ -21,7 +22,7 @@ internal static partial class AWSSemanticConventions /// to use it. This helps ensure the attribute doesn't get used if the user has specified /// a specific . /// - /// See for details. + /// See for details. /// private abstract class AWSSemanticConventionsBase { diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index 1d6a245f77..bf38f5a35a 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -14,11 +14,12 @@ namespace OpenTelemetry.AWS; /// -/// Abstracts the complexities of honoring . +/// Abstracts the complexities of honoring . /// /// Classes emitting attributes can use the extension methods in this class to build -/// a List of s containing Attribute Name and Value without -/// needing to know which version of the Semantic Convention to use. +/// a List of s containing +/// Attribute Name and Value without needing to know which version of the +/// Semantic Convention to use. /// /// Below is a hypothetical example showing how attributes can be constructed. It is not necessary /// for this consumer to accommodate differing behavior based on , diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.10.cs b/src/Shared/AWS/AWSSemanticConventions.v1.10.cs index 8bd6afcae4..b3d6e06e5a 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.10.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.10.cs @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + namespace OpenTelemetry.AWS; // disable Style Warnings to improve readability of this specific file. diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs b/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs index c0e6156fc9..5701617f8b 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + namespace OpenTelemetry.AWS; // disable Style Warnings to improve readability of this specific file. @@ -25,6 +28,7 @@ private class AWSSemanticConventions_v1_10_1 : AWSSemanticConventions_v1_10 // HTTP Attributes public override string AttributeHttpStatusCode => this.AttributeHttpResponseStatusCode; public override string AttributeHttpScheme => this.AttributeUrlScheme; + //public override string AttributeHttpTarget => string.Empty; // value no longer written ---- move to new PR public override string AttributeHttpMethod => this.AttributeHttpRequestMethod; public override string AttributeHttpResponseStatusCode => "http.response.status_code"; diff --git a/src/Shared/AWS/SemanticConventionVersion.cs b/src/Shared/AWS/SemanticConventionVersion.cs index b521738d79..6d2706fefc 100644 --- a/src/Shared/AWS/SemanticConventionVersion.cs +++ b/src/Shared/AWS/SemanticConventionVersion.cs @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + namespace OpenTelemetry.AWS; #pragma warning disable SA1300 diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index 61f7469064..b95359b96b 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -15,19 +15,6 @@ public class AWSLambdaWrapperTests private const string XRayParentId = "53995c3f42cd8ad8"; private const string CustomParentId = "11195c3f42cd8222"; - private static class ExpectedSemanticConventions - { - public const string AttributeCloudProvider = "cloud.provider"; - public const string AttributeCloudAccountID = "cloud.account.id"; - public const string AttributeCloudRegion = "cloud.region"; - public const string AttributeFaasColdStart = "faas.coldstart"; - public const string AttributeFaasName = "faas.name"; - public const string AttributeFaasExecution = "faas.invocation_id"; - public const string AttributeFaasID = "cloud.resource_id"; - public const string AttributeFaasTrigger = "faas.trigger"; - public const string AttributeFaasVersion = "faas.version"; - } - private readonly SampleHandlers sampleHandlers; private readonly SampleLambdaContext sampleLambdaContext; @@ -297,4 +284,17 @@ private void AssertSpanException(Activity activity) Assert.Equal("exception", exception.Name); Assert.Equal("TestException", exception.Tags.SingleOrDefault(t => t.Key.Equals("exception.message")).Value); } + + private static class ExpectedSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudAccountID = "cloud.account.id"; + public const string AttributeCloudRegion = "cloud.region"; + public const string AttributeFaasColdStart = "faas.coldstart"; + public const string AttributeFaasName = "faas.name"; + public const string AttributeFaasExecution = "faas.invocation_id"; + public const string AttributeFaasID = "cloud.resource_id"; + public const string AttributeFaasTrigger = "faas.trigger"; + public const string AttributeFaasVersion = "faas.version"; + } } diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs index 461f29e4f7..102ef2fa40 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs @@ -13,16 +13,6 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Tests.Implementation; [Collection("TracerProviderDependent")] public class AWSLambdaHttpUtilsTests { - private static class ExpectedSemanticConventions - { - public const string AttributeHttpScheme = "url.scheme"; - public const string AttributeHttpTarget = "http.target"; - public const string AttributeNetHostName = "server.address"; - public const string AttributeNetHostPort = "server.port"; - public const string AttributeHttpMethod = "http.request.method"; - public const string AttributeHttpStatusCode = "http.response.status_code"; - } - [Fact] public void GetHttpTags_APIGatewayProxyRequest_ReturnsCorrectTags() { @@ -464,4 +454,14 @@ private static void AssertTags(Dictionary expected Assert.Contains(new KeyValuePair(tag.Key, (TActualValue)tag.Value), actualTags); } } + + private static class ExpectedSemanticConventions + { + public const string AttributeHttpScheme = "url.scheme"; + public const string AttributeHttpTarget = "http.target"; + public const string AttributeNetHostName = "server.address"; + public const string AttributeNetHostPort = "server.port"; + public const string AttributeHttpMethod = "http.request.method"; + public const string AttributeHttpStatusCode = "http.response.status_code"; + } } diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs index 7f53ba59cf..244a9ee919 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs @@ -20,7 +20,7 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Tests.Implementation; #else [Collection("Sequential-.NET8")] #endif -public class AWSLambdaInstrumentationOptionsTests :IDisposable +public sealed class AWSLambdaInstrumentationOptionsTests : IDisposable { [Fact] public void CanUseSemanticConvention1_10() @@ -56,6 +56,16 @@ public void CanUseSemanticConvention1_10_1() this.CheckHttpTags(semanticVersion, expectedTags); } + public void Dispose() + { + // Semantic Convention is saved statically - and needs to be reset to + // Latest following these tests. + Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations(c => + c.SemanticConventionVersion = SemanticConventionVersion.Latest) + .Build(); + } + private void CheckHttpTags(SemanticConventionVersion version, List expectedTags) { var request = new APIGatewayProxyRequest @@ -72,11 +82,10 @@ private void CheckHttpTags(SemanticConventionVersion version, List expec }, }; - using var _ = + using var builder = Sdk.CreateTracerProviderBuilder() .AddAWSLambdaConfigurations(c => - c.SemanticConventionVersion = version - ) + c.SemanticConventionVersion = version) .Build(); var actualTags = AWSLambdaHttpUtils.GetHttpTags(request); @@ -96,15 +105,4 @@ private void AssertContainsTags(List expectedTags, IEnumer Assert.Contains(tag, keys); } } - - public void Dispose() - { - // Semantic Convention is saved statically - and needs to be reset to - // Latest following these tests. - Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations(c => - c.SemanticConventionVersion = SemanticConventionVersion.Latest - ) - .Build(); - } } diff --git a/test/OpenTelemetry.Resources.AWS.Tests/AWSEBSDetectorTests.cs b/test/OpenTelemetry.Resources.AWS.Tests/AWSEBSDetectorTests.cs index e510bf3327..14640bd613 100644 --- a/test/OpenTelemetry.Resources.AWS.Tests/AWSEBSDetectorTests.cs +++ b/test/OpenTelemetry.Resources.AWS.Tests/AWSEBSDetectorTests.cs @@ -9,16 +9,6 @@ public class AWSEBSDetectorTests { private const string AWSEBSMetadataFilePath = "SampleMetadataFiles/environment.conf"; - private static class AWSSemanticConventions - { - public const string AttributeCloudProvider = "cloud.provider"; - public const string AttributeCloudPlatform = "cloud.platform"; - public const string AttributeServiceName = "service.name"; - public const string AttributeServiceNamespace = "service.namespace"; - public const string AttributeServiceInstanceID = "service.instance.id"; - public const string AttributeServiceVersion = "service.version"; - } - [Fact] public void TestDetect() { @@ -50,4 +40,14 @@ public void TestGetEBSMetadata() Assert.Equal("Test AWS Elastic Beanstalk Environment Name", ebsMetadata.EnvironmentName); Assert.Equal("Test Version", ebsMetadata.VersionLabel); } + + private static class AWSSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudPlatform = "cloud.platform"; + public const string AttributeServiceName = "service.name"; + public const string AttributeServiceNamespace = "service.namespace"; + public const string AttributeServiceInstanceID = "service.instance.id"; + public const string AttributeServiceVersion = "service.version"; + } } diff --git a/test/OpenTelemetry.Resources.AWS.Tests/AWSEC2DetectorTests.cs b/test/OpenTelemetry.Resources.AWS.Tests/AWSEC2DetectorTests.cs index eedf4f8a23..279ec8d35d 100644 --- a/test/OpenTelemetry.Resources.AWS.Tests/AWSEC2DetectorTests.cs +++ b/test/OpenTelemetry.Resources.AWS.Tests/AWSEC2DetectorTests.cs @@ -7,18 +7,6 @@ namespace OpenTelemetry.Resources.AWS.Tests; public class AWSEC2DetectorTests { - private static class ExpectedSemanticConventions - { - public const string AttributeCloudProvider = "cloud.provider"; - public const string AttributeCloudPlatform = "cloud.platform"; - public const string AttributeCloudAccountID = "cloud.account.id"; - public const string AttributeCloudAvailabilityZone = "cloud.availability_zone"; - public const string AttributeCloudRegion = "cloud.region"; - public const string AttributeHostID = "host.id"; - public const string AttributeHostType = "host.type"; - public const string AttributeHostName = "host.name"; - } - [Fact] public void TestDetect() { @@ -56,4 +44,16 @@ public void TestDeserializeResponse() Assert.Equal("t2.micro", ec2IdentityDocumentModel.InstanceType); Assert.Equal("us-east-1", ec2IdentityDocumentModel.Region); } + + private static class ExpectedSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudPlatform = "cloud.platform"; + public const string AttributeCloudAccountID = "cloud.account.id"; + public const string AttributeCloudAvailabilityZone = "cloud.availability_zone"; + public const string AttributeCloudRegion = "cloud.region"; + public const string AttributeHostID = "host.id"; + public const string AttributeHostType = "host.type"; + public const string AttributeHostName = "host.name"; + } } diff --git a/test/OpenTelemetry.Resources.AWS.Tests/AWSECSDetectorTests.cs b/test/OpenTelemetry.Resources.AWS.Tests/AWSECSDetectorTests.cs index 03ff09f370..e0004df38d 100644 --- a/test/OpenTelemetry.Resources.AWS.Tests/AWSECSDetectorTests.cs +++ b/test/OpenTelemetry.Resources.AWS.Tests/AWSECSDetectorTests.cs @@ -18,25 +18,6 @@ public class AWSECSDetectorTests : IDisposable private const string AWSECSMetadataURLKey = "ECS_CONTAINER_METADATA_URI"; private const string AWSECSMetadataURLV4Key = "ECS_CONTAINER_METADATA_URI_V4"; - private static class ExpectedSemanticConventions - { - public const string AttributeCloudProvider = "cloud.provider"; - public const string AttributeCloudPlatform = "cloud.platform"; - public const string AttributeCloudAccountID = "cloud.account.id"; - public const string AttributeCloudAvailabilityZone = "cloud.availability_zone"; - public const string AttributeCloudRegion = "cloud.region"; - public const string AttributeCloudResourceId = "cloud.resource_id"; - public const string AttributeEcsContainerArn = "aws.ecs.container.arn"; - public const string AttributeEcsLaunchtype = "aws.ecs.launchtype"; - public const string AttributeEcsTaskArn = "aws.ecs.task.arn"; - public const string AttributeEcsTaskFamily = "aws.ecs.task.family"; - public const string AttributeEcsTaskRevision = "aws.ecs.task.revision"; - public const string AttributeLogGroupArns = "aws.log.group.arns"; - public const string AttributeLogGroupNames = "aws.log.group.names"; - public const string AttributeLogStreamArns = "aws.log.stream.arns"; - public const string AttributeLogStreamNames = "aws.log.stream.names"; - } - public AWSECSDetectorTests() { this.ResetEnvironment(); @@ -193,5 +174,24 @@ protected virtual async ValueTask DisposeAsyncCore() await this.server.StopAsync(); } } + + private static class ExpectedSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudPlatform = "cloud.platform"; + public const string AttributeCloudAccountID = "cloud.account.id"; + public const string AttributeCloudAvailabilityZone = "cloud.availability_zone"; + public const string AttributeCloudRegion = "cloud.region"; + public const string AttributeCloudResourceId = "cloud.resource_id"; + public const string AttributeEcsContainerArn = "aws.ecs.container.arn"; + public const string AttributeEcsLaunchtype = "aws.ecs.launchtype"; + public const string AttributeEcsTaskArn = "aws.ecs.task.arn"; + public const string AttributeEcsTaskFamily = "aws.ecs.task.family"; + public const string AttributeEcsTaskRevision = "aws.ecs.task.revision"; + public const string AttributeLogGroupArns = "aws.log.group.arns"; + public const string AttributeLogGroupNames = "aws.log.group.names"; + public const string AttributeLogStreamArns = "aws.log.stream.arns"; + public const string AttributeLogStreamNames = "aws.log.stream.names"; + } } #endif diff --git a/test/OpenTelemetry.Resources.AWS.Tests/AWSEKSDetectorTests.cs b/test/OpenTelemetry.Resources.AWS.Tests/AWSEKSDetectorTests.cs index b1a3241197..02ae46ce89 100644 --- a/test/OpenTelemetry.Resources.AWS.Tests/AWSEKSDetectorTests.cs +++ b/test/OpenTelemetry.Resources.AWS.Tests/AWSEKSDetectorTests.cs @@ -12,14 +12,6 @@ public class AWSEKSDetectorTests private const string AWSEKSCredentialsPath = "SampleMetadataFiles/testekstoken"; private const string AWSEKSMetadataFilePath = "SampleMetadataFiles/testcgroup"; - private static class ExpectedSemanticConventions - { - public const string AttributeCloudProvider = "cloud.provider"; - public const string AttributeCloudPlatform = "cloud.platform"; - public const string AttributeK8SClusterName = "k8s.cluster.name"; - public const string AttributeContainerID = "container.id"; - } - [Fact] public void TestDetect() { @@ -100,6 +92,14 @@ public void TestDeserializeResponse() Assert.NotNull(eksClusterInformation.Data); Assert.Equal("Test", eksClusterInformation.Data.ClusterName); } + + private static class ExpectedSemanticConventions + { + public const string AttributeCloudProvider = "cloud.provider"; + public const string AttributeCloudPlatform = "cloud.platform"; + public const string AttributeK8SClusterName = "k8s.cluster.name"; + public const string AttributeContainerID = "container.id"; + } } #endif From bc32e394a4a523b448c896f188b1e931c0dac0e9 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Fri, 6 Dec 2024 16:57:45 -0800 Subject: [PATCH 14/35] fix minor issues found by unit tests --- .../Implementation/AWSLambdaHttpUtils.cs | 27 +++- src/Shared/AWS/AWSSemanticConventions.cs | 142 +++++++++--------- .../AWS/AWSSemanticConventions.v1.10.cs | 4 +- .../AWS/AWSSemanticConventions.v1.10_1.cs | 3 +- 4 files changed, 96 insertions(+), 80 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs index ba554d06e3..efadfd55b7 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs @@ -54,12 +54,27 @@ internal static IEnumerable> GetHttpTags(TI return tags; } - tags - .AddAttributeHttpScheme(httpScheme) - .AddAttributeHttpTarget(httpTarget) - .AddAttributeHttpMethod(httpMethod) - .AddAttributeNetHostName(hostName) - .AddAttributeNetHostPort(hostPort); + if (httpScheme != null) + { + tags.AddAttributeHttpScheme(httpScheme, addIfEmpty: true); + } + + if (httpTarget != null) + { + tags.AddAttributeHttpTarget(httpTarget, addIfEmpty: true); + } + + if (httpMethod != null) + { + tags.AddAttributeHttpMethod(httpMethod, addIfEmpty: true); + } + + if (hostName != null) + { + tags.AddAttributeNetHostName(hostName, addIfEmpty: true); + } + + tags.AddAttributeNetHostPort(hostPort); return tags; } diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index bf38f5a35a..68b62bbf4b 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -88,11 +88,11 @@ public static IDictionary AddAttributeAWSBedrockKnowledgeBaseId( #region Cloud Attributes /// - public static T AddAttributeCloudAccountID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeCloudAccountID, value, addIfNull); + public static T AddAttributeCloudAccountID(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeCloudAccountID, value, addIfEmpty); /// - public static T AddAttributeCloudAvailabilityZone(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeCloudAvailabilityZone, value, addIfNull); + public static T AddAttributeCloudAvailabilityZone(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeCloudAvailabilityZone, value, addIfEmpty); /// public static T AddAttributeCloudPlatformIsAwsEc2(this T attributes) where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEc2); @@ -109,17 +109,17 @@ public static T AddAttributeCloudPlatformIsAwsElasticBeanstalk(this T attribu public static T AddAttributeCloudProviderIsAWS(this T attributes) where T : IList> => Add(attributes, x => x.AttributeCloudProvider, x => x.CloudProviderValuesAws); /// - public static T AddAttributeCloudRegion(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeCloudRegion, value, addIfNull); + public static T AddAttributeCloudRegion(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeCloudRegion, value, addIfEmpty); /// - public static T AddAttributeCloudResourceId(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeCloudResourceId, value, addIfNull); + public static T AddAttributeCloudResourceId(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeCloudResourceId, value, addIfEmpty); #endregion #region Container /// - public static T AddAttributeContainerId(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeContainerID, value, addIfNull); + public static T AddAttributeContainerId(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeContainerID, value, addIfEmpty); #endregion #region AWS @@ -130,11 +130,11 @@ public static T AddAttributeContainerId(this T attributes, object? value, boo public static Activity? SetTagAttributeGenAiSystemToBedrock(this Activity? activity) => SetTag(activity, x => x.AttributeGenAiSystem, x => x.AttributeAWSBedrock); /// - public static T AddAttributeEcsContainerArn(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsContainerArn, value, addIfNull); + public static T AddAttributeEcsContainerArn(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeEcsContainerArn, value, addIfEmpty); /// - public static T AddAttributeEcsClusterArn(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsClusterArn, value, addIfNull); + public static T AddAttributeEcsClusterArn(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeEcsClusterArn, value, addIfEmpty); /// public static T AddAttributeEcsLaunchtypeIsEc2(this T attributes) where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeEc2); @@ -142,60 +142,60 @@ public static T AddAttributeEcsLaunchtypeIsEc2(this T attributes) public static T AddAttributeEcsLaunchtypeIsFargate(this T attributes) where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeFargate); /// - public static T AddAttributeEcsTaskArn(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsTaskArn, value, addIfNull); + public static T AddAttributeEcsTaskArn(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeEcsTaskArn, value, addIfEmpty); /// - public static T AddAttributeEcsTaskFamily(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsTaskFamily, value, addIfNull); + public static T AddAttributeEcsTaskFamily(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeEcsTaskFamily, value, addIfEmpty); /// - public static T AddAttributeEcsTaskRevision(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeEcsTaskRevision, value, addIfNull); + public static T AddAttributeEcsTaskRevision(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeEcsTaskRevision, value, addIfEmpty); /// - public static T AddAttributeLogGroupNames(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeLogGroupNames, value, addIfNull); + public static T AddAttributeLogGroupNames(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeLogGroupNames, value, addIfEmpty); /// - public static T AddAttributeLogGroupArns(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeLogGroupArns, value, addIfNull); + public static T AddAttributeLogGroupArns(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeLogGroupArns, value, addIfEmpty); /// - public static T AddAttributeLogStreamNames(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeLogStreamNames, value, addIfNull); + public static T AddAttributeLogStreamNames(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeLogStreamNames, value, addIfEmpty); /// - public static T AddAttributeLogStreamArns(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeLogStreamArns, value, addIfNull); + public static T AddAttributeLogStreamArns(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeLogStreamArns, value, addIfEmpty); #endregion #region Faas /// - public static T AddAttributeFaasID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasID, value, addIfNull); + public static T AddAttributeFaasID(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeFaasID, value, addIfEmpty); /// - public static T AddAttributeFaasExecution(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasExecution, value, addIfNull); + public static T AddAttributeFaasExecution(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeFaasExecution, value, addIfEmpty); /// - public static T AddAttributeFaasName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasName, value, addIfNull); + public static T AddAttributeFaasName(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeFaasName, value, addIfEmpty); /// - public static T AddAttributeFaasVersion(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasVersion, value, addIfNull); + public static T AddAttributeFaasVersion(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeFaasVersion, value, addIfEmpty); /// - public static T AddAttributeFaasTrigger(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasTrigger, value, addIfNull); + public static T AddAttributeFaasTrigger(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeFaasTrigger, value, addIfEmpty); /// - public static T AddAttributeFaasColdStart(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeFaasColdStart, value, addIfNull); + public static T AddAttributeFaasColdStart(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeFaasColdStart, value, addIfEmpty); #endregion #region Host /// - public static T AddAttributeHostID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHostID, value, addIfNull); + public static T AddAttributeHostID(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeHostID, value, addIfEmpty); /// - public static T AddAttributeHostType(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHostType, value, addIfNull); + public static T AddAttributeHostType(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeHostType, value, addIfEmpty); /// - public static T AddAttributeHostName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHostName, value, addIfNull); + public static T AddAttributeHostName(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeHostName, value, addIfEmpty); #endregion #region Http @@ -203,29 +203,29 @@ public static T AddAttributeHostName(this T attributes, object? value, bool a public static Activity? SetTagAttributeHttpStatusCode(this Activity? activity, int value) => SetTag(activity, x => x.AttributeHttpStatusCode, value); /// - public static T AddAttributeHttpScheme(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHttpScheme, value, addIfNull); + public static T AddAttributeHttpScheme(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeHttpScheme, value, addIfEmpty); /// - public static T AddAttributeHttpTarget(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHttpTarget, value, addIfNull); + public static T AddAttributeHttpTarget(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeHttpTarget, value, addIfEmpty); /// - public static T AddAttributeHttpMethod(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeHttpMethod, value, addIfNull); + public static T AddAttributeHttpMethod(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeHttpMethod, value, addIfEmpty); #endregion #region Net /// - public static T AddAttributeNetHostName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeNetHostName, value, addIfNull); + public static T AddAttributeNetHostName(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeNetHostName, value, addIfEmpty); /// - public static T AddAttributeNetHostPort(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeNetHostPort, value, addIfNull); + public static T AddAttributeNetHostPort(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeNetHostPort, value, addIfEmpty); #endregion #region K8s /// - public static T AddAttributeK8SClusterName(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeK8SClusterName, value, addIfNull); + public static T AddAttributeK8SClusterName(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeK8SClusterName, value, addIfEmpty); #endregion #region Service @@ -233,29 +233,29 @@ public static T AddAttributeK8SClusterName(this T attributes, object? value, public static T AddAttributeServiceNameIsAwsElasticBeanstalk(this T attributes) where T : IList> => Add(attributes, x => x.AttributeServiceName, x => x.ServiceNameValuesAwsElasticBeanstalk); /// - public static T AddAttributeServiceNamespace(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeServiceNamespace, value, addIfNull); + public static T AddAttributeServiceNamespace(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeServiceNamespace, value, addIfEmpty); /// - public static T AddAttributeServiceInstanceID(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeServiceInstanceID, value, addIfNull); + public static T AddAttributeServiceInstanceID(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeServiceInstanceID, value, addIfEmpty); /// - public static T AddAttributeServiceVersion(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeServiceVersion, value, addIfNull); + public static T AddAttributeServiceVersion(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeServiceVersion, value, addIfEmpty); #endregion #region Url /// - public static T AddAttributeUrlPath(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeUrlPath, value, addIfNull); + public static T AddAttributeUrlPath(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeUrlPath, value, addIfEmpty); /// - public static T AddAttributeUrlQuery(this T attributes, object? value, bool addIfNull = false) - where T : IList> => Add(attributes, x => x.AttributeUrlQuery, value, addIfNull); + public static T AddAttributeUrlQuery(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeUrlQuery, value, addIfEmpty); #endregion private static T Add(this T attributes, Func attributeNameFunc, Func valueFunc) where T : IList> => Add(attributes, attributeNameFunc, valueFunc(GetSemanticConventionVersion())); - private static T Add(this T attributes, Func attributeNameFunc, object? value, bool addIfNull = false) + private static T Add(this T attributes, Func attributeNameFunc, object? value, bool addIfEmpty = false) where T : IList> { var semanticConventionVersionImpl = GetSemanticConventionVersion(); @@ -264,7 +264,7 @@ private static T Add(this T attributes, Func AddDic(IDictionary di if (!string.IsNullOrEmpty(attributeName)) { - dict.Add(attributeName, value); + dict.Add(value, attributeName); } return dict; diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.10.cs b/src/Shared/AWS/AWSSemanticConventions.v1.10.cs index b3d6e06e5a..572e0e073e 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.10.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.10.cs @@ -57,8 +57,8 @@ private class AWSSemanticConventions_v1_10 : AWSSemanticConventionsBase public override string AttributeLogGroupArns => "aws.log.group.arns"; public override string AttributeLogStreamNames => "aws.log.stream.arns"; public override string AttributeLogStreamArns => "aws.log.stream.names"; - public override string AttributeAWSDynamoTableName => "aws.dynamodb.table_names"; - public override string AttributeAWSSQSQueueUrl => "aws.queue_url"; // todo - confirm in java; + public override string AttributeAWSDynamoTableName => "aws.table_name"; + public override string AttributeAWSSQSQueueUrl => "aws.queue_url"; public override string AttributeAWSBedrockAgentId => "aws.bedrock.agent.id"; public override string AttributeAWSBedrockDataSourceId => "aws.bedrock.data_source.id"; public override string AttributeAWSBedrockGuardrailId => "aws.bedrock.guardrail.id"; diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs b/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs index 5701617f8b..3cb2b5b6a4 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs @@ -19,7 +19,8 @@ internal static partial class AWSSemanticConventions private class AWSSemanticConventions_v1_10_1 : AWSSemanticConventions_v1_10 { // AWS Attributes - public override string AttributeAWSBedrock => "aws.bedrock"; + //public override string AttributeAWSBedrock => "aws.bedrock"; + //public override string AttributeAWSDynamoTableName => "aws.dynamodb.table_names"; // FAAS Attributes public override string AttributeFaasID => "cloud.resource_id"; From 31700b85a3befbe0caa07c01f81773b477544d38 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Fri, 6 Dec 2024 17:00:09 -0800 Subject: [PATCH 15/35] Update Instrumentation.AWS.Tests to use Semantic Convention 1.29 --- src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs | 4 ++-- .../TestAWSClientInstrumentation.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs b/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs index 3cb2b5b6a4..8c7ffbc574 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs @@ -19,8 +19,8 @@ internal static partial class AWSSemanticConventions private class AWSSemanticConventions_v1_10_1 : AWSSemanticConventions_v1_10 { // AWS Attributes - //public override string AttributeAWSBedrock => "aws.bedrock"; - //public override string AttributeAWSDynamoTableName => "aws.dynamodb.table_names"; + public override string AttributeAWSBedrock => "aws.bedrock"; + public override string AttributeAWSDynamoTableName => "aws.dynamodb.table_names"; // FAAS Attributes public override string AttributeFaasID => "cloud.resource_id"; diff --git a/test/OpenTelemetry.Instrumentation.AWS.Tests/TestAWSClientInstrumentation.cs b/test/OpenTelemetry.Instrumentation.AWS.Tests/TestAWSClientInstrumentation.cs index 62dab131ce..f3a4b762c5 100644 --- a/test/OpenTelemetry.Instrumentation.AWS.Tests/TestAWSClientInstrumentation.cs +++ b/test/OpenTelemetry.Instrumentation.AWS.Tests/TestAWSClientInstrumentation.cs @@ -522,7 +522,7 @@ private void ValidateAWSActivity(Activity aws_activity, Activity parent) private void ValidateDynamoActivityTags(Activity ddb_activity) { Assert.Equal("DynamoDB.Scan", ddb_activity.DisplayName); - Assert.Equal("SampleProduct", Utils.GetTagValue(ddb_activity, "aws.table_name")); + Assert.Equal("SampleProduct", Utils.GetTagValue(ddb_activity, "aws.dynamodb.table_names")); Assert.Equal("dynamodb", Utils.GetTagValue(ddb_activity, "db.system")); Assert.Equal("aws-api", Utils.GetTagValue(ddb_activity, "rpc.system")); Assert.Equal("DynamoDB", Utils.GetTagValue(ddb_activity, "rpc.service")); @@ -551,7 +551,7 @@ private void ValidateBedrockRuntimeActivityTags(Activity bedrock_activity) { Assert.Equal("Bedrock Runtime.InvokeModel", bedrock_activity.DisplayName); Assert.Equal("amazon.titan-text-express-v1", Utils.GetTagValue(bedrock_activity, "gen_ai.request.model")); - Assert.Equal("aws_bedrock", Utils.GetTagValue(bedrock_activity, "gen_ai.system")); + Assert.Equal("aws.bedrock", Utils.GetTagValue(bedrock_activity, "gen_ai.system")); Assert.Equal("aws-api", Utils.GetTagValue(bedrock_activity, "rpc.system")); Assert.Equal("Bedrock Runtime", Utils.GetTagValue(bedrock_activity, "rpc.service")); Assert.Equal("InvokeModel", Utils.GetTagValue(bedrock_activity, "rpc.method")); From bb6315ad9a140e1e1514e0d180b6cf38b5cb89e9 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Fri, 6 Dec 2024 15:37:05 -0800 Subject: [PATCH 16/35] Change SemanticConventionVersion to track Semantic Convention versions --- .../.publicApi/PublicAPI.Unshipped.txt | 4 +- .../README.md | 2 +- .../.publicApi/PublicAPI.Unshipped.txt | 4 +- .../README.md | 2 +- .../.publicApi/PublicAPI.Unshipped.txt | 4 +- src/OpenTelemetry.Resources.AWS/README.md | 2 +- src/Shared/AWS/AWSSemanticConventions.Base.cs | 2 +- src/Shared/AWS/AWSSemanticConventions.cs | 8 ++-- ...0.cs => AWSSemanticConventions.v1.27.0.cs} | 4 +- ...1.cs => AWSSemanticConventions.v1.29.0.cs} | 4 +- src/Shared/AWS/SemanticConventionVersion.cs | 43 ++++++++++++------- .../AWSLambdaInstrumentationOptionsTests.cs | 4 +- 12 files changed, 47 insertions(+), 36 deletions(-) rename src/Shared/AWS/{AWSSemanticConventions.v1.10.cs => AWSSemanticConventions.v1.27.0.cs} (97%) rename src/Shared/AWS/{AWSSemanticConventions.v1.10_1.cs => AWSSemanticConventions.v1.29.0.cs} (92%) diff --git a/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt index c215e54797..cd7c7fea99 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt @@ -1,8 +1,8 @@ #nullable enable OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.AWS.SemanticConventionVersion.Latest = 0 -> OpenTelemetry.AWS.SemanticConventionVersion -OpenTelemetry.AWS.SemanticConventionVersion.v1_10_1_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion -OpenTelemetry.AWS.SemanticConventionVersion.v1_10_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_29_0_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_27_0_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.AWSClientInstrumentationOptions() -> void OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SemanticConventionVersion.get -> OpenTelemetry.AWS.SemanticConventionVersion diff --git a/src/OpenTelemetry.Instrumentation.AWS/README.md b/src/OpenTelemetry.Instrumentation.AWS/README.md index 31b55630e8..b0f37de079 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/README.md +++ b/src/OpenTelemetry.Instrumentation.AWS/README.md @@ -67,7 +67,7 @@ public void ConfigureServices(IServiceCollection services) services.AddOpenTelemetryTracing((builder) => builder .AddAWSInstrumentation(opt => { // pin to a specific Semantic Convention version - opt.SemanticConventionVersion = SemanticConventionVersion.v1_10_EXPERIMENTAL; + opt.SemanticConventionVersion = SemanticConventionVersion.v1_27_0_Experimental; }); } ``` diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt index aa2cbd314b..0729ddfc74 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/.publicApi/PublicAPI.Unshipped.txt @@ -1,8 +1,8 @@ #nullable enable OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.AWS.SemanticConventionVersion.Latest = 0 -> OpenTelemetry.AWS.SemanticConventionVersion -OpenTelemetry.AWS.SemanticConventionVersion.v1_10_1_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion -OpenTelemetry.AWS.SemanticConventionVersion.v1_10_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_29_0_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_27_0_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.AWSLambdaInstrumentationOptions() -> void OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaInstrumentationOptions.DisableAwsXRayContextExtraction.get -> bool diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/README.md b/src/OpenTelemetry.Instrumentation.AWSLambda/README.md index 055beaa741..75fe65d70e 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/README.md +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/README.md @@ -167,7 +167,7 @@ To opt-out of automatic upgrades, you can pin to a specific version: .AddAWSLambdaConfigurations(opt => { // pin to a specific Semantic Convention version - opt.SemanticConventionVersion = SemanticConventionVersion.v1_10_EXPERIMENTAL; + opt.SemanticConventionVersion = SemanticConventionVersion.v1_27_0_Experimental; }) .Build()!); ``` diff --git a/src/OpenTelemetry.Resources.AWS/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Resources.AWS/.publicApi/PublicAPI.Unshipped.txt index abbd25c43d..4f8d7efcd5 100644 --- a/src/OpenTelemetry.Resources.AWS/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Resources.AWS/.publicApi/PublicAPI.Unshipped.txt @@ -1,7 +1,7 @@ OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.AWS.SemanticConventionVersion.Latest = 0 -> OpenTelemetry.AWS.SemanticConventionVersion -OpenTelemetry.AWS.SemanticConventionVersion.v1_10_1_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion -OpenTelemetry.AWS.SemanticConventionVersion.v1_10_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_29_0_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.AWS.SemanticConventionVersion.v1_27_0_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion OpenTelemetry.Resources.AWS.AWSResourceBuilderOptions OpenTelemetry.Resources.AWS.AWSResourceBuilderOptions.AWSResourceBuilderOptions() -> void OpenTelemetry.Resources.AWS.AWSResourceBuilderOptions.SemanticConventionVersion.get -> OpenTelemetry.AWS.SemanticConventionVersion diff --git a/src/OpenTelemetry.Resources.AWS/README.md b/src/OpenTelemetry.Resources.AWS/README.md index 0fa8038f71..8484f0d5e5 100644 --- a/src/OpenTelemetry.Resources.AWS/README.md +++ b/src/OpenTelemetry.Resources.AWS/README.md @@ -93,7 +93,7 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder() .ConfigureResource(resource => resource.AddAWSEC2Detector( opt => { // pin to a specific Semantic Convention version - opt.SemanticConventionVersion = SemanticConventionVersion.v1_10_EXPERIMENTAL; + opt.SemanticConventionVersion = SemanticConventionVersion.v1_27_0_Experimental; } )) // other configurations diff --git a/src/Shared/AWS/AWSSemanticConventions.Base.cs b/src/Shared/AWS/AWSSemanticConventions.Base.cs index 370a96ac84..de36d5d066 100644 --- a/src/Shared/AWS/AWSSemanticConventions.Base.cs +++ b/src/Shared/AWS/AWSSemanticConventions.Base.cs @@ -18,7 +18,7 @@ internal static partial class AWSSemanticConventions /// Defines all Semantic Conventions used by AWS extension projects. /// /// All values default to string.Empty and are then is only defined - /// in the first version specific class (ie ) + /// in the first version specific class (ie ) /// to use it. This helps ensure the attribute doesn't get used if the user has specified /// a specific . /// diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index 68b62bbf4b..f70c3be2b8 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -313,11 +313,11 @@ private static AWSSemanticConventionsBase GetSemanticConventionVersion() switch (SemanticConventionVersion) { case SemanticConventionVersion.Latest: - case SemanticConventionVersion.v1_10_1_Experimental: - return new AWSSemanticConventions_v1_10_1(); + case SemanticConventionVersion.v1_29_0_Experimental: + return new AWSSemanticConventions_v1_29_0(); - case SemanticConventionVersion.v1_10_Experimental: - return new AWSSemanticConventions_v1_10(); + case SemanticConventionVersion.v1_27_0_Experimental: + return new AWSSemanticConventions_v1_27_0(); default: throw new InvalidEnumArgumentException( diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.10.cs b/src/Shared/AWS/AWSSemanticConventions.v1.27.0.cs similarity index 97% rename from src/Shared/AWS/AWSSemanticConventions.v1.10.cs rename to src/Shared/AWS/AWSSemanticConventions.v1.27.0.cs index 572e0e073e..43b33c5562 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.10.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.27.0.cs @@ -13,7 +13,7 @@ namespace OpenTelemetry.AWS; internal static partial class AWSSemanticConventions { /// - /// Open Telemetry Semantic Conventions as of the 1.10 release of this library. + /// Open Telemetry Semantic Conventions as of the 1.27.0 /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.27.0. /// /// @@ -22,7 +22,7 @@ internal static partial class AWSSemanticConventions /// /// Future version specific convention classes will only need to define new or changed attributes. /// - private class AWSSemanticConventions_v1_10 : AWSSemanticConventionsBase + private class AWSSemanticConventions_v1_27_0 : AWSSemanticConventionsBase { // CLOUD Attributes public override string AttributeCloudAccountID => "cloud.account.id"; diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs b/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs similarity index 92% rename from src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs rename to src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs index 8c7ffbc574..8d58278b4a 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.10_1.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs @@ -13,10 +13,10 @@ namespace OpenTelemetry.AWS; internal static partial class AWSSemanticConventions { /// - /// Open Telemetry Semantic Conventions as of the 1.10.1 release of this library. + /// Open Telemetry Semantic Conventions as of 1.29.0: /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.29.0. /// - private class AWSSemanticConventions_v1_10_1 : AWSSemanticConventions_v1_10 + private class AWSSemanticConventions_v1_29_0 : AWSSemanticConventions_v1_27_0 { // AWS Attributes public override string AttributeAWSBedrock => "aws.bedrock"; diff --git a/src/Shared/AWS/SemanticConventionVersion.cs b/src/Shared/AWS/SemanticConventionVersion.cs index 6d2706fefc..89c47aff12 100644 --- a/src/Shared/AWS/SemanticConventionVersion.cs +++ b/src/Shared/AWS/SemanticConventionVersion.cs @@ -8,26 +8,34 @@ namespace OpenTelemetry.AWS; /// /// -/// Collection of the Open Telemetry Semantic Conventions supported by the OpenTelemetry.*.AWS libraries. -/// Can be used to pin the version of Semantic Convention emitted. +/// Collection of the Open Telemetry Semantic Conventions supported by +/// the OpenTelemetry.*.AWS libraries. Can be used to pin the version +/// of Semantic Convention emitted. /// /// -/// While these libraries are intended for production use, they rely on several Semantic Conventions that are -/// still considered Experimental, meaning they may undergo additional changes before becoming Stable. This can -/// impact the aggregation and analysis of telemetry signals in environments with multiple applications or microservices. -/// For example, a microservice using an older version of the Semantic Conventions for Http Attributes may emit -/// "http.method" with a value of GET, while a different microservice, using a new version of Semantic Convention may instead emit the GET as +/// While these libraries are intended for production use, they rely on several +/// Semantic Conventions that are still considered Experimental, meaning they +/// may undergo additional changes before becoming Stable. This can impact +/// the aggregation and analysis of telemetry signals in environments with +/// multiple applications or microservices. For example, a microservice using +/// an older version of the Semantic Conventions for Http Attributes may emit +/// "http.method" with a value of GET, while a different microservice, +/// using a new version of Semantic Convention may instead emit the GET as /// "http.request.method". /// /// -/// Future versions the OpenTelemetry.*.AWS libraries will include updates to the Semantic Convention, which may break compatibility with a previous version. +/// Future versions the OpenTelemetry.*.AWS libraries will include updates +/// to the Semantic Convention, which may break compatibility with a previous +/// version. +/// /// To opt-out of automatic upgrades, you can pin to a specific version: +/// /// /// /// { -/// opt.SemanticConventionVersion = SemanticConventionVersion.v1_10_EXPERIMENTAL; +/// opt.SemanticConventionVersion = SemanticConventionVersion.v1_27_0_Experimental; /// }) /// .Build()!); /// ]]> @@ -39,25 +47,28 @@ namespace OpenTelemetry.AWS; /// /// /// -/// Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS libraries will remain on that version until the -/// next major version bump. +/// Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS libraries +/// will remain on that version until the next major version bump. /// public enum SemanticConventionVersion { /// - /// Use Experimental Conventions until they become stable and then pin to stable. + /// Use Experimental Conventions until they become stable and then + /// pin to stable. /// Latest = 0, /// - /// Pin to the specific state of all Semantic Conventions as of the 1.10 release of this library. + /// Pin to the specific state of all Semantic Conventions as of the 1.27.0 + /// release. See: /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.27.0. /// - v1_10_Experimental = 1, + v1_27_0_Experimental = 1, /// - /// Pin to the specific state of all Semantic Conventions as of the 1.10.1 release of this library. + /// Pin to the specific state of all Semantic Conventions as of the 1.29.0 + /// release. See: /// https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.29.0. /// - v1_10_1_Experimental = 2, + v1_29_0_Experimental = 2, } diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs index 244a9ee919..7a7d0c150c 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs @@ -25,7 +25,7 @@ public sealed class AWSLambdaInstrumentationOptionsTests : IDisposable [Fact] public void CanUseSemanticConvention1_10() { - var semanticVersion = SemanticConventionVersion.v1_10_Experimental; + var semanticVersion = SemanticConventionVersion.v1_27_0_Experimental; var expectedTags = new List { @@ -42,7 +42,7 @@ public void CanUseSemanticConvention1_10() [Fact] public void CanUseSemanticConvention1_10_1() { - var semanticVersion = SemanticConventionVersion.v1_10_1_Experimental; + var semanticVersion = SemanticConventionVersion.v1_29_0_Experimental; var expectedTags = new List { From 62e75e89141087a8fbd97552c03b7d4e3997ee92 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Fri, 6 Dec 2024 17:05:12 -0800 Subject: [PATCH 17/35] move depreication of AttributeHttpTarget to new PR --- src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs b/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs index 8d58278b4a..4e2b70f68a 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs @@ -30,7 +30,6 @@ private class AWSSemanticConventions_v1_29_0 : AWSSemanticConventions_v1_27_0 public override string AttributeHttpStatusCode => this.AttributeHttpResponseStatusCode; public override string AttributeHttpScheme => this.AttributeUrlScheme; - //public override string AttributeHttpTarget => string.Empty; // value no longer written ---- move to new PR public override string AttributeHttpMethod => this.AttributeHttpRequestMethod; public override string AttributeHttpResponseStatusCode => "http.response.status_code"; public override string AttributeHttpRequestMethod => "http.request.method"; From 0387cb26f5b2ce916ffcd9cafedd0ddf075ec114 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Fri, 6 Dec 2024 17:06:02 -0800 Subject: [PATCH 18/35] implement AttirbuteHttpTarget --- .../Implementation/AWSLambdaHttpUtils.cs | 25 ++++++++++++++++--- .../AWS/AWSSemanticConventions.v1.29.0.cs | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs index efadfd55b7..9a04a7e555 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs @@ -22,6 +22,8 @@ internal static IEnumerable> GetHttpTags(TI string? httpScheme; string? httpTarget; + string? urlPath; + string? urlQuery; string? httpMethod; string? hostName; int? hostPort; @@ -30,22 +32,27 @@ internal static IEnumerable> GetHttpTags(TI { case APIGatewayProxyRequest request: httpScheme = AWSLambdaUtils.GetHeaderValues(request, HeaderXForwardedProto)?.LastOrDefault(); - var path = request.RequestContext?.Path ?? request.Path ?? string.Empty; - httpTarget = string.Concat(path, GetQueryString(request)); + urlPath = request.RequestContext?.Path ?? request.Path ?? string.Empty; + urlQuery = GetQueryString(request); + httpTarget = string.Concat(urlPath, urlQuery); httpMethod = request.RequestContext?.HttpMethod ?? request.HttpMethod; var hostHeader = AWSLambdaUtils.GetHeaderValues(request, HeaderHost)?.LastOrDefault(); (hostName, hostPort) = GetHostAndPort(httpScheme, hostHeader); break; case APIGatewayHttpApiV2ProxyRequest requestV2: httpScheme = AWSLambdaUtils.GetHeaderValues(requestV2, HeaderXForwardedProto)?.LastOrDefault(); - httpTarget = string.Concat(requestV2.RawPath ?? string.Empty, GetQueryString(requestV2)); + urlPath = requestV2.RawPath ?? string.Empty; + urlQuery = GetQueryString(requestV2); + httpTarget = string.Concat(urlPath, urlQuery); httpMethod = requestV2.RequestContext?.Http?.Method; var hostHeaderV2 = AWSLambdaUtils.GetHeaderValues(requestV2, HeaderHost)?.LastOrDefault(); (hostName, hostPort) = GetHostAndPort(httpScheme, hostHeaderV2); break; case ApplicationLoadBalancerRequest albRequest: httpScheme = AWSLambdaUtils.GetHeaderValues(albRequest, HeaderXForwardedProto)?.LastOrDefault(); - httpTarget = string.Concat(albRequest.Path ?? string.Empty, GetQueryString(albRequest)); + urlPath = albRequest.Path ?? string.Empty; + urlQuery = GetQueryString(albRequest); + httpTarget = string.Concat(urlPath, urlQuery); httpMethod = albRequest.HttpMethod; var albHostHeader = AWSLambdaUtils.GetHeaderValues(albRequest, HeaderHost)?.LastOrDefault(); (hostName, hostPort) = GetHostAndPort(httpScheme, albHostHeader); @@ -64,6 +71,16 @@ internal static IEnumerable> GetHttpTags(TI tags.AddAttributeHttpTarget(httpTarget, addIfEmpty: true); } + if (urlPath != null) + { + tags.AddAttributeUrlPath(urlPath, addIfEmpty: true); + } + + if (urlQuery != null) + { + tags.AddAttributeUrlQuery(urlQuery, addIfEmpty: true); + } + if (httpMethod != null) { tags.AddAttributeHttpMethod(httpMethod, addIfEmpty: true); diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs b/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs index 4e2b70f68a..d1ab723bc7 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs @@ -30,6 +30,7 @@ private class AWSSemanticConventions_v1_29_0 : AWSSemanticConventions_v1_27_0 public override string AttributeHttpStatusCode => this.AttributeHttpResponseStatusCode; public override string AttributeHttpScheme => this.AttributeUrlScheme; + public override string AttributeHttpTarget => string.Empty; // value no longer written public override string AttributeHttpMethod => this.AttributeHttpRequestMethod; public override string AttributeHttpResponseStatusCode => "http.response.status_code"; public override string AttributeHttpRequestMethod => "http.request.method"; From 071f0b3fa1eb4d08da4e68904332c0eb167cff3a Mon Sep 17 00:00:00 2001 From: philip pittle Date: Fri, 6 Dec 2024 17:39:44 -0800 Subject: [PATCH 19/35] update AWS Lambda tests to use Semantic Convention 1.29 --- .../Implementation/AWSLambdaHttpUtilsTests.cs | 27 ++++++++++++------- .../AWSLambdaInstrumentationOptionsTests.cs | 3 ++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs index 102ef2fa40..4e5057b1f3 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs @@ -41,7 +41,8 @@ public void GetHttpTags_APIGatewayProxyRequest_ReturnsCorrectTags() var expectedTags = new Dictionary { { ExpectedSemanticConventions.AttributeHttpScheme, "https" }, - { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeUrlPath, "/path/test" }, + { ExpectedSemanticConventions.AttributeUrlQuery, "?q1=value1" }, { ExpectedSemanticConventions.AttributeNetHostName, "localhost" }, { ExpectedSemanticConventions.AttributeNetHostPort, 1234 }, { ExpectedSemanticConventions.AttributeHttpMethod, "GET" }, @@ -73,7 +74,8 @@ public void GetHttpTags_ApplicationLoadBalancerRequest_ReturnsCorrectTags() var expectedTags = new Dictionary { { ExpectedSemanticConventions.AttributeHttpScheme, "https" }, - { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeUrlPath, "/path/test" }, + { ExpectedSemanticConventions.AttributeUrlQuery, "?q1=value1" }, { ExpectedSemanticConventions.AttributeNetHostName, "localhost" }, { ExpectedSemanticConventions.AttributeNetHostPort, 1234 }, { ExpectedSemanticConventions.AttributeHttpMethod, "GET" }, @@ -107,7 +109,8 @@ public void GetHttpTags_ApplicationLoadBalancerRequestWithMultiValue_ReturnsCorr var expectedTags = new Dictionary { { ExpectedSemanticConventions.AttributeHttpScheme, "https" }, - { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeUrlPath, "/path/test" }, + { ExpectedSemanticConventions.AttributeUrlQuery, "?q1=value1" }, { ExpectedSemanticConventions.AttributeNetHostName, "localhost" }, { ExpectedSemanticConventions.AttributeNetHostPort, 1234 }, { ExpectedSemanticConventions.AttributeHttpMethod, "GET" }, @@ -132,7 +135,8 @@ public void GetHttpTags_ApplicationLoadBalancerRequestWithMultiValueHeader_UsesL var expectedTags = new Dictionary { - { ExpectedSemanticConventions.AttributeHttpTarget, string.Empty }, + { ExpectedSemanticConventions.AttributeUrlPath, string.Empty }, + { ExpectedSemanticConventions.AttributeUrlQuery, string.Empty }, { ExpectedSemanticConventions.AttributeHttpScheme, "http" }, { ExpectedSemanticConventions.AttributeNetHostName, "myhost" }, { ExpectedSemanticConventions.AttributeNetHostPort, 432 }, @@ -238,7 +242,8 @@ public void GetHttpTags_APIGatewayProxyRequestWithEmptyContext_ReturnsTagsFromRe var expectedTags = new Dictionary { { ExpectedSemanticConventions.AttributeHttpMethod, "POST" }, - { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeUrlPath, "/path/test" }, + { ExpectedSemanticConventions.AttributeUrlQuery, "?q1=value1" }, }; AssertTags(expectedTags, actualTags); @@ -260,7 +265,8 @@ public void GetHttpTags_APIGatewayProxyRequestWithMultiValueHeader_UsesLastValue var expectedTags = new Dictionary { - { ExpectedSemanticConventions.AttributeHttpTarget, string.Empty }, + { ExpectedSemanticConventions.AttributeUrlPath, string.Empty }, + { ExpectedSemanticConventions.AttributeUrlQuery, string.Empty }, { ExpectedSemanticConventions.AttributeHttpScheme, "http" }, { ExpectedSemanticConventions.AttributeNetHostName, "myhost" }, { ExpectedSemanticConventions.AttributeNetHostPort, 432 }, @@ -295,7 +301,8 @@ public void GetHttpTags_APIGatewayHttpApiV2ProxyRequest_ReturnsCorrectTags() var expectedTags = new Dictionary { { ExpectedSemanticConventions.AttributeHttpScheme, "https" }, - { ExpectedSemanticConventions.AttributeHttpTarget, "/path/test?q1=value1" }, + { ExpectedSemanticConventions.AttributeUrlPath, "/path/test" }, + { ExpectedSemanticConventions.AttributeUrlQuery, "?q1=value1" }, { ExpectedSemanticConventions.AttributeNetHostName, "localhost" }, { ExpectedSemanticConventions.AttributeNetHostPort, 1234 }, { ExpectedSemanticConventions.AttributeHttpMethod, "GET" }, @@ -320,7 +327,8 @@ public void GetHttpTags_APIGatewayHttpApiV2ProxyRequestWithMultiValueHeader_Uses var expectedTags = new Dictionary { - { ExpectedSemanticConventions.AttributeHttpTarget, string.Empty }, + { ExpectedSemanticConventions.AttributeUrlPath, string.Empty }, + { ExpectedSemanticConventions.AttributeUrlQuery, string.Empty }, { ExpectedSemanticConventions.AttributeHttpScheme, "http" }, { ExpectedSemanticConventions.AttributeNetHostName, "myhost" }, { ExpectedSemanticConventions.AttributeNetHostPort, 432 }, @@ -458,7 +466,8 @@ private static void AssertTags(Dictionary expected private static class ExpectedSemanticConventions { public const string AttributeHttpScheme = "url.scheme"; - public const string AttributeHttpTarget = "http.target"; + public const string AttributeUrlPath = "url.path"; + public const string AttributeUrlQuery = "url.query"; public const string AttributeNetHostName = "server.address"; public const string AttributeNetHostPort = "server.port"; public const string AttributeHttpMethod = "http.request.method"; diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs index 7a7d0c150c..89db7c762d 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs @@ -47,7 +47,8 @@ public void CanUseSemanticConvention1_10_1() var expectedTags = new List { "url.scheme", - "http.target", + "url.path", + "url.query", "server.address", "server.port", "http.request.method", From f180dd204e8bcbff230f56442e2457ac47953dd6 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Mon, 9 Dec 2024 15:46:13 -0800 Subject: [PATCH 20/35] change whitespace to improve readability --- src/Shared/AWS/AWSSemanticConventions.cs | 43 ++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index f70c3be2b8..4fcea65090 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -66,21 +66,27 @@ internal static partial class AWSSemanticConventions /// public static IDictionary AddAttributeAWSDynamoTableName(this IDictionary dict, string value) => AddDic(dict, x => x.AttributeAWSDynamoTableName, value); + /// public static IDictionary AddAttributeAWSSQSQueueUrl(this IDictionary dict, string value) => AddDic(dict, x => x.AttributeAWSSQSQueueUrl, value); + /// public static IDictionary AddAttributeGenAiModelId(this IDictionary dict, string value) => AddDic(dict, x => x.AttributeGenAiModelId, value); + /// public static IDictionary AddAttributeAWSBedrockAgentId(this IDictionary dict, string value) => AddDic(dict, x => x.AttributeAWSBedrockAgentId, value); + /// public static IDictionary AddAttributeAWSBedrockDataSourceId(this IDictionary dict, string value) => AddDic(dict, x => x.AttributeAWSBedrockDataSourceId, value); + /// public static IDictionary AddAttributeAWSBedrockGuardrailId(this IDictionary dict, string value) => AddDic(dict, x => x.AttributeAWSBedrockGuardrailId, value); + /// public static IDictionary AddAttributeAWSBedrockKnowledgeBaseId(this IDictionary dict, string value) => AddDic(dict, x => x.AttributeAWSBedrockKnowledgeBaseId, value); @@ -90,27 +96,35 @@ public static IDictionary AddAttributeAWSBedrockKnowledgeBaseId( /// public static T AddAttributeCloudAccountID(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeCloudAccountID, value, addIfEmpty); + /// public static T AddAttributeCloudAvailabilityZone(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeCloudAvailabilityZone, value, addIfEmpty); + /// public static T AddAttributeCloudPlatformIsAwsEc2(this T attributes) where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEc2); + /// public static T AddAttributeCloudPlatformIsAwsEcs(this T attributes) where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEcs); + /// public static T AddAttributeCloudPlatformIsAwsEks(this T attributes) where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsEks); + /// public static T AddAttributeCloudPlatformIsAwsElasticBeanstalk(this T attributes) where T : IList> => Add(attributes, x => x.AttributeCloudPlatform, x => x.CloudPlatformValuesAwsElasticBeanstalk); + /// public static T AddAttributeCloudProviderIsAWS(this T attributes) where T : IList> => Add(attributes, x => x.AttributeCloudProvider, x => x.CloudProviderValuesAws); + /// public static T AddAttributeCloudRegion(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeCloudRegion, value, addIfEmpty); + /// public static T AddAttributeCloudResourceId(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeCloudResourceId, value, addIfEmpty); @@ -126,60 +140,78 @@ public static T AddAttributeContainerId(this T attributes, object? value, boo /// public static Activity? SetTagAttributeDbSystemToDynamoDb(this Activity? activity) => SetTag(activity, x => x.AttributeDbSystem, x => x.AttributeDynamoDb); + /// public static Activity? SetTagAttributeGenAiSystemToBedrock(this Activity? activity) => SetTag(activity, x => x.AttributeGenAiSystem, x => x.AttributeAWSBedrock); + /// public static T AddAttributeEcsContainerArn(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeEcsContainerArn, value, addIfEmpty); + /// public static T AddAttributeEcsClusterArn(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeEcsClusterArn, value, addIfEmpty); + /// public static T AddAttributeEcsLaunchtypeIsEc2(this T attributes) where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeEc2); + /// public static T AddAttributeEcsLaunchtypeIsFargate(this T attributes) where T : IList> => Add(attributes, x => x.AttributeEcsLaunchtype, x => x.ValueEcsLaunchTypeFargate); + /// public static T AddAttributeEcsTaskArn(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeEcsTaskArn, value, addIfEmpty); + /// public static T AddAttributeEcsTaskFamily(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeEcsTaskFamily, value, addIfEmpty); + /// public static T AddAttributeEcsTaskRevision(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeEcsTaskRevision, value, addIfEmpty); + /// public static T AddAttributeLogGroupNames(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeLogGroupNames, value, addIfEmpty); + /// public static T AddAttributeLogGroupArns(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeLogGroupArns, value, addIfEmpty); + /// public static T AddAttributeLogStreamNames(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeLogStreamNames, value, addIfEmpty); + /// public static T AddAttributeLogStreamArns(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeLogStreamArns, value, addIfEmpty); + #endregion #region Faas /// public static T AddAttributeFaasID(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeFaasID, value, addIfEmpty); + /// public static T AddAttributeFaasExecution(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeFaasExecution, value, addIfEmpty); + /// public static T AddAttributeFaasName(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeFaasName, value, addIfEmpty); + /// public static T AddAttributeFaasVersion(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeFaasVersion, value, addIfEmpty); + /// public static T AddAttributeFaasTrigger(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeFaasTrigger, value, addIfEmpty); + /// public static T AddAttributeFaasColdStart(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeFaasColdStart, value, addIfEmpty); @@ -190,24 +222,30 @@ public static T AddAttributeFaasColdStart(this T attributes, object? value, b /// public static T AddAttributeHostID(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeHostID, value, addIfEmpty); + /// public static T AddAttributeHostType(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeHostType, value, addIfEmpty); + /// public static T AddAttributeHostName(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeHostName, value, addIfEmpty); + #endregion #region Http /// public static Activity? SetTagAttributeHttpStatusCode(this Activity? activity, int value) => SetTag(activity, x => x.AttributeHttpStatusCode, value); + /// public static T AddAttributeHttpScheme(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeHttpScheme, value, addIfEmpty); + /// public static T AddAttributeHttpTarget(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeHttpTarget, value, addIfEmpty); + /// public static T AddAttributeHttpMethod(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeHttpMethod, value, addIfEmpty); @@ -217,6 +255,7 @@ public static T AddAttributeHttpMethod(this T attributes, object? value, bool /// public static T AddAttributeNetHostName(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeNetHostName, value, addIfEmpty); + /// public static T AddAttributeNetHostPort(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeNetHostPort, value, addIfEmpty); @@ -232,12 +271,15 @@ public static T AddAttributeK8SClusterName(this T attributes, object? value, /// public static T AddAttributeServiceNameIsAwsElasticBeanstalk(this T attributes) where T : IList> => Add(attributes, x => x.AttributeServiceName, x => x.ServiceNameValuesAwsElasticBeanstalk); + /// public static T AddAttributeServiceNamespace(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeServiceNamespace, value, addIfEmpty); + /// public static T AddAttributeServiceInstanceID(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeServiceInstanceID, value, addIfEmpty); + /// public static T AddAttributeServiceVersion(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeServiceVersion, value, addIfEmpty); @@ -247,6 +289,7 @@ public static T AddAttributeServiceVersion(this T attributes, object? value, /// public static T AddAttributeUrlPath(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeUrlPath, value, addIfEmpty); + /// public static T AddAttributeUrlQuery(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeUrlQuery, value, addIfEmpty); From b7b251b470fbdd1cda699f7916e42e369923f129 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Mon, 9 Dec 2024 16:01:57 -0800 Subject: [PATCH 21/35] rebase change semnatic versions to track --- .../Implementation/AWSLambdaInstrumentationOptionsTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs index 89db7c762d..67d142ffe0 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs @@ -23,7 +23,7 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Tests.Implementation; public sealed class AWSLambdaInstrumentationOptionsTests : IDisposable { [Fact] - public void CanUseSemanticConvention1_10() + public void CanUseSemanticConvention_v1_27_0() { var semanticVersion = SemanticConventionVersion.v1_27_0_Experimental; @@ -40,7 +40,7 @@ public void CanUseSemanticConvention1_10() } [Fact] - public void CanUseSemanticConvention1_10_1() + public void CanUseSemanticConvention_v1_29_0() { var semanticVersion = SemanticConventionVersion.v1_29_0_Experimental; From 2bc2930c4900471dffb3a7099ac5ff0ef8d094d7 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Mon, 9 Dec 2024 16:05:34 -0800 Subject: [PATCH 22/35] adjust strategy to list attributes as obsolete and add additional AddAttribute calls in core logic --- .../Implementation/AWSLambdaHttpUtils.cs | 21 ++++++++------ src/Shared/AWS/AWSSemanticConventions.Base.cs | 6 ++++ src/Shared/AWS/AWSSemanticConventions.cs | 28 +++++++++++++++++++ .../AWS/AWSSemanticConventions.v1.27.0.cs | 6 ++++ .../AWS/AWSSemanticConventions.v1.29.0.cs | 16 +++++++---- 5 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs index 9a04a7e555..cc0143bac2 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/Implementation/AWSLambdaHttpUtils.cs @@ -8,6 +8,9 @@ using Amazon.Lambda.ApplicationLoadBalancerEvents; using OpenTelemetry.AWS; +// Continue to off obsolete Semantic Convention until the next major version bump +#pragma warning disable CS0618 // Type or member is obsolete + namespace OpenTelemetry.Instrumentation.AWSLambda.Implementation; internal class AWSLambdaHttpUtils @@ -64,17 +67,11 @@ internal static IEnumerable> GetHttpTags(TI if (httpScheme != null) { tags.AddAttributeHttpScheme(httpScheme, addIfEmpty: true); + tags.AddAttributeUrlScheme(httpScheme, addIfEmpty: true); } - if (httpTarget != null) - { - tags.AddAttributeHttpTarget(httpTarget, addIfEmpty: true); - } - - if (urlPath != null) - { - tags.AddAttributeUrlPath(urlPath, addIfEmpty: true); - } + tags.AddAttributeHttpTarget(httpTarget, addIfEmpty: true); + tags.AddAttributeUrlPath(urlPath, addIfEmpty: true); if (urlQuery != null) { @@ -84,14 +81,17 @@ internal static IEnumerable> GetHttpTags(TI if (httpMethod != null) { tags.AddAttributeHttpMethod(httpMethod, addIfEmpty: true); + tags.AddAttributeHttpRequestMethod(httpMethod, addIfEmpty: true); } if (hostName != null) { tags.AddAttributeNetHostName(hostName, addIfEmpty: true); + tags.AddAttributeServerAddress(hostName, addIfEmpty: true); } tags.AddAttributeNetHostPort(hostPort); + tags.AddAttributeServerPort(hostPort); return tags; } @@ -107,12 +107,15 @@ internal static void SetHttpTagsFromResult(Activity? activity, object? result) { case APIGatewayProxyResponse response: activity.SetTagAttributeHttpStatusCode(response.StatusCode); + activity.SetTagAttributeHttpResponseStatusCode(response.StatusCode); break; case APIGatewayHttpApiV2ProxyResponse responseV2: activity.SetTagAttributeHttpStatusCode(responseV2.StatusCode); + activity.SetTagAttributeHttpResponseStatusCode(responseV2.StatusCode); break; case ApplicationLoadBalancerResponse albResponse: activity.SetTagAttributeHttpStatusCode(albResponse.StatusCode); + activity.SetTagAttributeHttpResponseStatusCode(albResponse.StatusCode); break; default: break; diff --git a/src/Shared/AWS/AWSSemanticConventions.Base.cs b/src/Shared/AWS/AWSSemanticConventions.Base.cs index de36d5d066..976ce97246 100644 --- a/src/Shared/AWS/AWSSemanticConventions.Base.cs +++ b/src/Shared/AWS/AWSSemanticConventions.Base.cs @@ -142,22 +142,28 @@ private abstract class AWSSemanticConventionsBase // HTTP Attributes /// + [Obsolete("Replaced by http.response.status_code.")] public virtual string AttributeHttpStatusCode => string.Empty; /// public virtual string AttributeHttpResponseStatusCode => string.Empty; /// + [Obsolete("Replaced by url.scheme instead.")] public virtual string AttributeHttpScheme => string.Empty; /// + [Obsolete("Split to url.path and `url.query.")] public virtual string AttributeHttpTarget => string.Empty; /// + [Obsolete("Replaced by http.request.method.")] public virtual string AttributeHttpMethod => string.Empty; /// public virtual string AttributeHttpRequestMethod => string.Empty; // NET Attributes /// + [Obsolete("Replaced by server.address.")] public virtual string AttributeNetHostName => string.Empty; /// + [Obsolete("Replaced by server.port.")] public virtual string AttributeNetHostPort => string.Empty; // SERVER Attributes diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index 4fcea65090..4f625def02 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -235,28 +235,42 @@ public static T AddAttributeHostName(this T attributes, object? value, bool a #region Http /// + [Obsolete("Replaced by http.response.status_code.")] public static Activity? SetTagAttributeHttpStatusCode(this Activity? activity, int value) => SetTag(activity, x => x.AttributeHttpStatusCode, value); + /// + public static Activity? SetTagAttributeHttpResponseStatusCode(this Activity? activity, int value) + => SetTag(activity, x => x.AttributeHttpResponseStatusCode, value); + /// + [Obsolete("Replaced by url.scheme instead.")] public static T AddAttributeHttpScheme(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeHttpScheme, value, addIfEmpty); /// + [Obsolete("Split to url.path and `url.query.")] public static T AddAttributeHttpTarget(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeHttpTarget, value, addIfEmpty); /// + [Obsolete("Replaced by http.request.method.")] public static T AddAttributeHttpMethod(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeHttpMethod, value, addIfEmpty); + + /// + public static T AddAttributeHttpRequestMethod(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeHttpRequestMethod, value, addIfEmpty); #endregion #region Net /// + [Obsolete("Replaced by server.address.")] public static T AddAttributeNetHostName(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeNetHostName, value, addIfEmpty); /// + [Obsolete("Replaced by server.port.")] public static T AddAttributeNetHostPort(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeNetHostPort, value, addIfEmpty); #endregion @@ -267,6 +281,16 @@ public static T AddAttributeK8SClusterName(this T attributes, object? value, where T : IList> => Add(attributes, x => x.AttributeK8SClusterName, value, addIfEmpty); #endregion + #region Server + /// + public static T AddAttributeServerAddress(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeServerAddress, value, addIfEmpty); + + /// + public static T AddAttributeServerPort(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeServerPort, value, addIfEmpty); + #endregion + #region Service /// public static T AddAttributeServiceNameIsAwsElasticBeanstalk(this T attributes) @@ -293,6 +317,10 @@ public static T AddAttributeUrlPath(this T attributes, object? value, bool ad /// public static T AddAttributeUrlQuery(this T attributes, object? value, bool addIfEmpty = false) where T : IList> => Add(attributes, x => x.AttributeUrlQuery, value, addIfEmpty); + + /// + public static T AddAttributeUrlScheme(this T attributes, object? value, bool addIfEmpty = false) + where T : IList> => Add(attributes, x => x.AttributeUrlScheme, value, addIfEmpty); #endregion private static T Add(this T attributes, Func attributeNameFunc, Func valueFunc) diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.27.0.cs b/src/Shared/AWS/AWSSemanticConventions.v1.27.0.cs index 43b33c5562..cef99b05b6 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.27.0.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.27.0.cs @@ -83,13 +83,19 @@ private class AWSSemanticConventions_v1_27_0 : AWSSemanticConventionsBase public override string AttributeHostName => "host.name"; // HTTP Attributes + [Obsolete("Replaced by http.response.status_code.")] public override string AttributeHttpStatusCode => "http.status_code"; + [Obsolete("Replaced by url.scheme instead.")] public override string AttributeHttpScheme => "http.scheme"; + [Obsolete("Split to url.path and `url.query.")] public override string AttributeHttpTarget => "http.target"; + [Obsolete("Replaced by http.request.method.")] public override string AttributeHttpMethod => "http.method"; // NET Attributes + [Obsolete("Replaced by server.address.")] public override string AttributeNetHostName => "net.host.name"; + [Obsolete("Replaced by server.port.")] public override string AttributeNetHostPort => "net.host.port"; // K8s Attributes diff --git a/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs b/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs index d1ab723bc7..23f69bbd3b 100644 --- a/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs +++ b/src/Shared/AWS/AWSSemanticConventions.v1.29.0.cs @@ -27,17 +27,23 @@ private class AWSSemanticConventions_v1_29_0 : AWSSemanticConventions_v1_27_0 public override string AttributeFaasExecution => "faas.invocation_id"; // HTTP Attributes - public override string AttributeHttpStatusCode => this.AttributeHttpResponseStatusCode; - public override string AttributeHttpScheme => this.AttributeUrlScheme; + [Obsolete("Replaced by http.response.status_code.")] + public override string AttributeHttpStatusCode => string.Empty; // value no longer written + [Obsolete("Replaced by url.scheme instead.")] + public override string AttributeHttpScheme => string.Empty; // value no longer written + [Obsolete("Split to url.path and `url.query.")] public override string AttributeHttpTarget => string.Empty; // value no longer written - public override string AttributeHttpMethod => this.AttributeHttpRequestMethod; + [Obsolete("Replaced by http.request.method.")] + public override string AttributeHttpMethod => string.Empty; // value no longer written public override string AttributeHttpResponseStatusCode => "http.response.status_code"; public override string AttributeHttpRequestMethod => "http.request.method"; // NET Attributes - public override string AttributeNetHostName => this.AttributeServerAddress; - public override string AttributeNetHostPort => this.AttributeServerPort; + [Obsolete("Replaced by server.address.")] + public override string AttributeNetHostName => string.Empty; // value no longer written + [Obsolete("Replaced by server.port.")] + public override string AttributeNetHostPort => string.Empty; // value no longer written // SERVER Attributes public override string AttributeServerAddress => "server.address"; From 82bae2a76ee3389d0a7a546529d2861723f4806f Mon Sep 17 00:00:00 2001 From: philip pittle Date: Mon, 9 Dec 2024 17:00:07 -0800 Subject: [PATCH 23/35] change SemenaticCvonentionVersion strategy to pin to v1.27 - the current version used by the library. Users must opt-in to newer versions of semantic conventions. --- .../CHANGELOG.md | 4 ++ .../README.md | 7 ++- .../CHANGELOG.md | 4 ++ .../README.md | 7 ++- src/OpenTelemetry.Resources.AWS/CHANGELOG.md | 4 ++ src/OpenTelemetry.Resources.AWS/README.md | 7 ++- src/Shared/AWS/AWSSemanticConventions.cs | 7 ++- src/Shared/AWS/SemanticConventionVersion.cs | 13 ++++- .../TestAWSClientInstrumentation.cs | 55 +++++++++++++++---- .../AWSLambdaWrapperTests.cs | 44 ++++++++++++--- .../Implementation/AWSLambdaHttpUtilsTests.cs | 20 ++++++- .../AWSLambdaInstrumentationOptionsTests.cs | 3 +- 12 files changed, 143 insertions(+), 32 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AWS/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AWS/CHANGELOG.md index b4affacd6c..c495b6b4dc 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.AWS/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +* Introduce `AWSClientInstrumentationOptions.SemanticConventionVersion` which + provides a mechanism for developers to opt-in to newer versions of the + of the Open Telemetry Semantic Conventions. ([#2367](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2367)) + ## 1.10.0-beta.2 Released 2024-Dec-12 diff --git a/src/OpenTelemetry.Instrumentation.AWS/README.md b/src/OpenTelemetry.Instrumentation.AWS/README.md index b0f37de079..fb582b000d 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/README.md +++ b/src/OpenTelemetry.Instrumentation.AWS/README.md @@ -53,7 +53,10 @@ emit the GET as `"http.request.method"`. Future versions the OpenTelemetry.*.AWS libraries will include updates to the Semantic Convention, which may break compatibility with a previous version. -To opt-out of automatic upgrades, you can pin to a specific version: +The default will remain as `v1_27_0_Experimental` until the next major version bump. + +To opt in to automatic upgrades, you can use `SemanticConventionVersion.Latest` +or you can specify a specific version: ```csharp using OpenTelemetry; @@ -67,7 +70,7 @@ public void ConfigureServices(IServiceCollection services) services.AddOpenTelemetryTracing((builder) => builder .AddAWSInstrumentation(opt => { // pin to a specific Semantic Convention version - opt.SemanticConventionVersion = SemanticConventionVersion.v1_27_0_Experimental; + opt.SemanticConventionVersion = SemanticConventionVersion.v1_29_0_Experimental; }); } ``` diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md index 0c713f611b..578bc4b184 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +* Introduce `AWSClientInstrumentationOptions.SemanticConventionVersion` which + provides a mechanism for developers to opt-in to newer versions of the + of the Open Telemetry Semantic Conventions. ([#2367](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2367)) + ## 1.10.0-beta.2 Released 2024-Dec-12 diff --git a/src/OpenTelemetry.Instrumentation.AWSLambda/README.md b/src/OpenTelemetry.Instrumentation.AWSLambda/README.md index 75fe65d70e..1ad297014c 100644 --- a/src/OpenTelemetry.Instrumentation.AWSLambda/README.md +++ b/src/OpenTelemetry.Instrumentation.AWSLambda/README.md @@ -160,14 +160,17 @@ Future versions of OpenTelemetry.Instrumentation.AWSLambda library will include updates to the Semantic Convention, which may break compatibility with a previous version. -To opt-out of automatic upgrades, you can pin to a specific version: +The default will remain as `v1_27_0_Experimental` until the next major version bump. + +To opt in to automatic upgrades, you can use `SemanticConventionVersion.Latest` +or you can specify a specific version: ```csharp using (var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddAWSLambdaConfigurations(opt => { // pin to a specific Semantic Convention version - opt.SemanticConventionVersion = SemanticConventionVersion.v1_27_0_Experimental; + opt.SemanticConventionVersion = SemanticConventionVersion.v1_29_0_Experimental; }) .Build()!); ``` diff --git a/src/OpenTelemetry.Resources.AWS/CHANGELOG.md b/src/OpenTelemetry.Resources.AWS/CHANGELOG.md index a7f3bdd855..64ab45e160 100644 --- a/src/OpenTelemetry.Resources.AWS/CHANGELOG.md +++ b/src/OpenTelemetry.Resources.AWS/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +* Introduce `AWSResourceBuilderOptions.SemanticConventionVersion` which + provides a mechanism for developers to opt-in to newer versions of the + of the Open Telemetry Semantic Conventions. ([#2367](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2367)) + * Drop support for .NET 6 as this target is no longer supported and add .NET Standard 2.0 target. ([#2164](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2164)) diff --git a/src/OpenTelemetry.Resources.AWS/README.md b/src/OpenTelemetry.Resources.AWS/README.md index 8484f0d5e5..88f1bdf1c5 100644 --- a/src/OpenTelemetry.Resources.AWS/README.md +++ b/src/OpenTelemetry.Resources.AWS/README.md @@ -83,7 +83,10 @@ emit the GET as `"http.request.method"`. Future versions the OpenTelemetry.*.AWS libraries will include updates to the Semantic Convention, which may break compatibility with a previous version. -To opt-out of automatic upgrades, you can pin to a specific version: +The default will remain as `v1_27_0_Experimental` until the next major version bump. + +To opt in to automatic upgrades, you can use `SemanticConventionVersion.Latest` +or you can specify a specific version: ```csharp using OpenTelemetry; @@ -93,7 +96,7 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder() .ConfigureResource(resource => resource.AddAWSEC2Detector( opt => { // pin to a specific Semantic Convention version - opt.SemanticConventionVersion = SemanticConventionVersion.v1_27_0_Experimental; + opt.SemanticConventionVersion = SemanticConventionVersion.v1_29_0_Experimental; } )) // other configurations diff --git a/src/Shared/AWS/AWSSemanticConventions.cs b/src/Shared/AWS/AWSSemanticConventions.cs index 4f625def02..6ae9c4595b 100644 --- a/src/Shared/AWS/AWSSemanticConventions.cs +++ b/src/Shared/AWS/AWSSemanticConventions.cs @@ -10,6 +10,7 @@ #pragma warning disable SA1514 #pragma warning disable SA1201 #pragma warning disable SA1623 +#pragma warning disable IDE0001 namespace OpenTelemetry.AWS; @@ -59,7 +60,11 @@ internal static partial class AWSSemanticConventions /// ]]> /// /// - internal const SemanticConventionVersion DefaultSemanticConventionVersion = SemanticConventionVersion.Latest; + /// + /// Per , default should stay as + /// until next major version bump. + /// + internal const SemanticConventionVersion DefaultSemanticConventionVersion = SemanticConventionVersion.v1_27_0_Experimental; #region Service Parameter Mapping diff --git a/src/Shared/AWS/SemanticConventionVersion.cs b/src/Shared/AWS/SemanticConventionVersion.cs index 89c47aff12..2d409c7b0c 100644 --- a/src/Shared/AWS/SemanticConventionVersion.cs +++ b/src/Shared/AWS/SemanticConventionVersion.cs @@ -15,7 +15,7 @@ namespace OpenTelemetry.AWS; /// /// While these libraries are intended for production use, they rely on several /// Semantic Conventions that are still considered Experimental, meaning they -/// may undergo additional changes before becoming Stable. This can impact +/// may undergo additional changes before becoming Stable. This can impact /// the aggregation and analysis of telemetry signals in environments with /// multiple applications or microservices. For example, a microservice using /// an older version of the Semantic Conventions for Http Attributes may emit @@ -27,15 +27,22 @@ namespace OpenTelemetry.AWS; /// Future versions the OpenTelemetry.*.AWS libraries will include updates /// to the Semantic Convention, which may break compatibility with a previous /// version. +/// +/// +/// The default will remain as until the next major version +/// bump. +/// /// -/// To opt-out of automatic upgrades, you can pin to a specific version: +/// To opt in to automatic upgrades, you can use +/// or you can specify a specific version: /// +/// /// /// /// { -/// opt.SemanticConventionVersion = SemanticConventionVersion.v1_27_0_Experimental; +/// opt.SemanticConventionVersion = SemanticConventionVersion.v1_29_0_Experimental; /// }) /// .Build()!); /// ]]> diff --git a/test/OpenTelemetry.Instrumentation.AWS.Tests/TestAWSClientInstrumentation.cs b/test/OpenTelemetry.Instrumentation.AWS.Tests/TestAWSClientInstrumentation.cs index f3a4b762c5..487ededdb6 100644 --- a/test/OpenTelemetry.Instrumentation.AWS.Tests/TestAWSClientInstrumentation.cs +++ b/test/OpenTelemetry.Instrumentation.AWS.Tests/TestAWSClientInstrumentation.cs @@ -39,7 +39,10 @@ public async Task TestDDBScanSuccessful() using (Sdk.CreateTracerProviderBuilder() .SetSampler(new AlwaysOnSampler()) .AddXRayTraceId() - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -84,7 +87,10 @@ public async Task TestDDBSubtypeScanSuccessful() using (Sdk.CreateTracerProviderBuilder() .SetSampler(new AlwaysOnSampler()) .AddXRayTraceId() - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -129,7 +135,10 @@ public async Task TestDDBScanUnsuccessful() using (Sdk.CreateTracerProviderBuilder() .SetSampler(new AlwaysOnSampler()) .AddXRayTraceId() - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -189,7 +198,10 @@ public async Task TestSQSSendMessageSuccessful() using (Sdk.CreateTracerProviderBuilder() .AddXRayTraceId() .SetSampler(new AlwaysOnSampler()) - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -235,7 +247,10 @@ public async Task TestBedrockGetGuardrailSuccessful() using (Sdk.CreateTracerProviderBuilder() .AddXRayTraceId() .SetSampler(new AlwaysOnSampler()) - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -276,7 +291,10 @@ public async Task TestBedrockRuntimeInvokeModelSuccessful() using (Sdk.CreateTracerProviderBuilder() .AddXRayTraceId() .SetSampler(new AlwaysOnSampler()) - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -317,7 +335,10 @@ public async Task TestBedrockAgentGetAgentSuccessful() using (Sdk.CreateTracerProviderBuilder() .AddXRayTraceId() .SetSampler(new AlwaysOnSampler()) - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -358,7 +379,10 @@ public async Task TestBedrockAgentGetKnowledgeBaseSuccessful() using (Sdk.CreateTracerProviderBuilder() .AddXRayTraceId() .SetSampler(new AlwaysOnSampler()) - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -399,7 +423,10 @@ public async Task TestBedrockAgentGetDataSourceSuccessful() using (Sdk.CreateTracerProviderBuilder() .AddXRayTraceId() .SetSampler(new AlwaysOnSampler()) - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -440,7 +467,10 @@ public async Task TestBedrockAgentRuntimeInvokeAgentSuccessful() using (Sdk.CreateTracerProviderBuilder() .AddXRayTraceId() .SetSampler(new AlwaysOnSampler()) - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { @@ -487,7 +517,10 @@ public async Task TestBedrockAgentRuntimeRetrieveSuccessful() using (Sdk.CreateTracerProviderBuilder() .AddXRayTraceId() .SetSampler(new AlwaysOnSampler()) - .AddAWSInstrumentation() + .AddAWSInstrumentation(o => + { + o.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()) { diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs index b95359b96b..fa013b2f48 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/AWSLambdaWrapperTests.cs @@ -9,7 +9,7 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Tests; [Collection("TracerProviderDependent")] -public class AWSLambdaWrapperTests +public class AWSLambdaWrapperTests : IDisposable { private const string TraceId = "5759e988bd862e3fe1be46a994272793"; private const string XRayParentId = "53995c3f42cd8ad8"; @@ -28,6 +28,13 @@ public AWSLambdaWrapperTests() Environment.SetEnvironmentVariable("AWS_LAMBDA_FUNCTION_VERSION", "latest"); } + public void Dispose() + { + // reset Semantic Convention to default + Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations(); + } + [Theory] [InlineData(false)] [InlineData(true)] @@ -36,7 +43,10 @@ public void TraceSyncWithInputAndReturn(bool setCustomParent) var exportedItems = new List(); using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations() + .AddAWSLambdaConfigurations(opt => + { + opt.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()!) { @@ -61,7 +71,10 @@ public void TraceSyncWithInputAndNoReturn(bool setCustomParent) var exportedItems = new List(); using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations() + .AddAWSLambdaConfigurations(opt => + { + opt.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()!) { @@ -86,7 +99,10 @@ public async Task TraceAsyncWithInputAndReturn(bool setCustomParent) var exportedItems = new List(); using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations() + .AddAWSLambdaConfigurations(opt => + { + opt.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()!) { @@ -111,7 +127,10 @@ public async Task TraceAsyncWithInputAndNoReturn(bool setCustomParent) var exportedItems = new List(); using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations() + .AddAWSLambdaConfigurations(opt => + { + opt.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()!) { @@ -136,7 +155,10 @@ public void TestLambdaHandlerException(bool setCustomParent) var exportedItems = new List(); using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations() + .AddAWSLambdaConfigurations(opt => + { + opt.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()!) { @@ -168,7 +190,10 @@ public void TestLambdaHandlerNotSampled() var exportedItems = new List(); using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations() + .AddAWSLambdaConfigurations(opt => + { + opt.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .AddInMemoryExporter(exportedItems) .Build()!) { @@ -187,7 +212,10 @@ public void OnFunctionStart_NoParent_ActivityCreated() Activity? activity = null; using (var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations() + .AddAWSLambdaConfigurations(opt => + { + opt.SemanticConventionVersion = SemanticConventionVersion.Latest; + }) .Build()) { activity = AWSLambdaWrapper.OnFunctionStart("test-input", new SampleLambdaContext()); diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs index 4e5057b1f3..c1c1d0fa71 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaHttpUtilsTests.cs @@ -11,8 +11,26 @@ namespace OpenTelemetry.Instrumentation.AWSLambda.Tests.Implementation; [Collection("TracerProviderDependent")] -public class AWSLambdaHttpUtilsTests +public class AWSLambdaHttpUtilsTests : IDisposable { + public AWSLambdaHttpUtilsTests() + { + // have all tests use the latest Semantic Convention + Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations(opt => + { + opt.SemanticConventionVersion = SemanticConventionVersion.Latest; + }); + } + + public void Dispose() + { + // reset Semantic Convention to default + Sdk.CreateTracerProviderBuilder() + .AddAWSLambdaConfigurations(); + } + + [Fact] public void GetHttpTags_APIGatewayProxyRequest_ReturnsCorrectTags() { diff --git a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs index 67d142ffe0..442520091d 100644 --- a/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs +++ b/test/OpenTelemetry.Instrumentation.AWSLambda.Tests/Implementation/AWSLambdaInstrumentationOptionsTests.cs @@ -62,8 +62,7 @@ public void Dispose() // Semantic Convention is saved statically - and needs to be reset to // Latest following these tests. Sdk.CreateTracerProviderBuilder() - .AddAWSLambdaConfigurations(c => - c.SemanticConventionVersion = SemanticConventionVersion.Latest) + .AddAWSLambdaConfigurations() .Build(); } From 0eb9e875cc3ebfcfd92ed62b19bfa7beaef8c4b5 Mon Sep 17 00:00:00 2001 From: philip pittle Date: Mon, 9 Dec 2024 18:09:31 -0800 Subject: [PATCH 24/35] =?UTF-8?q?=EF=BB=BFSemanticConventionsVersion=20is?= =?UTF-8?q?=20public=20in=20multiple=20repositories=20and=20so=20must=20ha?= =?UTF-8?q?ve=20a=20unique=20namespace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.publicApi/PublicAPI.Unshipped.txt | 10 +++++----- .../AWSClientInstrumentationOptions.cs | 2 +- .../OpenTelemetry.Instrumentation.AWS.csproj | 1 + .../.publicApi/PublicAPI.Unshipped.txt | 10 +++++----- .../AWSLambdaInstrumentationOptions.cs | 2 +- .../OpenTelemetry.Instrumentation.AWSLambda.csproj | 1 + .../.publicApi/PublicAPI.Unshipped.txt | 10 +++++----- .../AWSResourceBuilderOptions.cs | 2 +- .../OpenTelemetry.Resources.AWS.csproj | 1 + src/Shared/AWS/AWSSemanticConventions.Base.cs | 8 +++++++- src/Shared/AWS/AWSSemanticConventions.cs | 13 ++++++++++--- src/Shared/AWS/SemanticConventionVersion.cs | 13 +++++++++++-- .../AWSLambdaInstrumentationOptionsTests.cs | 1 - 13 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt index cd7c7fea99..0638f4cf7e 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.AWS/.publicApi/PublicAPI.Unshipped.txt @@ -1,11 +1,11 @@ #nullable enable -OpenTelemetry.AWS.SemanticConventionVersion -OpenTelemetry.AWS.SemanticConventionVersion.Latest = 0 -> OpenTelemetry.AWS.SemanticConventionVersion -OpenTelemetry.AWS.SemanticConventionVersion.v1_29_0_Experimental = 2 -> OpenTelemetry.AWS.SemanticConventionVersion -OpenTelemetry.AWS.SemanticConventionVersion.v1_27_0_Experimental = 1 -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion +OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion.Latest = 0 -> OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion +OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion.v1_29_0_Experimental = 2 -> OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion +OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion.v1_27_0_Experimental = 1 -> OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.AWSClientInstrumentationOptions() -> void -OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SemanticConventionVersion.get -> OpenTelemetry.AWS.SemanticConventionVersion +OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SemanticConventionVersion.get -> OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SemanticConventionVersion.set -> void OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SuppressDownstreamInstrumentation.get -> bool OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.SuppressDownstreamInstrumentation.set -> void diff --git a/src/OpenTelemetry.Instrumentation.AWS/AWSClientInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.AWS/AWSClientInstrumentationOptions.cs index aaa5bd8d9a..193c65ebcf 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/AWSClientInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.AWS/AWSClientInstrumentationOptions.cs @@ -15,6 +15,6 @@ public class AWSClientInstrumentationOptions /// public bool SuppressDownstreamInstrumentation { get; set; } - /// + /// public SemanticConventionVersion SemanticConventionVersion { get; set; } = AWSSemanticConventions.DefaultSemanticConventionVersion; } diff --git a/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj b/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj index 3c394a43c5..bd2d98653f 100644 --- a/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj +++ b/src/OpenTelemetry.Instrumentation.AWS/OpenTelemetry.Instrumentation.AWS.csproj @@ -6,6 +6,7 @@ $(TargetFrameworks);$(NetFrameworkMinimumSupportedVersion) AWS client instrumentation for OpenTelemetry .NET. Instrumentation.AWS- + INSTRUMENTATION_AWS;$(DefineConstants)