|
| 1 | +//! # Exporting OpenTelemetry Metrics from Rust to Logfire |
| 2 | +//! |
| 3 | +//! This guide shows how to export OpenTelemetry metrics from Rust applications to Logfire and use them for creating dashboards and monitoring. |
| 4 | +//! |
| 5 | +//! ## Overview |
| 6 | +//! |
| 7 | +//! The Logfire Rust SDK provides built-in support for OpenTelemetry metrics through its metrics API. Metrics are automatically exported to Logfire alongside traces and logs, giving you comprehensive observability for your Rust applications. |
| 8 | +//! |
| 9 | +//! ## Prerequisites |
| 10 | +//! |
| 11 | +//! 1. **Set up a Logfire project** at [logfire.pydantic.dev](https://logfire.pydantic.dev/docs/#logfire) |
| 12 | +//! 2. **Create a write token** following the [token creation guide](https://logfire.pydantic.dev/docs/how-to-guides/create-write-tokens/) |
| 13 | +//! 3. **Set the environment variable**: `export LOGFIRE_TOKEN=your_token_here` |
| 14 | +//! |
| 15 | +//! ## Available Metric Types |
| 16 | +//! |
| 17 | +//! The Logfire SDK supports all OpenTelemetry metric types: |
| 18 | +//! |
| 19 | +//! ### Counters |
| 20 | +//! |
| 21 | +//! Monotonically increasing values (e.g., request counts, error counts): |
| 22 | +//! |
| 23 | +//! ```rust |
| 24 | +//! use std::sync::LazyLock; |
| 25 | +//! use opentelemetry::metrics::Counter; |
| 26 | +//! |
| 27 | +//! // For counting discrete events |
| 28 | +//! static HTTP_REQUESTS: LazyLock<Counter<u64>> = LazyLock::new(|| { |
| 29 | +//! logfire::u64_counter("http_requests_total") |
| 30 | +//! .with_description("Total HTTP requests") |
| 31 | +//! .with_unit("{request}") |
| 32 | +//! .build() |
| 33 | +//! }); |
| 34 | +//! |
| 35 | +//! // For floating-point measurements |
| 36 | +//! static DATA_PROCESSED: LazyLock<Counter<f64>> = LazyLock::new(|| { |
| 37 | +//! logfire::f64_counter("data_processed_bytes") |
| 38 | +//! .with_description("Total bytes processed") |
| 39 | +//! .with_unit("By") |
| 40 | +//! .build() |
| 41 | +//! }); |
| 42 | +//! ``` |
| 43 | +//! |
| 44 | +//! ### Gauges |
| 45 | +//! |
| 46 | +//! Current state values that can go up or down: |
| 47 | +//! |
| 48 | +//! ```rust |
| 49 | +//! use std::sync::LazyLock; |
| 50 | +//! use opentelemetry::metrics::Gauge; |
| 51 | +//! |
| 52 | +//! static ACTIVE_CONNECTIONS: LazyLock<Gauge<u64>> = LazyLock::new(|| { |
| 53 | +//! logfire::u64_gauge("active_connections") |
| 54 | +//! .with_description("Number of active connections") |
| 55 | +//! .with_unit("{connection}") |
| 56 | +//! .build() |
| 57 | +//! }); |
| 58 | +//! |
| 59 | +//! static CPU_USAGE: LazyLock<Gauge<f64>> = LazyLock::new(|| { |
| 60 | +//! logfire::f64_gauge("cpu_usage_percent") |
| 61 | +//! .with_description("CPU usage percentage") |
| 62 | +//! .with_unit("%") |
| 63 | +//! .build() |
| 64 | +//! }); |
| 65 | +//! ``` |
| 66 | +//! |
| 67 | +//! ### Histograms |
| 68 | +//! |
| 69 | +//! Distribution of values (e.g., request durations, response sizes): |
| 70 | +//! |
| 71 | +//! ```rust |
| 72 | +//! use std::sync::LazyLock; |
| 73 | +//! use opentelemetry::metrics::Histogram; |
| 74 | +//! |
| 75 | +//! static REQUEST_DURATION: LazyLock<Histogram<f64>> = LazyLock::new(|| { |
| 76 | +//! logfire::f64_histogram("http_request_duration") |
| 77 | +//! .with_description("HTTP request duration") |
| 78 | +//! .with_unit("s") |
| 79 | +//! .build() |
| 80 | +//! }); |
| 81 | +//! |
| 82 | +//! static RESPONSE_SIZE: LazyLock<Histogram<u64>> = LazyLock::new(|| { |
| 83 | +//! logfire::u64_histogram("http_response_size") |
| 84 | +//! .with_description("HTTP response size") |
| 85 | +//! .with_unit("By") |
| 86 | +//! .build() |
| 87 | +//! }); |
| 88 | +//! ``` |
| 89 | +//! |
| 90 | +//! ### Up/Down Counters |
| 91 | +//! |
| 92 | +//! Values that can increase or decrease: |
| 93 | +//! |
| 94 | +//! ```rust |
| 95 | +//! use std::sync::LazyLock; |
| 96 | +//! use opentelemetry::metrics::UpDownCounter; |
| 97 | +//! |
| 98 | +//! static QUEUE_SIZE: LazyLock<UpDownCounter<i64>> = LazyLock::new(|| { |
| 99 | +//! logfire::i64_up_down_counter("queue_size") |
| 100 | +//! .with_description("Current queue size") |
| 101 | +//! .with_unit("{item}") |
| 102 | +//! .build() |
| 103 | +//! }); |
| 104 | +//! ``` |
| 105 | +//! |
| 106 | +//! ## Observable Metrics |
| 107 | +//! |
| 108 | +//! For metrics that need to be sampled periodically rather than recorded on-demand: |
| 109 | +//! |
| 110 | +//! ```rust |
| 111 | +//! use std::sync::LazyLock; |
| 112 | +//! use opentelemetry::metrics::ObservableGauge; |
| 113 | +//! |
| 114 | +//! static MEMORY_USAGE: LazyLock<ObservableGauge<u64>> = LazyLock::new(|| { |
| 115 | +//! logfire::u64_observable_gauge("memory_usage_bytes") |
| 116 | +//! .with_description("Current memory usage") |
| 117 | +//! .with_unit("By") |
| 118 | +//! .with_callback(|observer| { |
| 119 | +//! // Get current memory usage (example) |
| 120 | +//! let memory_usage = get_memory_usage(); |
| 121 | +//! observer.observe(memory_usage, &[]); |
| 122 | +//! }) |
| 123 | +//! .build() |
| 124 | +//! }); |
| 125 | +//! |
| 126 | +//! fn get_memory_usage() -> u64 { |
| 127 | +//! // Implementation to get actual memory usage |
| 128 | +//! 1024 * 1024 * 100 // Example: 100MB |
| 129 | +//! } |
| 130 | +//! ``` |
| 131 | +//! |
| 132 | +//! ## Examples |
| 133 | +//! |
| 134 | +//! For examples using these metrics, see the [examples directory][crate::usage::examples]. |
| 135 | +//! |
| 136 | +//! ## Using Metrics in Logfire Dashboards |
| 137 | +//! |
| 138 | +//! Once your metrics are being exported to Logfire, you can create dashboards and alerts: |
| 139 | +//! |
| 140 | +//! ### 1. **View Metrics in Logfire** |
| 141 | +//! |
| 142 | +//! - Navigate to your Logfire project dashboard |
| 143 | +//! - Go to the ["Explore"](https://logfire.pydantic.dev/docs/guides/web-ui/explore/) view |
| 144 | +//! - Run `select * from metrics` to view all incoming metrics from your application |
| 145 | +//! |
| 146 | +//! ## Best Practices |
| 147 | +//! |
| 148 | +//! 1. **Use Static Variables**: Define metrics as static variables with `LazyLock` for efficiency |
| 149 | +//! 2. **Meaningful Names**: Use descriptive metric names following OpenTelemetry conventions |
| 150 | +//! 3. **Consistent Labels**: Use consistent label names across related metrics |
| 151 | +//! 4. **Appropriate Units**: Specify units (seconds, bytes, requests) for better dashboard formatting |
| 152 | +//! 5. **Documentation**: Add descriptions to help with dashboard creation |
| 153 | +//! 6. **Label Cardinality**: Be careful with high-cardinality labels (e.g., user IDs) - prefer aggregated metrics |
| 154 | +//! |
| 155 | +//! ## Troubleshooting |
| 156 | +//! |
| 157 | +//! ### Metrics Not Appearing |
| 158 | +//! |
| 159 | +//! - Verify `LOGFIRE_TOKEN` is set correctly |
| 160 | +//! - Check that metrics are being recorded (add debug logging) |
| 161 | +//! - Ensure the application runs long enough for metrics to be exported |
| 162 | +//! |
| 163 | +//! ### Performance Issues |
| 164 | +//! |
| 165 | +//! - Monitor label cardinality - too many unique label combinations can impact performance |
| 166 | +//! - Use histograms instead of gauges for distributions |
| 167 | +//! - Consider sampling for high-frequency metrics |
| 168 | +//! |
| 169 | +//! ### Dashboard Issues |
| 170 | +//! |
| 171 | +//! - Check metric names match exactly (case-sensitive) |
| 172 | +//! - Verify time ranges in queries |
| 173 | +//! - Use Logfire's query builder to test metric availability |
| 174 | +//! |
| 175 | +//! This guide provides a complete foundation for implementing metrics in your Rust applications and visualizing them in Logfire dashboards. |
0 commit comments