### Install Logfire Rust SDK Source: https://context7.com/pydantic/logfire-rust/llms.txt Add the logfire crate to your project's Cargo.toml file to include the SDK. Ensure the LOGFIRE_TOKEN environment variable is set with your write token from the Logfire dashboard for authentication. ```toml [dependencies] logfire = "0.9" ``` -------------------------------- ### Rust: Create and Record Metrics with Logfire Source: https://context7.com/pydantic/logfire-rust/llms.txt Demonstrates how to define and record various types of metrics (counters, gauges, histograms, and exponential histograms) using static variables for performance. It includes examples of initializing metrics with descriptions and units, and recording observations with attributes. Also shows how to use observable gauges with callbacks. ```rust use std::sync::LazyLock; use opentelemetry::{KeyValue, metrics::Counter}; // Define metrics as statics - initialized once, used throughout application static REQUEST_COUNTER: LazyLock> = LazyLock::new(|| { logfire::u64_counter("http_requests_total") .with_description("Total number of HTTP requests") .with_unit("{request}") .build() }); static RESPONSE_TIME: LazyLock> = LazyLock::new(|| { logfire::f64_histogram("http_response_time_seconds") .with_description("HTTP response time in seconds") .with_unit("s") .build() }); static ACTIVE_CONNECTIONS: LazyLock> = LazyLock::new(|| { logfire::i64_gauge("active_connections") .with_description("Number of active connections") .build() }); // Exponential histogram for high-resolution latency tracking static LATENCY_HISTOGRAM: LazyLock> = LazyLock::new(|| { logfire::f64_exponential_histogram("request_latency_ms", 20) // scale parameter .with_description("Request latency with exponential bucketing") .with_unit("ms") .build() }); fn main() -> Result<(), Box> { let logfire = logfire::configure() .with_metrics(Some(logfire::config::MetricsOptions::default())) .finish()?; let _guard = logfire.shutdown_guard(); // Record counter with labels/attributes REQUEST_COUNTER.add(1, &[ KeyValue::new("method", "GET"), KeyValue::new("path", "/api/users"), KeyValue::new("status_code", 200), ]); // Record histogram observation RESPONSE_TIME.record(0.045, &[ KeyValue::new("endpoint", "/api/users"), ]); // Record gauge value ACTIVE_CONNECTIONS.record(42, &[]); // Record to exponential histogram LATENCY_HISTOGRAM.record(23.5, &[ KeyValue::new("service", "auth"), ]); // Observable metrics with callbacks static OBSERVABLE_GAUGE: LazyLock> = LazyLock::new(|| { logfire::u64_observable_gauge("system_memory_bytes") .with_description("System memory usage") .with_unit("By") .with_callback(|gauge| { // Called periodically by the metrics runtime gauge.observe(1024 * 1024 * 512, &[]); // 512 MB }) .build() }); LazyLock::force(&OBSERVABLE_GAUGE); Ok(()) } ``` -------------------------------- ### Integrate Logfire Tracing Layer with Existing Subscribers (Rust) Source: https://context7.com/pydantic/logfire-rust/llms.txt Demonstrates how to use Logfire as a tracing layer within a `tracing-subscriber` setup. This allows for gradual adoption or custom configurations by combining Logfire's layer with other standard formatting or filtering layers. The SDK automatically handles global state or local configuration based on the `local()` setting. ```rust use tracing_subscriber::prelude::*; use tracing::level_filters::LevelFilter; fn main() -> Result<(), Box> { // Configure logfire in local mode (doesn't set global state) let logfire = logfire::configure() .local() .finish()?; // Keep shutdown guard for clean shutdown on panics let _guard = logfire.clone().shutdown_guard(); // Create subscriber with logfire layer and other layers let subscriber = tracing_subscriber::registry() .with(logfire.tracing_layer()) .with(tracing_subscriber::fmt::layer() .with_filter(LevelFilter::DEBUG)); // Set as global default tracing::subscriber::set_global_default(subscriber)?; // Now both tracing macros and logfire macros work tracing::info!("Captured by logfire via tracing"); logfire::info!("Direct logfire log"); let span = tracing::info_span!("tracing_span", field = "value"); let _guard = span.enter(); tracing::info!("Inside tracing span"); logfire.shutdown()?; Ok(()) } ``` -------------------------------- ### Instrument Actix-web with Logfire Source: https://context7.com/pydantic/logfire-rust/llms.txt Integrates Logfire with the Actix-web framework to provide OpenTelemetry tracing and metrics middleware. It uses `opentelemetry_instrumentation_actix_web` for both request tracing and metrics. The example shows a basic Actix-web server with a route to retrieve user information, demonstrating the application of tracing and metrics middleware. ```rust use actix_web::{web, App, HttpServer, HttpResponse}; use opentelemetry_instrumentation_actix_web::{RequestMetrics, RequestTracing}; use tracing::Instrument; async fn get_user(path: web::Path) -> HttpResponse { let user_id = path.into_inner(); async { logfire::info!("Fetching user {user_id}"); tokio::time::sleep(std::time::Duration::from_millis(10)) .instrument(logfire::span!("Database lookup")) .await; HttpResponse::Ok().json(serde_json::json!({ "id": user_id, "name": format!("User {user_id}") })) } .instrument(logfire::span!("Get user {user_id}", user_id = user_id)) .await } #[actix_web::main] async fn main() -> Result<(), Box> { let logfire = logfire::configure() .with_metrics(Some(logfire::config::MetricsOptions::default())) .finish()?; let _guard = logfire.shutdown_guard(); logfire::info!("Starting Actix-web server"); HttpServer::new(|| { App::new() .wrap(RequestTracing::new()) // Automatic request tracing .wrap(RequestMetrics::default()) // HTTP metrics .route("/users/{id}", web::get().to(get_user)) }) .bind("127.0.0.1:3000")? .run() .await?; Ok(()) } ``` -------------------------------- ### Instrument Rust Code with Logfire Spans and Info Logs Source: https://github.com/pydantic/logfire-rust/blob/main/README.md This Rust code demonstrates how to configure the Logfire SDK, install a panic handler, and instrument code with spans and info logs. It counts the size of files in the current directory, creating spans for the overall operation and each file read. The `logfire::configure().install_panic_handler().finish()?` line initializes the SDK and sets up a panic handler. `logfire::span!(...)` creates timed spans, and `logfire::info!(...)` sends informational messages. The `shutdown_handler.shutdown()?` ensures all buffered logs are sent before the program exits. ```rust use std::fs; use std::sync::LazyLock; type Result = std::result::Result>; fn main() -> Result<()> { let shutdown_handler = logfire::configure().install_panic_handler().finish()?; let mut total_size = 0u64; let cwd = std::env::current_dir()?; logfire::span!("counting size of {cwd}", cwd = cwd.display().to_string()).in_scope(|| { let entries = fs::read_dir(&cwd)?; for entry in entries { let entry = entry?; let path = entry.path(); let _span = logfire::span!( "reading {path}", path = path .strip_prefix(&cwd) .unwrap_or(&path) .display() .to_string() ) .entered(); let metadata = entry.metadata()?; if metadata.is_file() { total_size += metadata.len(); } } Result::Ok(()) })?; logfire::info!( "total size of {cwd} is {size} bytes", cwd = cwd.display().to_string(), size = total_size ); shutdown_handler.shutdown()?; Ok(()) } ``` -------------------------------- ### Instrument Axum Web Framework with Logfire Source: https://context7.com/pydantic/logfire-rust/llms.txt Integrates Logfire with the Axum web framework to provide automatic request tracing, custom spans, and metrics. It utilizes `axum-tracing-opentelemetry` for tracing and `axum-otel-metrics` for HTTP metrics. The example demonstrates setting up a basic Axum server with routes for user retrieval and health checks, including custom metrics. ```rust use axum::{ Router, Json, extract::Path, http::StatusCode, routing::{get, post}, }; use axum_tracing_opentelemetry::middleware::{OtelAxumLayer, OtelInResponseLayer}; use axum_otel_metrics::HttpMetricsLayerBuilder; use serde::{Deserialize, Serialize}; use std::sync::LazyLock; use opentelemetry::{KeyValue, metrics::Counter}; use tracing::Instrument; use tokio::net::TcpListener; static REQUEST_COUNTER: LazyLock> = LazyLock::new(|| { logfire::u64_counter("custom_requests_total") .with_description("Custom request counter") .build() }); #[derive(Serialize, Deserialize)] struct User { id: u32, name: String, } async fn get_user(Path(user_id): Path) -> Result, StatusCode> { // Wrap handler logic in a span async { logfire::info!("Fetching user {user_id}"); // Simulate database query with its own span tokio::time::sleep(std::time::Duration::from_millis(10)) .instrument(logfire::span!("Database query", table = "users")) .await; if user_id == 0 { logfire::warn!("Invalid user ID: {user_id}"); return Err(StatusCode::BAD_REQUEST); } REQUEST_COUNTER.add(1, &[KeyValue::new("endpoint", "get_user")]); Ok(Json(User { id: user_id, name: format!("User {user_id}"), })) } .instrument(logfire::span!("Get user {user_id}", user_id = user_id)) .await } async fn health_check() -> Json { logfire::debug!("Health check requested"); Json(serde_json::json!({"status": "healthy"})) } #[tokio::main] async fn main() -> Result<(), Box> { let logfire = logfire::configure() .with_metrics(Some(logfire::config::MetricsOptions::default())) .finish()?; let _guard = logfire.shutdown_guard(); logfire::info!("Starting Axum server"); let app = Router::new() .route("/users/{id}", get(get_user)) .route("/health", get(health_check)) // Automatic request tracing (filter out health checks) .layer(OtelAxumLayer::default().filter(|path| !path.starts_with("/health"))) .layer(OtelInResponseLayer::default()) // Standard HTTP metrics (request duration, etc.) .layer(HttpMetricsLayerBuilder::new().build()); let listener = TcpListener::bind("127.0.0.1:3000").await?; logfire::info!("Server listening on http://127.0.0.1:3000"); axum::serve(listener, app).await?; Ok(()) } ``` -------------------------------- ### Add Tracing and Flushing Layers in Rust Source: https://github.com/pydantic/logfire-rust/blob/main/src/usage/lambda.md This snippet demonstrates how to add the `TracingLayer` and `LogfireFlushLayer` to a Rust application's layer stack. The `TracingLayer` is added first to ensure spans are created, followed by `LogfireFlushLayer` to flush logs after spans are closed. This setup is common in environments like AWS Lambda. ```rust .layer(lambda_runtime::layers::TracingLayer::new()) // 5. Add the flushing layer after; this way the spans created // by the `TracingLayer` will be closed before logfire is flushed. .layer(LogfireFlushLayer { logfire }) // 6. And finally, run the process. .run() .await ``` -------------------------------- ### Initialize Logfire SDK in Rust Source: https://context7.com/pydantic/logfire-rust/llms.txt Basic initialization of the Logfire Rust SDK using the `configure` function. A shutdown guard is created to ensure clean shutdown on panic or exit, and a simple info log is emitted. ```rust use std::fs; fn main() -> Result<(), Box> { // Configure and initialize Logfire let logfire = logfire::configure().finish()?; // Create shutdown guard to ensure clean shutdown on panic or exit let _guard = logfire.shutdown_guard(); // Your application code here logfire::info!("Application started"); // Guard automatically shuts down Logfire when dropped Ok(()) } ``` -------------------------------- ### Configure Logfire SDK with Advanced Options in Rust Source: https://context7.com/pydantic/logfire-rust/llms.txt Demonstrates advanced configuration of the Logfire Rust SDK, including setting the token, service metadata, console output, log level filters, metrics, and custom base URL. The `shutdown_guard` ensures proper cleanup. ```rust use logfire::config::{ConsoleOptions, SendToLogfire, AdvancedOptions, MetricsOptions}; use tracing::level_filters::LevelFilter; fn main() -> Result<(), Box> { let logfire = logfire::configure() // Authentication (defaults to LOGFIRE_TOKEN env var) .with_token("your_token_here") // Service identification for traces .with_service_name("my-rust-service") .with_service_version("1.0.0") .with_environment("production") // Control whether to send data to Logfire platform .send_to_logfire(SendToLogfire::Yes) // Yes, No, or IfTokenPresent // Console output configuration .with_console(Some(ConsoleOptions::default() .with_colors(logfire::config::ConsoleColors::Auto) .with_include_timestamps(true) .with_min_log_level(tracing::Level::INFO))) // Log level filter (defaults to TRACE when sending to Logfire) .with_default_level_filter(LevelFilter::INFO) // Enable metrics collection .with_metrics(Some(MetricsOptions::default())) // Advanced: custom ID generator, resources, log processors .with_advanced_options(AdvancedOptions::default() .with_base_url("https://logfire-us.pydantic.dev") .with_tracing_metrics(true)) // Disable default panic handler if needed .with_install_panic_handler(true) .finish()?; let _guard = logfire.shutdown_guard(); logfire::info!("Configured with all options"); Ok(()) } ``` -------------------------------- ### Configure Logfire SDK with Environment Variables and Overrides (Rust) Source: https://context7.com/pydantic/logfire-rust/llms.txt Demonstrates how the Logfire SDK automatically reads configuration from environment variables. It also shows how programmatic configuration using methods like `with_token` and `with_service_name` can override values set via environment variables. ```rust // SDK automatically reads environment variables fn main() -> Result<(), Box> { // Token, service name, etc. picked up from environment let logfire = logfire::configure().finish()?; let _guard = logfire.shutdown_guard(); // Programmatic values override environment variables let logfire_custom = logfire::configure() .with_token("override_token") // Overrides LOGFIRE_TOKEN .with_service_name("override-name") // Overrides LOGFIRE_SERVICE_NAME .finish()?; Ok(()) } ``` -------------------------------- ### Configure Logfire SDK via Environment Variables (Bash) Source: https://context7.com/pydantic/logfire-rust/llms.txt Shows how to configure the Logfire SDK using environment variables. This includes setting authentication tokens, service identification details, data export controls, log levels, and credentials directory. It also mentions alternative OpenTelemetry standard names that Logfire respects. ```bash # Required: Authentication token export LOGFIRE_TOKEN="pylf_v1_us_your_write_token" # Optional: Service identification export LOGFIRE_SERVICE_NAME="my-service" export LOGFIRE_SERVICE_VERSION="1.0.0" export LOGFIRE_ENVIRONMENT="production" # Alternative OpenTelemetry standard names export OTEL_SERVICE_NAME="my-service" export OTEL_SERVICE_VERSION="1.0.0" # Control data export export LOGFIRE_SEND_TO_LOGFIRE="yes" # yes, no, if-token-present # Log level filtering (standard Rust log format) export RUST_LOG="info,my_crate=debug" # Credentials directory for CLI-based setup export LOGFIRE_CREDENTIALS_DIR=".logfire" # Export protocol (defaults to http/protobuf) export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" # or grpc, http/json ``` -------------------------------- ### Manage Logfire SDK Lifecycle and Shutdown (Rust) Source: https://context7.com/pydantic/logfire-rust/llms.txt Illustrates different methods for managing the Logfire SDK's lifecycle, ensuring telemetry data is flushed before application exit. It covers using a `shutdown_guard` for automatic cleanup (even on panics), manual shutdown, and forcing a flush without a full shutdown, which is useful in serverless environments. ```rust fn main() -> Result<(), Box> { let logfire = logfire::configure().finish()?; // Option 1: Use shutdown guard (recommended) // Automatically shuts down when dropped, even on panic { let guard = logfire.clone().shutdown_guard(); logfire::info!("Application running"); // Guard dropped here, triggers shutdown } // Option 2: Manual shutdown let logfire2 = logfire::configure() .send_to_logfire(logfire::config::SendToLogfire::IfTokenPresent) .finish()?; logfire::info!("Processing..."); // Force flush without full shutdown (useful in Lambda/serverless) logfire2.force_flush()?; // Full shutdown - flushes and closes all resources logfire2.shutdown()?; // Option 3: Explicit guard shutdown with result handling let logfire3 = logfire::configure() .send_to_logfire(logfire::config::SendToLogfire::IfTokenPresent) .finish()?; let guard = logfire3.shutdown_guard(); logfire::info!("Final processing"); // Explicit shutdown returns Result for error handling guard.shutdown()?; Ok(()) } ``` -------------------------------- ### Emit Logs with Logfire Macros Source: https://context7.com/pydantic/logfire-rust/llms.txt Illustrates the use of logging macros like `info!`, `error!`, `warn!`, `debug!`, and `trace!` in Rust with the logfire-rust crate. These macros allow emitting log events with structured attributes, associating them with the current span context, and exporting them to Logfire. Supports various shorthand notations for attributes. ```rust fn main() -> Result<(), Box> { let logfire = logfire::configure().finish()?; let _guard = logfire.shutdown_guard(); // Basic log messages at different levels logfire::trace!("Very detailed trace information"); logfire::debug!("Debug information for development"); logfire::info!("Normal operational information"); logfire::warn!("Warning about potential issues"); logfire::error!("Error occurred during processing"); // Logs with structured attributes let user_id = 42; let email = "user@example.com"; logfire::info!( "User logged in: {user_id}", user_id = user_id, user.email = email, login.method = "oauth" ); // Identifier shorthand - variable name becomes attribute key let request_id = "req-123"; let latency_ms = 45.5; logfire::info!( "Request completed", request_id, // Shorthand: key = "request_id", value = "req-123" latency_ms ); // Struct field shorthand struct Request { method: String, path: String, } let req = Request { method: "GET".to_string(), path: "/api/users".to_string(), }; logfire::info!("Handling request", req.method, req.path); // Logs with explicit parent span let span = logfire::span!("Parent operation"); logfire::info!(parent: &span, "Log associated with parent", status = "ok"); // Using the generic log! macro with explicit level logfire::log!(tracing::Level::INFO, "Generic log message", key = "value"); Ok(()) } ``` -------------------------------- ### Create Tracing Spans with Logfire Source: https://context7.com/pydantic/logfire-rust/llms.txt Demonstrates how to create tracing spans using the `logfire::span!` macro in Rust. Spans can include structured data, custom levels, explicit parents, and be used with async operations. They are essential for understanding the flow and performance of your application. ```rust use std::fs; use tracing::Instrument; fn main() -> Result<(), Box> { let logfire = logfire::configure().finish()?; let _guard = logfire.shutdown_guard(); // Basic span - automatically becomes parent for nested operations let root_span = logfire::span!("Processing request"); // Execute code within span context root_span.in_scope(|| { // Child span with attributes let _child = logfire::span!( "Database query", table = "users", query_type = "SELECT" ).entered(); // Spans can use format strings with captured variables let user_id = 42; let _fetch_span = logfire::span!( "Fetching user {user_id}", user_id = user_id, cache.hit = false ).entered(); logfire::info!("Query completed"); }); // Span with explicit parent let child_span = logfire::span!(parent: &root_span, "Child operation"); // Span with custom level let debug_span = logfire::span!( level: tracing::Level::DEBUG, "Debug operation", detail = "verbose info" ); // Using spans with async code via .instrument() async fn async_operation() { logfire::info!("Inside async operation"); } tokio::runtime::Runtime::new()?.block_on(async { async_operation() .instrument(logfire::span!("Async task")) .await; }); // Dynamic attribute recording let span = logfire::span!("Processing", result = tracing::field::Empty); span.record("result", "success"); Ok(()) } ``` -------------------------------- ### Add Logfire Crate to Cargo.toml Source: https://github.com/pydantic/logfire-rust/blob/main/README.md This snippet shows how to add the logfire crate as a dependency in your Rust project's Cargo.toml file. Ensure you are using a compatible version of the crate. ```toml [dependencies] logfire = "0.6" ``` -------------------------------- ### Implement Logfire Flushing Layer for AWS Lambda in Rust Source: https://github.com/pydantic/logfire-rust/blob/main/src/usage/lambda.md This Rust code defines a `tower::Layer` and `tower::Service` to ensure Logfire telemetry is flushed when a Lambda function invocation completes. It wraps the inner service's future and forces a flush before the future resolves, preventing data loss due to Lambda's runtime freezing. ```rust use std::future::Future; use std::task::{Context, Poll}; use lambda_runtime::{service_fn, Error, LambdaEvent}; use logfire::{config::ConsoleOptions, Logfire}; use pin_project::pin_project; use serde::{Deserialize, Serialize}; use tower::{Layer, Service}; /// A `tower::Layer` that will be used to introduce flushing to the lambda function. pub struct LogfireFlushLayer { logfire: Logfire, } impl Layer for LogfireFlushLayer { type Service = LogfireFlushService; fn layer(&self, service: S) -> Self::Service { LogfireFlushService { logfire: self.logfire.clone(), service, } } } /// A `tower::Service` which wraps an inner service to flush Logfire when the service /// finishes executing. pub struct LogfireFlushService { logfire: Logfire, service: S, } impl Service for LogfireFlushService where S: Service, { type Response = S::Response; type Error = S::Error; type Future = LogfireFlushFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.service.poll_ready(cx) } fn call(&mut self, request: Request) -> Self::Future { LogfireFlushFuture { inner: Some(self.service.call(request)), logfire: self.logfire.clone(), } } } /// The future produced when calling the `LogfireFlushService`. The future is /// responsible for driving the inner future and then flushing logfire when /// the inner future completes. #[pin_project] pub struct LogfireFlushFuture { #[pin] inner: Option, logfire: Logfire, } impl Future for LogfireFlushFuture where F: Future>, { type Output = Result; fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.project(); let Some(inner) = this.inner.as_mut().as_pin_mut() else { panic!("`LogfireFlushFuture` polled after completion"); }; match inner.poll(cx) { Poll::Ready(result) => { // Drop the inner future so that any spans it holds are dropped before flushing this.inner.set(None); // Flush logfire before returning. // Note that this is a blocking function. In the context of the current lambda // invocation that should not be a problem. let _ = this.logfire.force_flush(); Poll::Ready(result) } Poll::Pending => Poll::Pending, } } } /// Example lambda request payload. #[derive(Deserialize)] pub(crate) struct IncomingMessage { command: String, } /// Example lambda response payload. #[derive(Serialize)] pub(crate) struct OutgoingMessage { req_id: String, msg: String, } /// Main body of the lambda function. #[tracing::instrument(skip_all)] pub(crate) async fn function_handler( event: LambdaEvent, ) -> Result { // Change this logic to be whatever your lambda function needs to do. Ok(OutgoingMessage { req_id: event.context.request_id, msg: format!("Command {}.", event.payload.command), }) } /// Main function for the lambda process. #[tokio::main] async fn main() -> Result<(), Error> { // 1. Configure logfire on startup let logfire = logfire::configure() .with_console(Some(ConsoleOptions::default())) .finish()?; logfire::info!("Starting up"); // 2. Lambda processes require special termination logic. Logfire's // shutdown guard can be passed into `lambda_runtime`'s graceful // shutdown handler to ensure that telemetry is flushed when // idle lambda processes are shutdown. let shutdown_guard = logfire.clone().shutdown_guard(); lambda_runtime::spawn_graceful_shutdown_handler(|| async move { logfire::info!("Shutting down"); let _ = shutdown_guard.shutdown(); }) .await; // 3. Prepare the main `lambda_runtime::Runtime` lambda_runtime::Runtime::new(service_fn(function_handler)) // 4. Add a `TracingLayer` before the logfire layer ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.