From 8b014944f46a3a76ea26a2cada74e1b917d6a2ec Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Fri, 4 Aug 2023 03:28:01 +0800 Subject: [PATCH] chore(deps): opentelemetry 0.20 (#91) * chore(deps): opentelemetry 0.20 * fix(otel): missing SocketAddr * fix: clippy * fix: clippy * fix(deps): missing prometheus * fix(otel): prometheus * fix(docs): example --- Cargo.toml | 7 +- examples/otel/metrics/src/main.rs | 50 ++++++--- examples/otel/tracing/Cargo.toml | 2 +- viz-core/src/body.rs | 2 - viz-core/src/handler/mod.rs | 2 - viz-core/src/lib.rs | 1 + viz-core/src/middleware/mod.rs | 2 - viz-core/src/middleware/otel/metrics.rs | 135 ++++++++++++------------ viz-core/src/middleware/otel/mod.rs | 3 - viz-core/src/middleware/otel/tracing.rs | 122 +++++++++++---------- viz-core/src/request.rs | 4 +- viz-core/src/response.rs | 12 ++- viz-core/src/types/mod.rs | 2 - viz-handlers/Cargo.toml | 2 + viz-handlers/src/prometheus/mod.rs | 16 +-- viz/src/lib.rs | 2 +- 16 files changed, 200 insertions(+), 164 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 11cc0cf7..eaf64ece 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,11 +84,12 @@ hex = "0.4.3" rust-embed = "6.8.1" # OpenTelemetry -opentelemetry = { version = "0.19.0", default-features = false } -opentelemetry-prometheus = { version = "0.12.0", features = [ +opentelemetry = { version = "0.20.0", default-features = false } +opentelemetry-prometheus = { version = "0.13.0", features = [ "prometheus-encoding", ] } -opentelemetry-semantic-conventions = { version = "0.11.0" } +opentelemetry-semantic-conventions = { version = "0.12.0" } +prometheus = "0.13" # Tracing tracing = "0.1.37" diff --git a/examples/otel/metrics/src/main.rs b/examples/otel/metrics/src/main.rs index 6565f37f..8b495d17 100644 --- a/examples/otel/metrics/src/main.rs +++ b/examples/otel/metrics/src/main.rs @@ -7,16 +7,17 @@ use tokio::net::TcpListener; use opentelemetry::{ global, sdk::{ - export::metrics::aggregation, - metrics::{controllers, processors, selectors}, + metrics::{self, Aggregation, Instrument, MeterProvider, Stream}, + Resource, }, + KeyValue, }; use viz::{ - handlers::prometheus::{ExporterBuilder, Prometheus}, + handlers::prometheus::{ExporterBuilder, Prometheus, Registry}, middleware::otel, server::conn::http1, - Io, Request, Responder, Result, Router, Tree, + Error, Io, Request, Responder, Result, Router, Tree, }; async fn index(_: Request) -> Result<&'static str> { @@ -29,20 +30,39 @@ async fn main() -> Result<()> { let listener = TcpListener::bind(addr).await?; println!("listening on {addr}"); - let exporter = { - let controller = controllers::basic(processors::factory( - selectors::simple::histogram([1.0, 2.0, 5.0, 10.0, 20.0, 50.0]), - aggregation::cumulative_temporality_selector(), - )) - .build(); - ExporterBuilder::new(controller).init() + let registry = Registry::new(); + let (exporter, controller) = { + ( + ExporterBuilder::default() + .with_registry(registry.clone()) + .build() + .map_err(Error::normal)?, + metrics::new_view( + Instrument::new().name("http.server.duration"), + Stream::new().aggregation(Aggregation::ExplicitBucketHistogram { + boundaries: vec![ + 0.0, 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1.0, 2.5, 5.0, + 7.5, 10.0, + ], + record_min_max: true, + }), + ) + .unwrap(), + ) }; + let provider = MeterProvider::builder() + .with_reader(exporter) + .with_resource(Resource::new([KeyValue::new("service.name", "viz")])) + .with_view(controller) + .build(); + + global::set_meter_provider(provider.clone()); let app = Router::new() .get("/", index) .get("/:username", index) - .get("/metrics", Prometheus::new(exporter)) - .with(otel::metrics::Config::new(&global::meter("viz"))); + .get("/metrics", Prometheus::new(registry)) + .with(otel::metrics::Config::new(&global::meter("otel"))); let tree = Arc::new(Tree::from(app)); loop { @@ -57,4 +77,8 @@ async fn main() -> Result<()> { } }); } + + // Ensure all spans have been reported + // global::shutdown_tracer_provider(); + // provider.shutdown(); } diff --git a/examples/otel/tracing/Cargo.toml b/examples/otel/tracing/Cargo.toml index 67b47a20..82154c54 100644 --- a/examples/otel/tracing/Cargo.toml +++ b/examples/otel/tracing/Cargo.toml @@ -9,4 +9,4 @@ viz = { workspace = true, features = ["otel-tracing"] } tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] } opentelemetry.workspace = true -opentelemetry-jaeger = { version = "0.18.0", features = ["rt-tokio-current-thread"]} +opentelemetry-jaeger = { version = "0.19.0", features = ["rt-tokio-current-thread"]} diff --git a/viz-core/src/body.rs b/viz-core/src/body.rs index cd72d13e..12277405 100644 --- a/viz-core/src/body.rs +++ b/viz-core/src/body.rs @@ -1,5 +1,3 @@ -#![allow(clippy::module_name_repetitions)] - use std::{ pin::Pin, task::{Context, Poll}, diff --git a/viz-core/src/handler/mod.rs b/viz-core/src/handler/mod.rs index b368c53a..cdc01c7e 100644 --- a/viz-core/src/handler/mod.rs +++ b/viz-core/src/handler/mod.rs @@ -1,7 +1,5 @@ //! Traits and types for handling an HTTP. -#![allow(clippy::module_name_repetitions)] - use crate::{async_trait, Future}; mod after; diff --git a/viz-core/src/lib.rs b/viz-core/src/lib.rs index 90a0ec11..34d01f9e 100644 --- a/viz-core/src/lib.rs +++ b/viz-core/src/lib.rs @@ -4,6 +4,7 @@ #![doc(html_logo_url = "https://viz.rs/logo.svg")] #![doc(html_favicon_url = "https://viz.rs/logo.svg")] +#![allow(clippy::module_name_repetitions)] // #![forbid(unsafe_code)] #![warn( missing_debug_implementations, diff --git a/viz-core/src/middleware/mod.rs b/viz-core/src/middleware/mod.rs index 5da2df2b..a9205180 100644 --- a/viz-core/src/middleware/mod.rs +++ b/viz-core/src/middleware/mod.rs @@ -1,7 +1,5 @@ //! Built-in Middleware. -#![allow(clippy::module_name_repetitions)] - #[cfg(feature = "cookie")] pub mod cookie; #[cfg(feature = "cors")] diff --git a/viz-core/src/middleware/otel/metrics.rs b/viz-core/src/middleware/otel/metrics.rs index e1fbb9b5..c306d51b 100644 --- a/viz-core/src/middleware/otel/metrics.rs +++ b/viz-core/src/middleware/otel/metrics.rs @@ -2,42 +2,35 @@ //! //! [`OpenTelemetry`]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/semantic_conventions/http-metrics.md -use std::time::SystemTime; +use std::{net::SocketAddr, time::SystemTime}; use http::uri::Scheme; use opentelemetry::{ metrics::{Histogram, Meter, Unit, UpDownCounter}, - Context, KeyValue, + KeyValue, }; use opentelemetry_semantic_conventions::trace::{ - HTTP_CLIENT_IP, - HTTP_FLAVOR, - HTTP_METHOD, - // HTTP_RESPONSE_CONTENT_LENGTH, - HTTP_ROUTE, - HTTP_SCHEME, // , HTTP_SERVER_NAME - HTTP_STATUS_CODE, - HTTP_TARGET, - HTTP_USER_AGENT, - NET_HOST_PORT, - NET_SOCK_PEER_ADDR, + CLIENT_ADDRESS, CLIENT_SOCKET_ADDRESS, HTTP_REQUEST_METHOD, HTTP_RESPONSE_STATUS_CODE, + HTTP_ROUTE, NETWORK_PROTOCOL_VERSION, SERVER_ADDRESS, SERVER_PORT, URL_SCHEME, }; -use super::HTTP_HOST; - use crate::{ - async_trait, headers::UserAgent, Handler, IntoResponse, Request, RequestExt, Response, Result, + async_trait, Handler, IntoResponse, Request, RequestExt, Response, ResponseExt, Result, Transform, }; const HTTP_SERVER_ACTIVE_REQUESTS: &str = "http.server.active_requests"; const HTTP_SERVER_DURATION: &str = "http.server.duration"; +const HTTP_SERVER_REQUEST_SIZE: &str = "http.server.request.size"; +const HTTP_SERVER_RESPONSE_SIZE: &str = "http.server.response.size"; /// Request metrics middleware config. #[derive(Clone, Debug)] pub struct Config { active_requests: UpDownCounter, duration: Histogram, + request_size: Histogram, + response_size: Histogram, } impl Config { @@ -46,18 +39,35 @@ impl Config { pub fn new(meter: &Meter) -> Self { let active_requests = meter .i64_up_down_counter(HTTP_SERVER_ACTIVE_REQUESTS) - .with_description("HTTP concurrent in-flight requests per route") + .with_description( + "Measures the number of concurrent HTTP requests that are currently in-flight.", + ) + .with_unit(Unit::new("{request}")) .init(); let duration = meter .f64_histogram(HTTP_SERVER_DURATION) - .with_description("HTTP inbound request duration per route") - .with_unit(Unit::new("ms")) + .with_description("Measures the duration of inbound HTTP requests.") + .with_unit(Unit::new("s")) + .init(); + + let request_size = meter + .u64_histogram(HTTP_SERVER_REQUEST_SIZE) + .with_description("Measures the size of HTTP request messages (compressed).") + .with_unit(Unit::new("By")) + .init(); + + let response_size = meter + .u64_histogram(HTTP_SERVER_RESPONSE_SIZE) + .with_description("Measures the size of HTTP request messages (compressed).") + .with_unit(Unit::new("By")) .init(); Config { active_requests, duration, + request_size, + response_size, } } } @@ -70,6 +80,8 @@ impl Transform for Config { h, active_requests: self.active_requests.clone(), duration: self.duration.clone(), + request_size: self.request_size.clone(), + response_size: self.response_size.clone(), } } } @@ -80,6 +92,8 @@ pub struct MetricsMiddleware { h: H, active_requests: UpDownCounter, duration: Histogram, + request_size: Histogram, + response_size: Histogram, } #[async_trait] @@ -92,10 +106,12 @@ where async fn call(&self, req: Request) -> Self::Output { let timer = SystemTime::now(); - let cx = Context::current(); let mut attributes = build_attributes(&req, req.route_info().pattern.as_str()); - self.active_requests.add(&cx, 1, &attributes); + self.active_requests.add(1, &attributes); + + self.request_size + .record(req.content_length().unwrap_or(0), &attributes); let resp = self .h @@ -103,19 +119,18 @@ where .await .map(IntoResponse::into_response) .map(|resp| { - self.active_requests.add(&cx, -1, &attributes); + self.active_requests.add(-1, &attributes); - attributes.push(HTTP_STATUS_CODE.i64(i64::from(resp.status().as_u16()))); + attributes.push(HTTP_RESPONSE_STATUS_CODE.i64(i64::from(resp.status().as_u16()))); + + self.response_size + .record(resp.content_length().unwrap_or(0), &attributes); resp }); self.duration.record( - &cx, - timer - .elapsed() - .map(|t| t.as_secs_f64() * 1000.0) - .unwrap_or_default(), + timer.elapsed().map(|t| t.as_secs_f64()).unwrap_or_default(), &attributes, ); @@ -124,51 +139,39 @@ where } fn build_attributes(req: &Request, http_route: &str) -> Vec { - let mut attributes = Vec::with_capacity(10); - attributes.push( - HTTP_SCHEME.string( - req.schema() - .or(Some(&Scheme::HTTP)) - .map(ToString::to_string) - .unwrap(), - ), - ); - attributes.push(HTTP_FLAVOR.string(format!("{:?}", req.version()))); - attributes.push(HTTP_METHOD.string(req.method().to_string())); + let mut attributes = Vec::with_capacity(5); + // attributes.push(HTTP_ROUTE.string(http_route.to_string())); - if let Some(path_and_query) = req.uri().path_and_query() { - attributes.push(HTTP_TARGET.string(path_and_query.as_str().to_string())); - } - if let Some(host) = req.uri().host() { - attributes.push(HTTP_HOST.string(host.to_string())); - } - if let Some(user_agent) = req - .header_typed::() - .as_ref() - .map(UserAgent::as_str) - { - attributes.push(HTTP_USER_AGENT.string(user_agent.to_string())); + + // + attributes.push(HTTP_REQUEST_METHOD.string(req.method().to_string())); + attributes.push(NETWORK_PROTOCOL_VERSION.string(format!("{:?}", req.version()))); + + let remote_addr = req.remote_addr(); + if let Some(remote_addr) = remote_addr { + attributes.push(CLIENT_ADDRESS.string(remote_addr.to_string())); } - let realip = req.realip(); - if let Some(realip) = realip { - attributes.push(HTTP_CLIENT_IP.string(realip.0.to_string())); + if let Some(realip) = req.realip().map(|value| value.0).filter(|realip| { + remote_addr + .map(SocketAddr::ip) + .map_or(true, |remoteip| &remoteip != realip) + }) { + attributes.push(CLIENT_SOCKET_ADDRESS.string(realip.to_string())); } - // if server_name != host { - // attributes.insert(HTTP_SERVER_NAME, server_name.to_string().into()); - // } - if let Some(remote_ip) = req.remote_addr().map(std::net::SocketAddr::ip) { - if realip.map_or(true, |realip| realip.0 != remote_ip) { - // Client is going through a proxy - attributes.push(NET_SOCK_PEER_ADDR.string(remote_ip.to_string())); - } + + let uri = req.uri(); + if let Some(host) = uri.host() { + attributes.push(SERVER_ADDRESS.string(host.to_string())); } - if let Some(port) = req - .uri() + if let Some(port) = uri .port_u16() - .filter(|port| *port != 80 || *port != 443) + .and_then(|port| i64::try_from(port).ok()) + .filter(|port| *port != 80 && *port != 443) { - attributes.push(NET_HOST_PORT.i64(i64::from(port))); + attributes.push(SERVER_PORT.i64(port)); } + attributes.push(URL_SCHEME.string(uri.scheme().unwrap_or(&Scheme::HTTP).to_string())); + attributes } diff --git a/viz-core/src/middleware/otel/mod.rs b/viz-core/src/middleware/otel/mod.rs index 495c60b2..b6e24c54 100644 --- a/viz-core/src/middleware/otel/mod.rs +++ b/viz-core/src/middleware/otel/mod.rs @@ -1,8 +1,5 @@ //! Opentelemetry request tracking & metrics middleware. -/// `http.host` key -pub const HTTP_HOST: opentelemetry::Key = opentelemetry::Key::from_static_str("http.host"); - #[cfg(feature = "otel-metrics")] pub mod metrics; #[cfg(feature = "otel-tracing")] diff --git a/viz-core/src/middleware/otel/tracing.rs b/viz-core/src/middleware/otel/tracing.rs index 01079afa..1787a476 100644 --- a/viz-core/src/middleware/otel/tracing.rs +++ b/viz-core/src/middleware/otel/tracing.rs @@ -2,7 +2,7 @@ //! //! [`OpenTelemetry`]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md -use std::sync::Arc; +use std::{net::SocketAddr, sync::Arc}; use http::uri::Scheme; use opentelemetry::{ @@ -14,28 +14,17 @@ use opentelemetry::{ Context, Key, Value, }; use opentelemetry_semantic_conventions::trace::{ - EXCEPTION_MESSAGE, - HTTP_CLIENT_IP, - HTTP_FLAVOR, - HTTP_METHOD, - HTTP_RESPONSE_CONTENT_LENGTH, - HTTP_ROUTE, - HTTP_SCHEME, - // , HTTP_SERVER_NAME - HTTP_STATUS_CODE, - HTTP_TARGET, - HTTP_USER_AGENT, - NET_HOST_PORT, - NET_SOCK_PEER_ADDR, + CLIENT_ADDRESS, CLIENT_SOCKET_ADDRESS, EXCEPTION_MESSAGE, HTTP_REQUEST_BODY_SIZE, + HTTP_REQUEST_METHOD, HTTP_RESPONSE_BODY_SIZE, HTTP_RESPONSE_STATUS_CODE, HTTP_ROUTE, + NETWORK_PROTOCOL_VERSION, SERVER_ADDRESS, SERVER_PORT, URL_PATH, URL_QUERY, URL_SCHEME, + USER_AGENT_ORIGINAL, }; -use super::HTTP_HOST; - use crate::{ async_trait, header::{HeaderMap, HeaderName}, - headers::{self, HeaderMapExt, UserAgent}, - Handler, IntoResponse, Request, RequestExt, Response, Result, Transform, + headers::UserAgent, + Handler, IntoResponse, Request, RequestExt, Response, ResponseExt, Result, Transform, }; /// `OpenTelemetry` tracing config. @@ -111,11 +100,13 @@ where Ok(resp) => { let resp = resp.into_response(); span.add_event("request.completed".to_string(), vec![]); - span.set_attribute(HTTP_STATUS_CODE.i64(i64::from(resp.status().as_u16()))); - if let Some(content_length) = resp.headers().typed_get::() { + span.set_attribute( + HTTP_RESPONSE_STATUS_CODE.i64(i64::from(resp.status().as_u16())), + ); + if let Some(content_length) = resp.content_length() { span.set_attribute( - HTTP_RESPONSE_CONTENT_LENGTH - .i64(i64::try_from(content_length.0).unwrap_or(i64::MAX)), + HTTP_RESPONSE_BODY_SIZE + .i64(i64::try_from(content_length).unwrap_or(i64::MAX)), ); } if resp.status().is_server_error() { @@ -164,49 +155,68 @@ impl<'a> Extractor for RequestHeaderCarrier<'a> { fn build_attributes(req: &Request, http_route: &str) -> OrderMap { let mut attributes = OrderMap::::with_capacity(10); + // + attributes.insert(HTTP_ROUTE, http_route.to_string().into()); + + // + attributes.insert(HTTP_REQUEST_METHOD, req.method().to_string().into()); attributes.insert( - HTTP_SCHEME, - req.schema() - .or(Some(&Scheme::HTTP)) - .map(ToString::to_string) - .unwrap() - .into(), + NETWORK_PROTOCOL_VERSION, + format!("{:?}", req.version()).into(), ); - attributes.insert(HTTP_FLAVOR, format!("{:?}", req.version()).into()); - attributes.insert(HTTP_METHOD, req.method().to_string().into()); - attributes.insert(HTTP_ROUTE, http_route.to_string().into()); - if let Some(path_and_query) = req.uri().path_and_query() { - attributes.insert(HTTP_TARGET, path_and_query.as_str().to_string().into()); + + let remote_addr = req.remote_addr(); + if let Some(remote_addr) = remote_addr { + attributes.insert(CLIENT_ADDRESS, remote_addr.to_string().into()); } - if let Some(host) = req.uri().host() { - attributes.insert(HTTP_HOST, host.to_string().into()); + if let Some(realip) = req.realip().map(|value| value.0).filter(|realip| { + remote_addr + .map(SocketAddr::ip) + .map_or(true, |remoteip| &remoteip != realip) + }) { + attributes.insert(CLIENT_SOCKET_ADDRESS, realip.to_string().into()); } - if let Some(user_agent) = req - .header_typed::() - .as_ref() - .map(UserAgent::as_str) - { - attributes.insert(HTTP_USER_AGENT, user_agent.to_string().into()); + + let uri = req.uri(); + if let Some(host) = uri.host() { + attributes.insert(SERVER_ADDRESS, host.to_string().into()); } - let realip = req.realip(); - if let Some(realip) = realip { - attributes.insert(HTTP_CLIENT_IP, realip.0.to_string().into()); + if let Some(port) = uri + .port_u16() + .and_then(|len| i64::try_from(len).ok()) + .filter(|port| *port != 80 && *port != 443) + { + attributes.insert(SERVER_PORT, port.into()); } - // if server_name != host { - // attributes.insert(HTTP_SERVER_NAME, server_name.to_string().into()); - // } - if let Some(remote_ip) = req.remote_addr().map(std::net::SocketAddr::ip) { - if realip.map_or(true, |realip| realip.0 != remote_ip) { - // Client is going through a proxy - attributes.insert(NET_SOCK_PEER_ADDR, remote_ip.to_string().into()); + + if let Some(path_query) = uri.path_and_query() { + if path_query.path() != "/" { + attributes.insert(URL_PATH, path_query.path().to_string().into()); + } + if let Some(query) = path_query.query() { + attributes.insert(URL_QUERY, query.to_string().into()); } } - if let Some(port) = req - .uri() - .port_u16() - .filter(|port| *port != 80 || *port != 443) + + attributes.insert( + URL_SCHEME, + uri.scheme().unwrap_or(&Scheme::HTTP).to_string().into(), + ); + + if let Some(content_length) = req + .content_length() + .and_then(|len| i64::try_from(len).ok()) + .filter(|len| *len > 0) + { + attributes.insert(HTTP_REQUEST_BODY_SIZE, content_length.into()); + } + + if let Some(user_agent) = req + .header_typed::() + .as_ref() + .map(UserAgent::as_str) { - attributes.insert(NET_HOST_PORT, port.to_string().into()); + attributes.insert(USER_AGENT_ORIGINAL, user_agent.to_string().into()); } attributes diff --git a/viz-core/src/request.rs b/viz-core/src/request.rs index 485a1ee4..1c071c58 100644 --- a/viz-core/src/request.rs +++ b/viz-core/src/request.rs @@ -1,5 +1,3 @@ -#![allow(clippy::module_name_repetitions)] - use std::{mem::replace, sync::Arc}; use crate::{ @@ -48,8 +46,8 @@ pub trait RequestExt: Sized { /// Get URL's query string of this request. fn query_string(&self) -> Option<&str>; - #[cfg(feature = "query")] /// Get query data by type. + #[cfg(feature = "query")] fn query(&self) -> Result where T: serde::de::DeserializeOwned; diff --git a/viz-core/src/response.rs b/viz-core/src/response.rs index 828b2b60..892dd994 100644 --- a/viz-core/src/response.rs +++ b/viz-core/src/response.rs @@ -1,5 +1,3 @@ -#![allow(clippy::module_name_repetitions)] - #[cfg(feature = "json")] use bytes::{BufMut, BytesMut}; use http_body_util::Full; @@ -8,6 +6,9 @@ use crate::{header, Bytes, Error, OutgoingBody, Response, Result, StatusCode}; /// The [Response] Extension. pub trait ResponseExt: Sized { + /// Get the size of this response's body. + fn content_length(&self) -> Option; + /// The response with the specified [`Content-Type`][mdn]. /// /// [mdn]: @@ -138,6 +139,13 @@ pub trait ResponseExt: Sized { } impl ResponseExt for Response { + fn content_length(&self) -> Option { + self.headers() + .get(header::CONTENT_LENGTH) + .and_then(|v| v.to_str().ok()) + .and_then(|v| v.parse().ok()) + } + fn ok(&self) -> bool { self.status().is_success() } diff --git a/viz-core/src/types/mod.rs b/viz-core/src/types/mod.rs index 5600502c..f00d9130 100644 --- a/viz-core/src/types/mod.rs +++ b/viz-core/src/types/mod.rs @@ -1,7 +1,5 @@ //! Built-in Extractors types and traits. -#![allow(clippy::module_name_repetitions)] - #[cfg(feature = "cookie")] mod cookie; #[cfg(any(feature = "cookie-signed", feature = "cookie-private"))] diff --git a/viz-handlers/Cargo.toml b/viz-handlers/Cargo.toml index c93ecdca..7713b577 100644 --- a/viz-handlers/Cargo.toml +++ b/viz-handlers/Cargo.toml @@ -31,6 +31,7 @@ prometheus = [ "dep:http-body-util", "opentelemetry/metrics", "dep:opentelemetry-prometheus", + "dep:prometheus" ] [dependencies] @@ -57,6 +58,7 @@ rust-embed = { workspace = true, optional = true } # OpenTelemetry opentelemetry = { workspace = true, default-features = false, optional = true } opentelemetry-prometheus = { workspace = true, optional = true } +prometheus = { workspace = true, optional = true } [dev-dependencies] tokio = { workspace = true, features = ["rt", "macros"] } diff --git a/viz-handlers/src/prometheus/mod.rs b/viz-handlers/src/prometheus/mod.rs index eeb7b102..484b9320 100644 --- a/viz-handlers/src/prometheus/mod.rs +++ b/viz-handlers/src/prometheus/mod.rs @@ -4,7 +4,7 @@ use http_body_util::Full; use opentelemetry::{global::handle_error, metrics::MetricsError}; -use opentelemetry_prometheus::{Encoder, PrometheusExporter, TextEncoder}; +use prometheus::{Encoder, TextEncoder}; use viz_core::{ async_trait, @@ -14,20 +14,20 @@ use viz_core::{ #[doc(inline)] pub use opentelemetry_prometheus::ExporterBuilder; +#[doc(inline)] +pub use prometheus::Registry; -/// The [`PrometheusExporter`] wrapper. -/// -/// [`PrometheusExporter`]: opentelemetry_prometheus::PrometheusExporter +/// The [`Registry`] wrapper. #[derive(Clone, Debug)] pub struct Prometheus { - exporter: PrometheusExporter, + registry: Registry, } impl Prometheus { /// Creates a new Prometheus. #[must_use] - pub fn new(exporter: PrometheusExporter) -> Self { - Self { exporter } + pub fn new(registry: Registry) -> Self { + Self { registry } } } @@ -36,7 +36,7 @@ impl Handler for Prometheus { type Output = Result; async fn call(&self, _: Request) -> Self::Output { - let metric_families = self.exporter.registry().gather(); + let metric_families = self.registry.gather(); let encoder = TextEncoder::new(); let mut body = Vec::new(); diff --git a/viz/src/lib.rs b/viz/src/lib.rs index 6f8f2790..d04f2c23 100644 --- a/viz/src/lib.rs +++ b/viz/src/lib.rs @@ -91,7 +91,7 @@ //! type Output = Result; //! //! async fn call(&self, req: Request) -> Self::Output { -//! let path = req.path().clone(); +//! let path = req.path(); //! let method = req.method().clone(); //! let code = self.code.fetch_add(1, Ordering::SeqCst); //! Ok(format!("code = {}, method = {}, path = {}", code, method, path).into_response())