#open-telemetry

telemetry-rust

Open Telemetry fox Axum and Tracing

23 releases (14 stable)

3.4.0 Oct 7, 2024
3.2.0 Aug 12, 2024
3.1.0 May 20, 2024
2.0.0 Mar 14, 2024
0.1.1 Mar 14, 2023

#450 in HTTP server

Download history 37/week @ 2024-07-27 241/week @ 2024-08-03 182/week @ 2024-08-10 16/week @ 2024-08-17 16/week @ 2024-08-24 5/week @ 2024-08-31 6/week @ 2024-09-07 21/week @ 2024-09-14 13/week @ 2024-09-21 33/week @ 2024-09-28 383/week @ 2024-10-05 23/week @ 2024-10-12 17/week @ 2024-10-19 8/week @ 2024-10-26

434 downloads per month

MIT license

71KB
1.5K SLoC

telemetry-rust

use tracing::Level::INFO;
// middleware::axum is available if feature flag axum is on
use telemetry_rust::{
    init_tracing,
    middleware::axum::{OtelAxumLayer, OtelInResponseLayer},
};

#[tracing::instrument]
async fn route_otel() -> impl axum::response::IntoResponse {
    let trace_id =
        telemetry_rust::tracing_opentelemetry_instrumentation_sdk::find_current_trace_id();
    dbg!(&trace_id);
    axum::Json(serde_json::json!({ "trace-id": trace_id }))
}

#[tokio::main]
async fn main() {
    init_tracing!(INFO);

    // ...

    let app = axum::Router::new()
        // request processed inside span
        .route("/otel", axum::routing::get(route_otel))
        // include trace context as header into the response
        .layer(OtelInResponseLayer::default())
        // start OpenTelemetry trace on incoming request
        .layer(OtelAxumLayer::default());

    // ...

AWS SDK instrumentation

AwsInstrumented trait

let res = dynamo_client
    .get_item()
    .table_name("table_name")
    .index_name("my_index")
    .set_key(primary_key)
    .send()
    .instrument(DynamodbSpanBuilder::get_item("table_name"))
    .await;

Low level API

Creating new span:

// create new span in the current span's context using either a dedicated constructor
let aws_span = DynamodbSpanBuilder::get_item("table_name").start();
// or a generic one
let aws_span = AwsSpanBuilder::dynamodb("GetItem", vec!["table_name"]).start();

// optionally, provide an explicit parent context
let context = Span::current().context();
let aws_span = DynamodbSpanBuilder::get_item("table_name").context(&context).start();

// or set custom span attributes
let aws_span = DynamodbSpanBuilder::get_item("table_name")
    .attribute(KeyValue::new(semconv::AWS_DYNAMODB_INDEX_NAME, "my_index"))
    .attributes(vec![
        KeyValue::new(semconv::AWS_DYNAMODB_LIMIT, 6),
        KeyValue::new(semconv::AWS_DYNAMODB_SELECT, "ALL_ATTRIBUTES"),
    ])
    .start();

Ending the span once AWS operation is complete:

let res = dynamo_client
    .get_item()
    .table_name("table_name")
    .index_name("my_index")
    .set_key(primary_key)
    .send()
    .await;
aws_span.end(&res);

Only the following AWS targets are fully supported at the moment:

  • DynamoDB
  • SNS
  • Firehose

But a generic AwsSpanBuilder could be used to instrument any other AWS SDK:

let s3_span = AwsSpanBuilder::client(
    "S3",
    "GetObject",
    vec![KeyValue::new(semconv::AWS_S3_BUCKET, "my_bucket")],
)
.start();

AWS Lambda instrumentation

#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
    // Grab TracerProvider after telemetry initialisation
    let provider = telemetry_rust::init_tracing!(tracing::Level::WARN);

    // Create lambda telemetry layer
    let telemetry_layer = telemetry_rust::middleware::lambda::OtelLambdaLayer::new(provider);

    // Run lambda runtime with telemetry layer
    lambda_runtime::Runtime::new(tower::service_fn(handler))
        .layer(telemetry_layer)
        .run()
        .await?;

    // Shutdown tracer provider before exiting
    telemetry_rust::shutdown_signal();

    Ok(())
}

Publishing new version

New version could be published using cargo-release:

cargo release -x <level>

Dependencies

~16–30MB
~426K SLoC