Switch to opentelemetry-prometheus-text-exporter

This commit is contained in:
Quentin Gliech
2025-08-18 11:28:55 +02:00
parent d7691b9b02
commit 4578debdc2
5 changed files with 49 additions and 84 deletions

60
Cargo.lock generated
View File

@@ -3191,12 +3191,11 @@ dependencies = [
"opentelemetry-http", "opentelemetry-http",
"opentelemetry-jaeger-propagator", "opentelemetry-jaeger-propagator",
"opentelemetry-otlp", "opentelemetry-otlp",
"opentelemetry-prometheus", "opentelemetry-prometheus-text-exporter",
"opentelemetry-resource-detectors", "opentelemetry-resource-detectors",
"opentelemetry-semantic-conventions", "opentelemetry-semantic-conventions",
"opentelemetry-stdout", "opentelemetry-stdout",
"opentelemetry_sdk", "opentelemetry_sdk",
"prometheus",
"rand 0.8.5", "rand 0.8.5",
"rand_chacha 0.3.1", "rand_chacha 0.3.1",
"reqwest", "reqwest",
@@ -4172,15 +4171,14 @@ dependencies = [
] ]
[[package]] [[package]]
name = "opentelemetry-prometheus" name = "opentelemetry-prometheus-text-exporter"
version = "0.29.1" version = "0.2.0"
source = "git+https://github.com/sandhose/opentelemetry-rust.git?branch=otel-prometheus-0.30#193906c7577b4f8ee642aa771191c7d80b14a297" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddbb5743c13741bd9207de7c449f9797c0e513ac07551eac807da94056c530d9"
dependencies = [ dependencies = [
"once_cell",
"opentelemetry", "opentelemetry",
"opentelemetry_sdk", "opentelemetry_sdk",
"prometheus", "smartstring",
"tracing",
] ]
[[package]] [[package]]
@@ -4671,21 +4669,6 @@ dependencies = [
"yansi", "yansi",
] ]
[[package]]
name = "prometheus"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a"
dependencies = [
"cfg-if",
"fnv",
"lazy_static",
"memchr",
"parking_lot",
"protobuf",
"thiserror 2.0.12",
]
[[package]] [[package]]
name = "prost" name = "prost"
version = "0.13.5" version = "0.13.5"
@@ -4709,26 +4692,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "protobuf"
version = "3.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4"
dependencies = [
"once_cell",
"protobuf-support",
"thiserror 1.0.69",
]
[[package]]
name = "protobuf-support"
version = "3.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6"
dependencies = [
"thiserror 1.0.69",
]
[[package]] [[package]]
name = "psl" name = "psl"
version = "2.1.128" version = "2.1.128"
@@ -5830,6 +5793,17 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "smartstring"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29"
dependencies = [
"autocfg",
"static_assertions",
"version_check",
]
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.6.0" version = "0.6.0"

View File

@@ -407,10 +407,8 @@ version = "0.30.0"
version = "0.30.0" version = "0.30.0"
default-features = false default-features = false
features = ["trace", "metrics", "http-proto"] features = ["trace", "metrics", "http-proto"]
[workspace.dependencies.opentelemetry-prometheus] [workspace.dependencies.opentelemetry-prometheus-text-exporter]
# https://github.com/open-telemetry/opentelemetry-rust/pull/3076 version = "0.2.0"
git = "https://github.com/sandhose/opentelemetry-rust.git"
branch = "otel-prometheus-0.30"
[workspace.dependencies.opentelemetry-resource-detectors] [workspace.dependencies.opentelemetry-resource-detectors]
version = "0.9.0" version = "0.9.0"
[workspace.dependencies.opentelemetry-semantic-conventions] [workspace.dependencies.opentelemetry-semantic-conventions]
@@ -480,10 +478,6 @@ features = ["std", "pkcs5", "encryption"]
[workspace.dependencies.psl] [workspace.dependencies.psl]
version = "2.1.128" version = "2.1.128"
# Prometheus metrics
[workspace.dependencies.prometheus]
version = "0.14.0"
# High-precision clock # High-precision clock
[workspace.dependencies.quanta] [workspace.dependencies.quanta]
version = "0.12.6" version = "0.12.6"

View File

@@ -59,12 +59,11 @@ opentelemetry.workspace = true
opentelemetry-http.workspace = true opentelemetry-http.workspace = true
opentelemetry-jaeger-propagator.workspace = true opentelemetry-jaeger-propagator.workspace = true
opentelemetry-otlp.workspace = true opentelemetry-otlp.workspace = true
opentelemetry-prometheus.workspace = true opentelemetry-prometheus-text-exporter.workspace = true
opentelemetry-resource-detectors.workspace = true opentelemetry-resource-detectors.workspace = true
opentelemetry-semantic-conventions.workspace = true opentelemetry-semantic-conventions.workspace = true
opentelemetry-stdout.workspace = true opentelemetry-stdout.workspace = true
opentelemetry_sdk.workspace = true opentelemetry_sdk.workspace = true
prometheus.workspace = true
sentry.workspace = true sentry.workspace = true
sentry-tracing.workspace = true sentry-tracing.workspace = true
sentry-tower.workspace = true sentry-tower.workspace = true

View File

@@ -23,7 +23,7 @@ use opentelemetry::{
trace::TracerProvider as _, trace::TracerProvider as _,
}; };
use opentelemetry_otlp::{WithExportConfig, WithHttpConfig}; use opentelemetry_otlp::{WithExportConfig, WithHttpConfig};
use opentelemetry_prometheus::PrometheusExporter; use opentelemetry_prometheus_text_exporter::PrometheusExporter;
use opentelemetry_sdk::{ use opentelemetry_sdk::{
Resource, Resource,
metrics::{ManualReader, SdkMeterProvider, periodic_reader_with_async_runtime::PeriodicReader}, metrics::{ManualReader, SdkMeterProvider, periodic_reader_with_async_runtime::PeriodicReader},
@@ -33,7 +33,6 @@ use opentelemetry_sdk::{
}, },
}; };
use opentelemetry_semantic_conventions as semcov; use opentelemetry_semantic_conventions as semcov;
use prometheus::Registry;
use url::Url; use url::Url;
static SCOPE: LazyLock<InstrumentationScope> = LazyLock::new(|| { static SCOPE: LazyLock<InstrumentationScope> = LazyLock::new(|| {
@@ -49,7 +48,7 @@ pub static METER: LazyLock<Meter> =
pub static TRACER: OnceLock<Tracer> = OnceLock::new(); pub static TRACER: OnceLock<Tracer> = OnceLock::new();
static METER_PROVIDER: OnceLock<SdkMeterProvider> = OnceLock::new(); static METER_PROVIDER: OnceLock<SdkMeterProvider> = OnceLock::new();
static TRACER_PROVIDER: OnceLock<SdkTracerProvider> = OnceLock::new(); static TRACER_PROVIDER: OnceLock<SdkTracerProvider> = OnceLock::new();
static PROMETHEUS_REGISTRY: OnceLock<Registry> = OnceLock::new(); static PROMETHEUS_EXPORTER: OnceLock<PrometheusExporter> = OnceLock::new();
pub fn setup(config: &TelemetryConfig) -> anyhow::Result<()> { pub fn setup(config: &TelemetryConfig) -> anyhow::Result<()> {
let propagator = propagator(&config.tracing.propagators); let propagator = propagator(&config.tracing.propagators);
@@ -180,21 +179,30 @@ type PromServiceFuture =
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
fn prometheus_service_fn<T>(_req: T) -> PromServiceFuture { fn prometheus_service_fn<T>(_req: T) -> PromServiceFuture {
use prometheus::{Encoder, TextEncoder}; let response = if let Some(exporter) = PROMETHEUS_EXPORTER.get() {
// We'll need some space for this, so we preallocate a bit
let mut buffer = Vec::with_capacity(1024);
let response = if let Some(registry) = PROMETHEUS_REGISTRY.get() { if let Err(err) = exporter.export(&mut buffer) {
let mut buffer = Vec::new(); tracing::error!(
let encoder = TextEncoder::new(); error = &err as &dyn std::error::Error,
let metric_families = registry.gather(); "Failed to export Prometheus metrics"
);
// That shouldn't panic, unless we're constructing invalid labels Response::builder()
encoder.encode(&metric_families, &mut buffer).unwrap(); .status(500)
.header(CONTENT_TYPE, "text/plain")
Response::builder() .body(Full::new(Bytes::from_static(
.status(200) b"Failed to export Prometheus metrics, see logs for details",
.header(CONTENT_TYPE, encoder.format_type()) )))
.body(Full::new(Bytes::from(buffer))) .unwrap()
.unwrap() } else {
Response::builder()
.status(200)
.header(CONTENT_TYPE, "text/plain;version=1.0.0")
.body(Full::new(Bytes::from(buffer)))
.unwrap()
}
} else { } else {
Response::builder() Response::builder()
.status(500) .status(500)
@@ -209,7 +217,7 @@ fn prometheus_service_fn<T>(_req: T) -> PromServiceFuture {
} }
pub fn prometheus_service<T>() -> tower::util::ServiceFn<fn(T) -> PromServiceFuture> { pub fn prometheus_service<T>() -> tower::util::ServiceFn<fn(T) -> PromServiceFuture> {
if PROMETHEUS_REGISTRY.get().is_none() { if PROMETHEUS_EXPORTER.get().is_none() {
tracing::warn!( tracing::warn!(
"A Prometheus resource was mounted on a listener, but the Prometheus exporter was not setup in the config" "A Prometheus resource was mounted on a listener, but the Prometheus exporter was not setup in the config"
); );
@@ -219,16 +227,11 @@ pub fn prometheus_service<T>() -> tower::util::ServiceFn<fn(T) -> PromServiceFut
} }
fn prometheus_metric_reader() -> anyhow::Result<PrometheusExporter> { fn prometheus_metric_reader() -> anyhow::Result<PrometheusExporter> {
let registry = Registry::new(); let exporter = PrometheusExporter::builder().without_scope_info().build();
PROMETHEUS_REGISTRY PROMETHEUS_EXPORTER
.set(registry.clone()) .set(exporter.clone())
.map_err(|_| anyhow::anyhow!("PROMETHEUS_REGISTRY was set twice"))?; .map_err(|_| anyhow::anyhow!("PROMETHEUS_EXPORTER was set twice"))?;
let exporter = opentelemetry_prometheus::exporter()
.with_registry(registry)
.without_scope_info()
.build()?;
Ok(exporter) Ok(exporter)
} }

View File

@@ -98,8 +98,3 @@ deny = ["oldtime"]
unknown-registry = "warn" unknown-registry = "warn"
unknown-git = "warn" unknown-git = "warn"
allow-registry = ["https://github.com/rust-lang/crates.io-index"] allow-registry = ["https://github.com/rust-lang/crates.io-index"]
allow-git = [
# https://github.com/open-telemetry/opentelemetry-rust/pull/3076
"https://github.com/sandhose/opentelemetry-rust",
]