-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adding support for setting the status of the span through SpanExt (#176)
## Motivation I have found that when working with `tracing` spans created by 3rd party libraries, it is incredibly difficult to set the OpenTelemetry Status of the span, which results in always having an unset span in my visualization tool. <img width="623" alt="image" src="https://github.com/user-attachments/assets/7acaf443-3d7b-40b4-80c3-3c2d588679d1"> In this case, I am working with the span created by the `aws_lambda_runtime` [crate](https://github.com/awslabs/aws-lambda-rust-runtime/blob/main/lambda-runtime/src/layers/otel.rs#L75). Unfortunately, since the span in the `aws_lambda_runtime` crate does not include the `otel.status_code` attribute upfront the `OpenTelemetryLayer::SpanAttributeVisitor::record_str` and `OpenTelemetryLayer::SpanAttributeVisitor::record_debug` never gets triggered when calling `tracing::Span::current().record("otel.status_code", "ok");` This behavior of the `record` function ignoring new fields is documented [here](https://docs.rs/tracing/latest/tracing/struct.Span.html#method.record) ## Solution My solution to this is add a new member `OpenTelemetrySpanExt::set_status` that takes an `opentelemetry::trace::Status` enum that gets written to the underlying `SpanBuilder`.
- Loading branch information
1 parent
515fe00
commit ab629c3
Showing
2 changed files
with
107 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
use futures_util::future::BoxFuture; | ||
use opentelemetry::trace::{Status, TracerProvider as _}; | ||
use opentelemetry_sdk::{ | ||
export::trace::{ExportResult, SpanData, SpanExporter}, | ||
trace::{Tracer, TracerProvider}, | ||
}; | ||
use std::sync::{Arc, Mutex}; | ||
use tracing::level_filters::LevelFilter; | ||
use tracing::Subscriber; | ||
use tracing_opentelemetry::{layer, OpenTelemetrySpanExt}; | ||
use tracing_subscriber::prelude::*; | ||
|
||
#[derive(Clone, Default, Debug)] | ||
struct TestExporter(Arc<Mutex<Vec<SpanData>>>); | ||
|
||
impl SpanExporter for TestExporter { | ||
fn export(&mut self, mut batch: Vec<SpanData>) -> BoxFuture<'static, ExportResult> { | ||
let spans = self.0.clone(); | ||
Box::pin(async move { | ||
if let Ok(mut inner) = spans.lock() { | ||
inner.append(&mut batch); | ||
} | ||
Ok(()) | ||
}) | ||
} | ||
} | ||
|
||
fn test_tracer() -> (Tracer, TracerProvider, TestExporter, impl Subscriber) { | ||
let exporter = TestExporter::default(); | ||
let provider = TracerProvider::builder() | ||
.with_simple_exporter(exporter.clone()) | ||
.build(); | ||
let tracer = provider.tracer("test"); | ||
|
||
let subscriber = tracing_subscriber::registry() | ||
.with( | ||
layer() | ||
.with_tracer(tracer.clone()) | ||
.with_filter(LevelFilter::DEBUG), | ||
) | ||
.with(tracing_subscriber::fmt::layer().with_filter(LevelFilter::TRACE)); | ||
|
||
(tracer, provider, exporter, subscriber) | ||
} | ||
|
||
#[test] | ||
fn set_status_ok() { | ||
let root_span = set_status_helper(Status::Ok); | ||
assert_eq!(Status::Ok, root_span.status); | ||
} | ||
|
||
#[test] | ||
fn set_status_error() { | ||
let expected_error = Status::Error { | ||
description: std::borrow::Cow::Borrowed("Elon put in too much fuel in his rocket!"), | ||
}; | ||
let root_span = set_status_helper(expected_error.clone()); | ||
assert_eq!(expected_error, root_span.status); | ||
} | ||
|
||
fn set_status_helper(status: Status) -> SpanData { | ||
let (_tracer, provider, exporter, subscriber) = test_tracer(); | ||
|
||
tracing::subscriber::with_default(subscriber, || { | ||
let root = tracing::debug_span!("root").entered(); | ||
|
||
root.set_status(status); | ||
}); | ||
|
||
drop(provider); // flush all spans | ||
let spans = exporter.0.lock().unwrap(); | ||
|
||
assert_eq!(spans.len(), 1); | ||
|
||
spans.iter().find(|s| s.name == "root").unwrap().clone() | ||
} |