-
Notifications
You must be signed in to change notification settings - Fork 16
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
feat: Add OpenTelemetry Instrumentation Provider #68
Conversation
@@ -7,10 +7,13 @@ | |||
</PropertyGroup> | |||
|
|||
<ItemGroup> | |||
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.6.0" /> | |||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.6.0" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OpenTelemetry.Extensions.Hosting
is necessary to use our new AddAWSMessagingInstrumentation
extension method. Should it just be a dependency of our OTel package?
I don't think it's strictly required, see how we're setting up OTel during the unit tests via CreateTracerProviderBuilder()
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is OpenTelemetry.Extensions.Hosting
just something a user is going to have on their application that is doing the OTel configuration? Doesn't look like we have a compile dependency on the package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OpenTelemetry.Extensions.Hosting
enables IServiceCollection.AddOpenTelemetry
, which is necessary to use our AddAWSMessagingInstrumentation
extension that registers our OpenTelemetryProivder
singleton and adds our source name.
But it is not strictly required, since you can also enable OpenTelemetry via CreateTracerProviderBuilder
like we do in the tests. This is brought in via OpenTelemetry
, which is a transitive dependency for the user via our new AWS.Messaging.Telemetry.OpenTelemetry
.
// Alternative to DI, see https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/docs/trace/customizing-the-sdk/README.md#using-sdkcreatetracerproviderbuilder
using (var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource(TelemetryKeys.Source)
.ConfigureResource(resource => resource.AddService("unittest"))
.AddInMemoryExporter(activities).Build())
{
await _publisher.PublishAsync(new ChatMessage { MessageDescription = "Test Description" });
}
So my thinking was that because the user isn't required to configure OTel via DI, we didn't want to require the dependency ourselves. Though on the other hand it is only ~44KB so if we think it'd be more convenient we could require it ourselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets start without it. Easier to add it then remove it.
{ | ||
if (envelope.Metadata.TryGetValue(key, out var value)) | ||
{ | ||
if (value is JsonElement jsonValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Norm's prototype introduced DictionaryStringObjectConverter, which was deserializing these back to strings.
I didn't implement that yet since we'd have to cover a lot of primitive types, so for now both customers and us will have to use JsonElement
and know what type corresponds to which key. Let me know if you'd rather use Norm's approach though.
This also means the else if
is dead code, had left it in from iterating on tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer we do some conversion. It seems confusing to users that in the publish they put in a string or number and then on the subscriber they type has changed. And it feels like we are leaking our serialization logic potentially into user's business code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I attempted to apply the converter like the prototype, but realized via dotnet/runtime#32903 that a custom JsonConverter
cannot deserialize the dictionary attributed with JsonExtensionData
by design.
The prototype was working because it was doing something like this, so that MessageEnvelope.Metadata
was not being treated as overflow via JsonExtensionData
{
"metadata": {
"traceparent": "..."
}
}
But we want the OTel info (and possibly other extensions, set by us internally or users) in the top of the CloudEvents envelope.
We had an internal discussion on 11/9/23 debating:
- Leave deserialization as-is (both us and users will have to work with
JsonElement
values) when handlingMetadata
. We’ll route MPF’s OTel info through this path. - Move the OTel properties to real properties in our
MessageEnvelope<T>
- Simplifies this PR since we're not working with overflow, but not user-provided extensions.
- We also want to avoid any OTel code in the core
AWS.Messaging
package if possible.
- We could use
JsonExtensionData
to initially de-serialize overflow into something likeinternal RawMetadata<string, JsonElement>
and then do our own copy+casting into a separatepublic Metadata<string, object>
.
We agreed to start with approach number 1 for now.
test/AWS.Messaging.UnitTests/SerializationTests/EnvelopeSerializerTests.cs
Show resolved
Hide resolved
@@ -7,10 +7,13 @@ | |||
</PropertyGroup> | |||
|
|||
<ItemGroup> | |||
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.6.0" /> | |||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.6.0" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is OpenTelemetry.Extensions.Hosting
just something a user is going to have on their application that is doing the OTel configuration? Doesn't look like we have a compile dependency on the package.
{ | ||
if (envelope.Metadata.TryGetValue(key, out var value)) | ||
{ | ||
if (value is JsonElement jsonValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer we do some conversion. It seems confusing to users that in the publish they put in a string or number and then on the subscriber they type has changed. And it feels like we are leaking our serialization logic potentially into user's business code.
} | ||
|
||
/// <summary> | ||
/// Extracts propogation context from a <see cref="MessageEnvelope"/>, meant to be used with <see cref="TextMapPropagator"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo in "propogation" should be "propagation"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 7592368
namespace AWS.Messaging.Telemetry.OpenTelemetry; | ||
|
||
/// <summary> | ||
/// An OpenTelemetry trace (wrapper around a <see cref="Activity"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you opened a paranthesis but didn't close it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 7592368
contextToInject = _activity.Context; | ||
} | ||
// Even if an "AWS.Messaging" activity was not created, we still | ||
// propogate the the current activity (if it exists) through the message envelope |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you have 2 "the" in a row.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 7592368
envelope.Metadata[key] = JsonSerializer.SerializeToElement(value); | ||
} | ||
|
||
private bool _disposed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: add a new line between the property and the summary below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 7592368
@@ -362,7 +362,7 @@ public async Task SerializationCallbacks_AreCorrectlyInvoked() | |||
Assert.Equal("1.0", envelope.Version); | |||
Assert.Equal("/aws/messaging", envelope.Source?.ToString()); | |||
Assert.Equal("addressInfo", envelope.MessageTypeIdentifier); | |||
Assert.Equal(true, envelope.Metadata["Is-Delivered"]); | |||
Assert.Equal(true, envelope.Metadata["Is-Delivered"].GetBoolean()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you please resolve the warnings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was taking a small moral stance here, since we weren't really asserting that "some condition is true", rather more like "this piece of data is equal to the value true
".
But updated, not a big deal.
Issue #, if available: DOTNET-7031
Description of changes:
AWS.Messaging.Telemetry.OpenTelemetry
, which instruments the AWS Message Processing Framework for .NET for OpenTelemetryMessageEnvelope.Metadata
as top-level properties in the JSON envelope when sending messages. We're using this to telemetry, but us and customers can use for other CloudEvents extensions and/or custom attributes.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.