Skip to main content

Crate telemetry_batteries

Crate telemetry_batteries 

Source
Expand description

§telemetry-batteries

Batteries-included telemetry for Rust applications. Configure tracing, metrics, and error reporting with a single function call.

§Quick Start

#[tokio::main]
async fn main() -> eyre::Result<()> {
    // Initialize from environment variables
    let _guard = telemetry_batteries::init()?;

    tracing::info!("Hello, telemetry!");

    Ok(())
}

The guard must be kept alive for the duration of your application. When dropped, it gracefully shuts down the telemetry providers.

init() also installs a global panic hook. Panics are logged with tracing::error and structured fields like source, payload_type, location, thread, and backtrace; normal panic unwind/abort behavior is unchanged.

For fatal top-level errors, opt into the same panic path:

use telemetry_batteries::TopLevelResultExt;

#[tokio::main]
async fn main() -> eyre::Result<()> {
    let _guard = telemetry_batteries::init()?;
    run().await.panic_on_top_level_error();
    Ok(())
}

async fn run() -> eyre::Result<()> {
    eyre::bail!("fatal startup error")
}

§Configuration

Configuration is done via environment variables using presets:

§Presets

PresetLog FormatLog OutputSpan ExportUse Case
localprettystdoutnoneLocal development
datadogdatadog_jsonstdoutDatadog AgentProduction with Datadog
none-nonenoneDisable telemetry

§Environment Variables

VariableValuesDefault
TELEMETRY_PRESETlocal, datadog, nonelocal
TELEMETRY_SERVICE_NAMEstringrequired for datadog
RUST_LOG or TELEMETRY_LOG_LEVELEnvFilter syntaxinfo
TELEMETRY_LOG_FORMATpretty, json, compact, datadog_json(from preset)
TELEMETRY_DATADOG_ENDPOINTurlhttp://localhost:8126
TELEMETRY_EYRE_MODEcolor, jsoncolor

§Metrics Configuration

Metrics are configured independently from presets:

VariableValuesDefault
TELEMETRY_METRICS_BACKENDprometheus, statsd, nonenone
TELEMETRY_PROMETHEUS_MODEhttp, pushhttp
TELEMETRY_PROMETHEUS_LISTENaddr:port0.0.0.0:9090
TELEMETRY_PROMETHEUS_ENDPOINTurl-
TELEMETRY_PROMETHEUS_INTERVALseconds10
TELEMETRY_STATSD_HOSTstringlocalhost
TELEMETRY_STATSD_PORTu168125
TELEMETRY_STATSD_PREFIXstring-

§Programmatic Configuration

For more control, use the builder pattern:

use telemetry_batteries::{
    TelemetryConfig, TelemetryPreset, LogFormat,
    MetricsConfig, MetricsBackend, StatsdConfig,
};

#[tokio::main]
async fn main() -> eyre::Result<()> {
    let config = TelemetryConfig::builder()
        .preset(TelemetryPreset::Datadog)
        .service_name("my-service".to_owned())
        .log_format(LogFormat::Pretty)  // Override preset's log format
        .metrics(MetricsConfig::builder()
            .backend(MetricsBackend::Statsd)
            .statsd(StatsdConfig::builder()
                .host("localhost".to_owned())
                .port(8125)
                .build())
            .build())
        .build();

    let _guard = telemetry_batteries::init_with_config(config)?;

    tracing::info!("Configured programmatically!");

    Ok(())
}

§Usage Examples

# Local development - pretty logs, no tracing
cargo run

# Datadog production
TELEMETRY_PRESET=datadog TELEMETRY_SERVICE_NAME=my-service cargo run

# Datadog with pretty logs for debugging
TELEMETRY_PRESET=datadog TELEMETRY_SERVICE_NAME=my-service TELEMETRY_LOG_FORMAT=pretty cargo run

# With Prometheus metrics
TELEMETRY_METRICS_BACKEND=prometheus cargo run

§Distributed Tracing

For distributed tracing with Axum, enable the axum feature:

telemetry-batteries = { version = "0.4", features = ["axum"] }

Then use the route-aware constructor:

use axum::{routing::get, Router};
use telemetry_batteries::tracing::middleware::TraceLayer;

let app = Router::new()
    .route("/", get(handler))
    .layer(TraceLayer::new_for_axum());

The middleware automatically:

  • Creates a span for each request
  • Names the span from the HTTP method and matched route template
  • Records the matched route as http.route
  • Extracts trace context from incoming headers (e.g., traceparent)
  • Injects trace context into response headers

Use TraceLayer::new() for framework-neutral Tower services. A custom low-cardinality route template can be supplied with with_route_extractor.

Custom span creation:

use telemetry_batteries::tracing::middleware::TraceLayer;
use tracing::info_span;

let layer = TraceLayer::new().with_make_span(|req| {
    info_span!(
        "http_request",
        method = %req.method(),
        path = %req.uri().path(),
    )
});

§Outgoing requests

Inject the current span’s trace context into an individual reqwest request:

use telemetry_batteries::tracing::reqwest::RequestBuilderExt;

let response = reqwest::Client::new()
    .get("https://example.com")
    .inject_trace_context()
    .send()
    .await?;

For reqwest-middleware, enable the reqwest-middleware feature and attach TraceContextMiddleware once to the client:

use telemetry_batteries::tracing::reqwest::middleware::TraceContextMiddleware;

let client = reqwest_middleware::ClientBuilder::new(reqwest::Client::new())
    .with(TraceContextMiddleware::new())
    .build();

This integration propagates the current context but does not create client spans.

§Cargo Features

FeatureDefaultDescription
axumNoRoute-aware server tracing for Axum applications
metrics-prometheusYesPrometheus metrics exporter
metrics-statsdYesStatsD metrics exporter
reqwest-middlewareNoAutomatic outgoing trace-context propagation for reqwest-middleware clients
rustlsYesTLS via rustls
native-tlsNoTLS via native-tls

§Examples

See the examples directory:

  • basic.rs - Minimal setup with environment variables
  • axum_tracing.rs - Axum server with distributed trace propagation

Run the examples:

# Basic example with local preset
cargo run --example basic

# Basic example with Datadog
TELEMETRY_PRESET=datadog TELEMETRY_SERVICE_NAME=test cargo run --example basic

# Axum server with trace propagation
TELEMETRY_PRESET=datadog TELEMETRY_SERVICE_NAME=my-api cargo run --features axum --example axum_tracing

§License

Unless otherwise specified, all code in this repository is dual-licensed under either:

at your option. This means you may select the license you prefer to use.

Any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Re-exports§

pub use config::LogFormat;
pub use config::MetricsBackend;
pub use config::MetricsConfig;
pub use config::PrometheusConfig;
pub use config::PrometheusMode;
pub use config::StatsdConfig;
pub use config::TelemetryConfig;
pub use config::TelemetryPreset;
pub use opentelemetry;
pub use tracing_opentelemetry;

Modules§

config
Configuration types for telemetry initialization.
reexports
Reexports of crates that appear in the public API.
tracing

Structs§

TelemetryGuard
Guard that ensures telemetry is properly shut down when dropped.

Traits§

TopLevelResultExt
Extension trait for turning fatal top-level Result errors into panics.

Functions§

init
Initialize telemetry from environment variables.
init_with_config
Initialize telemetry with the given configuration.