Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade Semantic Convention handling in AWS libraries. #2367

Merged
merged 35 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0d5c59b
upgrade semantic convention
ppittle Oct 18, 2024
4e8d265
Use a builder pattern for resource attributes
ppittle Nov 5, 2024
59a6a9f
improve documentation
ppittle Dec 3, 2024
67c2b03
inline attribute strings and update obsolete attributes
ppittle Dec 3, 2024
d248279
Alternate strategy to simplify implementation
ppittle Dec 4, 2024
7658b78
renamed files to reflect decision to user simpler model for managing …
ppittle Dec 5, 2024
928f4f1
move the upgrade of AttributeHttpTarget to a new PR as this will requ…
ppittle Dec 5, 2024
b52cbc5
add new unit tests for SemanticConventionVersion switching
ppittle Dec 5, 2024
749f5dd
update AWS Lambda tests to use Semantic Convention 1.29
ppittle Dec 5, 2024
0c091f2
remove obsolete code
ppittle Dec 6, 2024
5204ab7
Update SetTag to be a no-op if attribute name is null or empty
ppittle Dec 6, 2024
a7be302
Update documentation and add documentation to README files
ppittle Dec 6, 2024
db38b54
run dotnet format
ppittle Dec 6, 2024
bc32e39
fix minor issues found by unit tests
ppittle Dec 7, 2024
31700b8
Update Instrumentation.AWS.Tests to use Semantic Convention 1.29
ppittle Dec 7, 2024
bb6315a
Change SemanticConventionVersion to track Semantic Convention versions
ppittle Dec 6, 2024
62e75e8
move depreication of AttributeHttpTarget to new PR
ppittle Dec 7, 2024
0387cb2
implement AttirbuteHttpTarget
ppittle Dec 7, 2024
071f0b3
update AWS Lambda tests to use Semantic Convention 1.29
ppittle Dec 7, 2024
f180dd2
change whitespace to improve readability
ppittle Dec 9, 2024
b7b251b
rebase change semnatic versions to track
ppittle Dec 10, 2024
2bc2930
adjust strategy to list attributes as obsolete and add additional Add…
ppittle Dec 10, 2024
82bae2a
change SemenaticCvonentionVersion strategy to pin to v1.27 - the curr…
ppittle Dec 10, 2024
0eb9e87
SemanticConventionsVersion is public in multiple repositories and so…
ppittle Dec 10, 2024
da6c620
run dotnet format
ppittle Dec 10, 2024
1a1f9d9
change AWSemanticConventions from a static to instances to improve te…
ppittle Dec 10, 2024
fc58a67
Update src/OpenTelemetry.Instrumentation.AWS/README.md
ppittle Dec 12, 2024
de586e4
Update changelog
ppittle Dec 13, 2024
671dfbf
change casing of
ppittle Dec 13, 2024
42a6d0a
inline documentation from opentelemetry.semanticconventions and remov…
ppittle Dec 13, 2024
d72c650
Update libraries to impelement Semantic Convention 1.28 and 1.29
ppittle Dec 17, 2024
abad591
no longer include common SemanticConventions file
ppittle Dec 19, 2024
189e873
drop the suffix expiremental in enum values and instead metnion exper…
ppittle Dec 19, 2024
d70a0c5
change strategy - beta version will default to Legacy (ie no change i…
ppittle Dec 19, 2024
8d75bfd
Update src/OpenTelemetry.Instrumentation.AWS/CHANGELOG.md
ppittle Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#nullable enable
OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion
OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion.Legacy = -1 -> OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion
OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion.Latest = 0 -> OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion
OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion.V1_29_0 = 2 -> OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion
OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion.V1_28_0 = 1 -> OpenTelemetry.Instrumentation.AWS.SemanticConventionVersion
OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions
OpenTelemetry.Instrumentation.AWS.AWSClientInstrumentationOptions.AWSClientInstrumentationOptions() -> void
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
OpenTelemetry.Trace.TracerProviderBuilderExtensions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using OpenTelemetry.AWS;

namespace OpenTelemetry.Instrumentation.AWS;

/// <summary>
Expand All @@ -12,4 +14,7 @@ public class AWSClientInstrumentationOptions
/// Gets or sets a value indicating whether downstream instrumentation is suppressed.
/// </summary>
public bool SuppressDownstreamInstrumentation { get; set; }

/// <inheritdoc cref="AWS.SemanticConventionVersion"/>
public SemanticConventionVersion SemanticConventionVersion { get; set; } = AWSSemanticConventions.DefaultSemanticConventionVersion;
}
8 changes: 8 additions & 0 deletions src/OpenTelemetry.Instrumentation.AWS/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## Unreleased

* Introduce `AWSClientInstrumentationOptions.SemanticConventionVersion` which
provides a mechanism for developers to opt-in to newer versions of the
of the OpenTelemetry Semantic Conventions. Currently, you need to opt-in
to these new conventions. In the upcoming stable release of this library,
the new conventions will be enabled by default, and the conventions this library
currently emit will no longer be supported.
([#2367](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2367))

## 1.10.0-beta.2

Released 2024-Dec-12
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,28 @@
// SPDX-License-Identifier: Apache-2.0

using Amazon.Runtime;
using OpenTelemetry.AWS;

namespace OpenTelemetry.Instrumentation.AWS.Implementation;

internal class AWSServiceHelper
{
internal static IReadOnlyDictionary<string, List<string>> ServiceRequestParameterMap = new Dictionary<string, List<string>>()
public AWSServiceHelper(AWSSemanticConventions semanticConventions)
{
this.ParameterAttributeMap =
semanticConventions
.ParameterMappingBuilder
.AddAttributeAWSDynamoTableName("TableName")
.AddAttributeAWSSQSQueueUrl("QueueUrl")
.AddAttributeGenAiModelId("ModelId")
.AddAttributeAWSBedrockAgentId("AgentId")
.AddAttributeAWSBedrockDataSourceId("DataSourceId")
.AddAttributeAWSBedrockGuardrailId("GuardrailId")
.AddAttributeAWSBedrockKnowledgeBaseId("KnowledgeBaseId")
.Build();
}

internal static IReadOnlyDictionary<string, List<string>> ServiceRequestParameterMap { get; } = new Dictionary<string, List<string>>()
{
{ AWSServiceType.DynamoDbService, ["TableName"] },
{ AWSServiceType.SQSService, ["QueueUrl"] },
Expand All @@ -16,25 +32,14 @@ internal class AWSServiceHelper
{ AWSServiceType.BedrockRuntimeService, ["ModelId"] },
};

internal static IReadOnlyDictionary<string, List<string>> ServiceResponseParameterMap = new Dictionary<string, List<string>>()
internal static IReadOnlyDictionary<string, List<string>> ServiceResponseParameterMap { get; } = new Dictionary<string, List<string>>()
{
{ AWSServiceType.BedrockService, ["GuardrailId"] },
{ AWSServiceType.BedrockAgentService, ["AgentId", "DataSourceId"] },
};

internal static IReadOnlyDictionary<string, string> ParameterAttributeMap = new Dictionary<string, string>()
{
{ "TableName", AWSSemanticConventions.AttributeAWSDynamoTableName },
{ "QueueUrl", AWSSemanticConventions.AttributeAWSSQSQueueUrl },
{ "ModelId", AWSSemanticConventions.AttributeGenAiModelId },
{ "AgentId", AWSSemanticConventions.AttributeAWSBedrockAgentId },
{ "DataSourceId", AWSSemanticConventions.AttributeAWSBedrockDataSourceId },
{ "GuardrailId", AWSSemanticConventions.AttributeAWSBedrockGuardrailId },
{ "KnowledgeBaseId", AWSSemanticConventions.AttributeAWSBedrockKnowledgeBaseId },
};

// for Bedrock Agent operations, we map each supported operation to one resource: Agent, DataSource, or KnowledgeBase
internal static List<string> BedrockAgentAgentOps =
internal static List<string> BedrockAgentAgentOps { get; } =
[
"CreateAgentActionGroup",
"CreateAgentAlias",
Expand All @@ -56,7 +61,7 @@ internal class AWSServiceHelper
"UpdateAgent"
];

internal static List<string> BedrockAgentKnowledgeBaseOps =
internal static List<string> BedrockAgentKnowledgeBaseOps { get; } =
[
"AssociateAgentKnowledgeBase",
"CreateDataSource",
Expand All @@ -68,13 +73,15 @@ internal class AWSServiceHelper
"UpdateAgentKnowledgeBase"
];

internal static List<string> BedrockAgentDataSourceOps =
internal static List<string> BedrockAgentDataSourceOps { get; } =
[
"DeleteDataSource",
"GetDataSource",
"UpdateDataSource"
];

internal IDictionary<string, string> ParameterAttributeMap { get; }

internal static IReadOnlyDictionary<string, string> OperationNameToResourceMap()
{
var operationClassMap = new Dictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ namespace OpenTelemetry.Instrumentation.AWS.Implementation;
/// </summary>
internal class AWSTracingPipelineCustomizer : IRuntimePipelineCustomizer
{
public const string UniqueName = "AWS Tracing Registration Customization";

private readonly AWSClientInstrumentationOptions options;

public AWSTracingPipelineCustomizer(AWSClientInstrumentationOptions options)
{
this.options = options;
}

public string UniqueName => "AWS Tracing Registration Customization";
string IRuntimePipelineCustomizer.UniqueName => UniqueName;

public void Customize(Type serviceClientType, RuntimePipeline pipeline)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
using Amazon.Runtime;
using Amazon.Runtime.Internal;
using Amazon.Runtime.Telemetry;
using OpenTelemetry.AWS;
using OpenTelemetry.Context.Propagation;
using OpenTelemetry.Trace;

namespace OpenTelemetry.Instrumentation.AWS.Implementation;

Expand All @@ -19,25 +19,29 @@ namespace OpenTelemetry.Instrumentation.AWS.Implementation;
internal sealed class AWSTracingPipelineHandler : PipelineHandler
{
private readonly AWSClientInstrumentationOptions options;
private readonly AWSSemanticConventions awsSemanticConventions;
private readonly AWSServiceHelper awsServiceHelper;

public AWSTracingPipelineHandler(AWSClientInstrumentationOptions options)
{
this.options = options;
this.awsSemanticConventions = new AWSSemanticConventions(options.SemanticConventionVersion);
this.awsServiceHelper = new AWSServiceHelper(this.awsSemanticConventions);
}

public override void InvokeSync(IExecutionContext executionContext)
{
var activity = this.ProcessBeginRequest(executionContext);
base.InvokeSync(executionContext);
ProcessEndRequest(activity, executionContext);
this.ProcessEndRequest(activity, executionContext);
}

public override async Task<T> InvokeAsync<T>(IExecutionContext executionContext)
{
var activity = this.ProcessBeginRequest(executionContext);
var ret = await base.InvokeAsync<T>(executionContext).ConfigureAwait(false);

ProcessEndRequest(activity, executionContext);
this.ProcessEndRequest(activity, executionContext);

return ret;
}
Expand All @@ -48,7 +52,7 @@ public override async Task<T> InvokeAsync<T>(IExecutionContext executionContext)
"IL2075",
Justification = "The reflected properties were already used by the AWS SDK's marshallers so the properties could not have been trimmed.")]
#endif
private static void AddResponseSpecificInformation(Activity activity, IExecutionContext executionContext)
private void AddResponseSpecificInformation(Activity activity, IExecutionContext executionContext)
{
var service = executionContext.RequestContext.ServiceMetaData.ServiceId;
var responseContext = executionContext.ResponseContext;
Expand All @@ -67,14 +71,14 @@ private static void AddResponseSpecificInformation(Activity activity, IExecution
var operationName = Utils.RemoveSuffix(response.GetType().Name, "Response");
if (AWSServiceHelper.OperationNameToResourceMap()[operationName] == parameter)
{
AddBedrockAgentResponseAttribute(activity, response, parameter);
this.AddBedrockAgentResponseAttribute(activity, response, parameter);
}
}

var property = response.GetType().GetProperty(parameter);
if (property != null)
{
if (AWSServiceHelper.ParameterAttributeMap.TryGetValue(parameter, out var attribute))
if (this.awsServiceHelper.ParameterAttributeMap.TryGetValue(parameter, out var attribute))
{
activity.SetTag(attribute, property.GetValue(response));
}
Expand All @@ -95,7 +99,7 @@ private static void AddResponseSpecificInformation(Activity activity, IExecution
"IL2075",
Justification = "The reflected properties were already used by the AWS SDK's marshallers so the properties could not have been trimmed.")]
#endif
private static void AddBedrockAgentResponseAttribute(Activity activity, AmazonWebServiceResponse response, string parameter)
private void AddBedrockAgentResponseAttribute(Activity activity, AmazonWebServiceResponse response, string parameter)
{
var responseObject = response.GetType().GetProperty(Utils.RemoveSuffix(parameter, "Id"));
if (responseObject != null)
Expand All @@ -106,7 +110,7 @@ private static void AddBedrockAgentResponseAttribute(Activity activity, AmazonWe
var property = attributeObject.GetType().GetProperty(parameter);
if (property != null)
{
if (AWSServiceHelper.ParameterAttributeMap.TryGetValue(parameter, out var attribute))
if (this.awsServiceHelper.ParameterAttributeMap.TryGetValue(parameter, out var attribute))
{
activity.SetTag(attribute, property.GetValue(attributeObject));
}
Expand All @@ -121,7 +125,7 @@ private static void AddBedrockAgentResponseAttribute(Activity activity, AmazonWe
"IL2075",
Justification = "The reflected properties were already used by the AWS SDK's marshallers so the properties could not have been trimmed.")]
#endif
private static void AddRequestSpecificInformation(Activity activity, IRequestContext requestContext)
private void AddRequestSpecificInformation(Activity activity, IRequestContext requestContext)
{
var service = requestContext.ServiceMetaData.ServiceId;

Expand All @@ -145,7 +149,7 @@ private static void AddRequestSpecificInformation(Activity activity, IRequestCon
var property = request.GetType().GetProperty(parameter);
if (property != null)
{
if (AWSServiceHelper.ParameterAttributeMap.TryGetValue(parameter, out var attribute))
if (this.awsServiceHelper.ParameterAttributeMap.TryGetValue(parameter, out var attribute))
{
activity.SetTag(attribute, property.GetValue(request));
}
Expand All @@ -161,7 +165,7 @@ private static void AddRequestSpecificInformation(Activity activity, IRequestCon

if (AWSServiceType.IsDynamoDbService(service))
{
activity.SetTag(SemanticConventions.AttributeDbSystem, AWSSemanticConventions.AttributeValueDynamoDb);
this.awsSemanticConventions.TagBuilder.SetTagAttributeDbSystemToDynamoDb(activity);
}
else if (AWSServiceType.IsSqsService(service))
{
Expand All @@ -175,18 +179,18 @@ private static void AddRequestSpecificInformation(Activity activity, IRequestCon
}
else if (AWSServiceType.IsBedrockRuntimeService(service))
{
activity.SetTag(AWSSemanticConventions.AttributeGenAiSystem, AWSSemanticConventions.AttributeAWSBedrock);
this.awsSemanticConventions.TagBuilder.SetTagAttributeGenAiSystemToBedrock(activity);
}
}

private static void ProcessEndRequest(Activity? activity, IExecutionContext executionContext)
private void ProcessEndRequest(Activity? activity, IExecutionContext executionContext)
{
if (activity == null || !activity.IsAllDataRequested)
{
return;
}

AddResponseSpecificInformation(activity, executionContext);
this.AddResponseSpecificInformation(activity, executionContext);
}

private Activity? ProcessBeginRequest(IExecutionContext executionContext)
Expand All @@ -205,7 +209,7 @@ private static void ProcessEndRequest(Activity? activity, IExecutionContext exec
return null;
}

AddRequestSpecificInformation(currentActivity, executionContext.RequestContext);
this.AddRequestSpecificInformation(currentActivity, executionContext.RequestContext);
return currentActivity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<TargetFrameworks Condition="$(OS) == 'Windows_NT'">$(TargetFrameworks);$(NetFrameworkMinimumSupportedVersion)</TargetFrameworks>
<Description>AWS client instrumentation for OpenTelemetry .NET.</Description>
<MinVerTagPrefix>Instrumentation.AWS-</MinVerTagPrefix>
<DefineConstants>INSTRUMENTATION_AWS;$(DefineConstants)</DefineConstants>
</PropertyGroup>

<!-- Do not run Package Baseline Validation as this package has never released a stable version.
Expand All @@ -25,9 +26,9 @@
</ItemGroup>

<ItemGroup>
<Compile Include="$(RepoRoot)\src\Shared\AWS\*.cs" Link="Includes\AWS\%(Filename).cs" />
<Compile Include="$(RepoRoot)\src\Shared\AssemblyVersionExtensions.cs" Link="Includes\AssemblyVersionExtensions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
<Compile Include="$(RepoRoot)\src\Shared\SemanticConventions.cs" Link="Includes\SemanticConventions.cs" />
</ItemGroup>

</Project>
45 changes: 45 additions & 0 deletions src/OpenTelemetry.Instrumentation.AWS/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,48 @@ public void ConfigureServices(IServiceCollection services)
.AddOtlpExporter());
}
```

## Semantic Conventions

_For an overview on Semantic Conventions, see
[OpenTelemetery - 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
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.

The default will remain as `V1_28_0` 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;
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_29_0;
});
}
```

**NOTE:** Once a Semantic Convention becomes Stable, OpenTelemetry.*.AWS
libraries will remain on that version until the
next major version bump.
Loading
Loading