Creates a connection from an Axum server to a Honeycomb collector.
The following environment variables are used:
OTEL_EXPORTER_OTLP_ENDPOINTcontains the endpoint for Honeycomb - could behttps://api.eu1.honeycomb.io/OTEL_EXPORTER_OTLP_HEADERScontains the headers for the Honeycomb endpoint should havex-honeycomb-teamOTEL_SERVICE_NAMEcontains the service name.
All are required but the first two can be copied from the Send data page in Honeycomb.
Do the following to add the crates to your Cargo.toml:
cargo add axum-otlp-honeycomb --git https://github.com/adaptdk/axum-otlp-honeycomb.git
cargo add clap --features cargo
Where you create your tracing_subscriber do this:
use axum_otlp_honeycomb::{init_otlp_layer, init_otlp_log_layer};
use tracing::level_filters::LevelFilter;
use tracing_subscriber::filter::EnvFilter;
use tracing_subscriber::prelude::*;
use std::env;
...
// Set the service-name to the crates name from Cargo.toml, allow override
// from environment variable
env::set_var(
"OTEL_SERVICE_NAME",
env::var("OTEL_SERVICE_NAME").unwrap_or(clap::crate_name!().to_string()),
);
// Default the Honeycomb endpoint to EU, allow override from environment
// variable
env::set_var(
"OTEL_EXPORTER_OTLP_ENDPOINT",
env::var("OTEL_EXPORTER_OTLP_ENDPOINT")
.unwrap_or("https://api.eu1.honeycomb.io/".to_string()),
);
// Collect 1% of traces on production, all traces elsewhere:
let sample_rate = if branch == "main" { 0.01 } else { 1.0 };
tracing_subscriber::Registry::default()
.with(
tracing_subscriber::fmt::layer()
.with_ansi(false)
.with_filter(EnvFilter::from_default_env()),
)
.with(init_otlp_layer(sample_rate).with_filter(LevelFilter::INFO))
.with(init_otlp_log_layer().with_filter(LevelFilter::INFO))
.init();
The first .with is for local logging to eg Platform.sh's app.log. The log-level
is set by the RUST_LOG environment variable.
The second .with is for tracing to Honeycomb. LevelFilter::INFO ensures that tracing
done with #[tracing::instrument] is forwarded. Logging with LevelFilter::DEBUG gives
traces for just too much.
The third .with is for forwarding events to Honeycomb's Logs. Again the LevelFilter::WARN
ensures that only relevant events are forwarded.
NOTE: Any event field named body will overwrite the event message.
In your app add this:
use axum_otlp_honeycomb::{opentelemetry_tracing_layer};
...
let app = Router::new()
...
.layer(opentelemetry_tracing_layer());
or, if you don't want to extract the parent context:
.layer(opentelemetry_tracing_layer_without_parent());
In the traces sent to Honeycomb the following headers will be removed:
- authorization
- cookie
- and any header whose name contains 'token'
Also a field user.id is created in the root-span, to allow authorization code to
record the user-id by eg:
let user_ud = get_current_user_id();
Span::current().record("user.id", user_id);
Note that the current span needs to be the root span for the server
otherwise the record() call will fail silently.
This is done using the reqwest-tracing crate:
cargo add reqwest-tracing
cargo add reqwest-middleware --features json
And then you add the middleware-layer to the reqwest-client:
Change:
let client: Client = Client::builder()
...
build()?;
to:
let reqwest_client: Client = Client::builder()
...
build()?;
let client = reqwest_middleware::ClientBuilder::new(reqwest_client)
.with(tracing_middleware)
.build();
And change all occurencies of Client to ClientWithMiddleware and
of reqwest::Client to reqwest_middleware::ClientWithMiddleware.
Trace propagation does not work at the moment. This is a work in progress.