-
Notifications
You must be signed in to change notification settings - Fork 102
feat: Add OpenTelemetrySpanExt methods for direct span event creation #201
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 OpenTelemetrySpanExt methods for direct span event creation #201
Conversation
Hi @djc (and other maintainers), I'm happy to handle the version bump and finalize the changelog entry if after your review this PR is ready to merge. I wasn't sure about the appropriate version target for this addition, since it's adding new API surface (non-breaking) to a 0.x crate, would you typically target a minor version bump (e.g., 0.31.0) or a patch release (e.g., 0.30.1)? |
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.
This is mostly looking good, thanks!
Please keep the clippy commits separate and squash any additional changes into your original commit (might be easier to reorder them so that the clippy commits come first).
src/span_ext.rs
Outdated
/// | ||
/// app_root.add_otel_span_event("job_completed", vec![KeyValue::new("status", "success")]); | ||
/// ``` | ||
fn add_otel_span_event<T>(&self, name: T, attributes: Vec<KeyValue>) |
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.
Are there other kinds of events in OTel? The name is a little verbose, so would be nice if we can get away with something a bit shorter like add_otel_event()
.
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.
Yes, there's a new WIP spec for OTel Events, as a new signal type. More background about it in here:
- https://github.com/open-telemetry/opentelemetry-specification/blob/main/oteps/0202-events-and-logs-api.md
- https://github.com/open-telemetry/opentelemetry-specification/blob/main/oteps/0265-event-vision.md
- https://github.com/open-telemetry/opentelemetry-specification/blob/main/oteps/4430-span-event-api-deprecation-plan.md
I think though that it's still far away from being widely implemented and adopted, so I am happy with the span events API for now (and I don't necessarily agree that it was a good idea to introduce a new signal type, but that's digressing).
I agree that the name is verbose, but add_otel_event
would then be a little ambiguous when those specs are more widely adopted and known. Alternatively, we could use add_event
(as in the OTel Span trait, in the same way that you have add_link
) and since this is a method of a trait that is meant to "wrap" an OTel span, maybe it would be clear that is not a Tracing event. Let me know your preference and I will update the PR.
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.
Yeah, let's do add_event()
for now -- it seems there will still be sufficient opportunities to make breaking changes should the need arise.
src/span_ext.rs
Outdated
/// | ||
/// app_root.add_otel_span_event("job_completed", vec![KeyValue::new("status", "success")]); | ||
/// ``` | ||
fn add_otel_span_event<T>(&self, name: T, attributes: Vec<KeyValue>) |
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: please use impl trait in arguments consistently where possible, so this should have name: impl Into<Cow<'static, str>>
(everywhere).
examples/opentelemetry-span-event.rs
Outdated
@@ -0,0 +1,65 @@ | |||
use opentelemetry::trace::TracerProvider as _; |
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.
This seems a little niche so I'd prefer to avoid maintaining an example for 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.
Ok I can remove it
src/span_ext.rs
Outdated
if let Some(get_context) = subscriber.downcast_ref::<WithContext>() { | ||
get_context.with_context(subscriber, id, move |data, _tracer| { | ||
if let Some(event) = event.take() { | ||
data.builder.events.get_or_insert_with(Vec::new).push(event); | ||
} | ||
}); | ||
} |
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: I'm aware this is mostly copy/pasting, but please use let-else to reduce rightward drift where possible. (If you want to fix up the original function too, that would be nice, but please keep it in a separate commit.)
CHANGELOG.md
Outdated
- Add `OpenTelemetrySpanExt::add_otel_span_event` function to allow adding OpenTelemetry | ||
events directly to a `tracing::Span`, enabling the use of dynamic attribute keys. | ||
- Add `OpenTelemetrySpanExt::add_otel_span_event_with_timestamp` function, similar to | ||
`add_otel_span_event`, but allowing a specific `SystemTime` to be provided for the event. |
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: I think these changes belong in a single bullet point.
CHANGELOG.md
Outdated
events directly to a `tracing::Span`, enabling the use of dynamic attribute keys. | ||
- Add `OpenTelemetrySpanExt::add_otel_span_event_with_timestamp` function, similar to | ||
`add_otel_span_event`, but allowing a specific `SystemTime` to be provided for the event. | ||
- Add `examples/opentelemetry-span-event.rs` demonstrating the usage of the new span event methods. |
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.
Don't forget to remove this when you remove the example.
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.
will do
Use `.next_back()` instead of `.last()` on a `DoubleEndedIterator` in `tests/metrics_publishing.rs` to satisfy the `clippy::double_ended_iterator_last` lint, which was likely surfaced by CI flags (`-D warnings`) or a toolchain update.
c54ba96
to
f7cc03e
Compare
@djc I think I have addressed all the changes requested. Let me know if you spot something else. |
As mentioned:
Please squash the last two commits ("rename span event methods" and "use impl trait consistently"), which AFAICT only touch new code you have added, into your original commit ("add OpenTelemetrySpanExt methods"). |
Adds `add_event` and `add_event_with_timestamp` methods to the `OpenTelemetrySpanExt` trait. These methods allow users to add OpenTelemetry span events directly to a `tracing::Span`, including events with dynamic attribute keys, bypassing the limitations of the `tracing::event!` macro for such use cases. The signatures use `impl Into<Cow<'static, str>>` for the event name. Includes: - Trait method definitions and implementations. - Corresponding test cases. - Updates to README.md. - Changelog entries. Also incorporates refactoring based on review feedback: - Use let-else patterns to reduce rightward drift. - Rename methods for API simplification (`add_event`). - Use `impl trait` consistently in method parameters. - Remove example file (`examples/opentelemetry-span-event.rs`).
55880e7
to
78e8247
Compare
You actually didn't address my feedback exactly, because you also squashed the refactoring that changed other pre-existing code that you didn't add, so that's a little yucky from a reviewing perspective. However, I don't think it's worth doing another round trip on this, so I'll just merge this. |
Apologies, I misunderstood, I thought you just wanted the clippy fixes separated. I see your point now. |
This PR adds methods to
OpenTelemetrySpanExt
for directly adding OpenTelemetry span events, addressing the limitations of usingtracing::event!
for events with dynamic attributes.Fixes #200
Motivation
As discussed in issue #200, the current
tracing::event!
macro requires attribute keys to be known at compile time. This makes it difficult or impossible to record OpenTelemetry span events with dynamic attributes (e.g., from processing arbitrary JSON payloads) without resorting to lossy serialization, which hinders observability.This change provides a way to directly add
opentelemetry::trace::Event
objects with dynamicVec<KeyValue>
attributes, similar to howset_attribute
allows setting dynamic span attributes. This improves flexibility, makes porting code easier, and aligns better with the capabilities of the OpenTelemetry Span API.Solution
This PR extends the
OpenTelemetrySpanExt
trait with two new methods:add_otel_span_event<T>(&self, name: T, attributes: Vec<KeyValue>) where T: Into<Cow<'static, str>>
: Adds an OpenTelemetry span event with the current timestamp.add_otel_span_event_with_timestamp<T>(&self, name: T, timestamp: SystemTime, attributes: Vec<KeyValue>) where T: Into<Cow<'static, str>>
: Adds an OpenTelemetry span event with a specified timestamp.The implementation uses the existing
with_subscriber
->downcast_ref::<WithContext>
->with_context
pattern found in otherOpenTelemetrySpanExt
methods (set_attribute
,set_status
) to access the internalOtelData
builder and push the event.The name
add_otel_span_event
was chosen overadd_event
to avoid potential confusion with thetracing::event!
macro within the context of this crate.This PR includes:
src/span_ext.rs
.tests/span_ext.rs
.README.md
documentation.examples/opentelemetry-span-event.rs
.CHANGELOG.md
.