1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-07 22:41:18 +03:00

OpenTelemetry upgrade

This commit is contained in:
Quentin Gliech
2023-08-07 14:20:37 +02:00
parent 6e8222c765
commit 699dfba55f
13 changed files with 225 additions and 242 deletions

View File

@ -34,12 +34,13 @@ tracing-appender = "0.2.2"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
tracing-opentelemetry = "0.20.0"
opentelemetry = { version = "0.20.0", features = ["trace", "metrics", "rt-tokio"] }
opentelemetry-semantic-conventions = "0.12.0"
opentelemetry-http = { version = "0.9.0", features = ["tokio", "hyper"] }
opentelemetry-jaeger = { version = "0.19.0", features = ["rt-tokio", "collector_client"] }
opentelemetry-otlp = { version = "0.13.0", features = ["trace", "metrics"] }
opentelemetry-zipkin = { version = "0.17.0", features = ["opentelemetry-http"], default-features = false }
opentelemetry-http = { version = "0.9.0", features = ["tokio", "hyper"] }
opentelemetry-prometheus = { version = "0.13.0" }
opentelemetry-prometheus = "0.13.0"
opentelemetry-semantic-conventions = "0.12.0"
opentelemetry-stdout = { version = "0.1.0", features = ["trace", "metrics"] }
opentelemetry-zipkin = { version = "0.18.0", default-features = false }
prometheus = "0.13.3"
sentry = { version = "0.31.5", default-features = false, features = ["backtrace", "contexts", "panic", "tower"] }
sentry-tracing = "0.31.5"

View File

@ -100,7 +100,7 @@ async fn try_main() -> anyhow::Result<()> {
});
// Setup OpenTelemetry tracing and metrics
let (tracer, _meter) = telemetry::setup(&telemetry_config)
let tracer = telemetry::setup(&telemetry_config)
.await
.context("failed to setup OpenTelemetry")?;

View File

@ -13,7 +13,6 @@
// limitations under the License.
use std::{
borrow::Cow,
future::ready,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpListener, ToSocketAddrs},
os::unix::net::UnixListener,
@ -27,7 +26,7 @@ use axum::{
Extension, Router,
};
use hyper::{
header::{HeaderValue, CACHE_CONTROL},
header::{HeaderValue, CACHE_CONTROL, USER_AGENT},
Method, Request, Response, StatusCode, Version,
};
use listenfd::ListenFd;
@ -40,10 +39,11 @@ use mas_tower::{
make_span_fn, metrics_attributes_fn, DurationRecorderLayer, InFlightCounterLayer, TraceLayer,
KV,
};
use opentelemetry::{Key, KeyValue};
use opentelemetry::{trace::TraceContextExt, Key, KeyValue};
use opentelemetry_http::HeaderExtractor;
use opentelemetry_semantic_conventions::trace::{
HTTP_METHOD, HTTP_ROUTE, HTTP_SCHEME, HTTP_STATUS_CODE,
HTTP_REQUEST_METHOD, HTTP_RESPONSE_STATUS_CODE, HTTP_ROUTE, NETWORK_PROTOCOL_NAME,
NETWORK_PROTOCOL_VERSION, URL_SCHEME,
};
use rustls::ServerConfig;
use sentry_tower::{NewSentryLayer, SentryHttpLayer};
@ -52,35 +52,33 @@ use tower_http::{services::ServeDir, set_header::SetResponseHeaderLayer};
use tracing::{warn, Span};
use tracing_opentelemetry::OpenTelemetrySpanExt;
const NET_PROTOCOL_NAME: Key = Key::from_static_str("net.protocol.name");
const NET_PROTOCOL_VERSION: Key = Key::from_static_str("net.protocol.version");
const MAS_LISTENER_NAME: Key = Key::from_static_str("mas.listener.name");
#[inline]
fn otel_http_method<B>(request: &Request<B>) -> Cow<'static, str> {
fn otel_http_method<B>(request: &Request<B>) -> &'static str {
match request.method() {
&Method::OPTIONS => "OPTIONS".into(),
&Method::GET => "GET".into(),
&Method::POST => "POST".into(),
&Method::PUT => "PUT".into(),
&Method::DELETE => "DELETE".into(),
&Method::HEAD => "HEAD".into(),
&Method::TRACE => "TRACE".into(),
&Method::CONNECT => "CONNECT".into(),
&Method::PATCH => "PATCH".into(),
other => other.to_string().into(),
&Method::OPTIONS => "OPTIONS",
&Method::GET => "GET",
&Method::POST => "POST",
&Method::PUT => "PUT",
&Method::DELETE => "DELETE",
&Method::HEAD => "HEAD",
&Method::TRACE => "TRACE",
&Method::CONNECT => "CONNECT",
&Method::PATCH => "PATCH",
_other => "_OTHER",
}
}
#[inline]
fn otel_net_protocol_version<B>(request: &Request<B>) -> Cow<'static, str> {
fn otel_net_protocol_version<B>(request: &Request<B>) -> &'static str {
match request.version() {
Version::HTTP_09 => "0.9".into(),
Version::HTTP_10 => "1.0".into(),
Version::HTTP_11 => "1.1".into(),
Version::HTTP_2 => "2.0".into(),
Version::HTTP_3 => "3.0".into(),
other => format!("{other:?}").into(),
Version::HTTP_09 => "0.9",
Version::HTTP_10 => "1.0",
Version::HTTP_11 => "1.1",
Version::HTTP_2 => "2.0",
Version::HTTP_3 => "3.0",
_other => "_OTHER",
}
}
@ -91,11 +89,7 @@ fn otel_http_route<B>(request: &Request<B>) -> Option<&str> {
.map(MatchedPath::as_str)
}
fn otel_http_target<B>(request: &Request<B>) -> &str {
request.uri().path_and_query().map_or("", |p| p.as_str())
}
fn otel_http_scheme<B>(request: &Request<B>) -> &'static str {
fn otel_url_scheme<B>(request: &Request<B>) -> &'static str {
// XXX: maybe we should panic if the connection info was not injected in the
// request extensions
request
@ -117,7 +111,7 @@ fn make_http_span<B>(req: &Request<B>) -> Span {
let span_name = if let Some(route) = route.as_ref() {
format!("{method} {route}")
} else {
format!("{method}")
method.to_owned()
};
let span = tracing::info_span!(
@ -125,42 +119,60 @@ fn make_http_span<B>(req: &Request<B>) -> Span {
"otel.kind" = "server",
"otel.name" = span_name,
"otel.status_code" = tracing::field::Empty,
"net.protocol.name" = "http",
"net.protocol.version" = otel_net_protocol_version(req).as_ref(),
"http.scheme" = otel_http_scheme(req),
"http.method" = method.as_ref(),
"network.protocol.name" = "http",
"network.protocol.version" = otel_net_protocol_version(req),
"http.method" = method,
"http.route" = tracing::field::Empty,
"http.target" = otel_http_target(req),
"http.status_code" = tracing::field::Empty,
"http.response.status_code" = tracing::field::Empty,
"url.path" = req.uri().path(),
"url.query" = tracing::field::Empty,
"url.scheme" = otel_url_scheme(req),
"user_agent.original" = tracing::field::Empty,
);
if let Some(route) = route.as_ref() {
span.record("http.route", route);
}
if let Some(query) = req.uri().query() {
span.record("url.query", query);
}
if let Some(user_agent) = req.headers().get(USER_AGENT) {
span.record(
"user_agent.original",
user_agent.to_str().unwrap_or("INVALID"),
);
}
// Extract the parent span context from the request headers
let parent_context = opentelemetry::global::get_text_map_propagator(|propagator| {
let extractor = HeaderExtractor(req.headers());
let context = opentelemetry::Context::new();
propagator.extract_with_context(&context, &extractor)
});
span.set_parent(parent_context);
if parent_context.span().span_context().is_remote() {
// For now, set_parent is broken, so in the meantime we're using add_link
// instead
span.add_link(parent_context.span().span_context().clone());
}
span
}
fn on_http_request_labels<B>(request: &Request<B>) -> Vec<KeyValue> {
vec![
NET_PROTOCOL_NAME.string("http"),
NET_PROTOCOL_VERSION.string(otel_net_protocol_version(request)),
HTTP_METHOD.string(otel_http_method(request)),
HTTP_SCHEME.string(otel_http_scheme(request).as_ref()),
NETWORK_PROTOCOL_NAME.string("http"),
NETWORK_PROTOCOL_VERSION.string(otel_net_protocol_version(request)),
HTTP_REQUEST_METHOD.string(otel_http_method(request)),
HTTP_ROUTE.string(otel_http_route(request).unwrap_or("FALLBACK").to_owned()),
URL_SCHEME.string(otel_url_scheme(request).as_ref()),
]
}
fn on_http_response_labels<B>(res: &Response<B>) -> Vec<KeyValue> {
vec![HTTP_STATUS_CODE.i64(res.status().as_u16().into())]
vec![HTTP_RESPONSE_STATUS_CODE.i64(res.status().as_u16().into())]
}
pub fn build_router<B>(
@ -259,7 +271,7 @@ where
))
.on_response_fn(|span: &Span, response: &Response<_>| {
let status_code = response.status().as_u16();
span.record("http.status_code", status_code);
span.record("http.response.status_code", status_code);
span.record("otel.status_code", "OK");
}),
)

View File

@ -25,26 +25,29 @@ use opentelemetry::{
propagation::TextMapPropagator,
sdk::{
self,
metrics::controllers::BasicController,
metrics::{
reader::{DefaultAggregationSelector, DefaultTemporalitySelector},
MeterProvider, PeriodicReader,
},
propagation::{BaggagePropagator, TextMapCompositePropagator, TraceContextPropagator},
trace::{Sampler, Tracer},
trace::{Sampler, Tracer, TracerProvider},
Resource,
},
Context,
trace::TracerProvider as _,
};
use opentelemetry_jaeger::Propagator as JaegerPropagator;
use opentelemetry_otlp::MetricsExporterBuilder;
use opentelemetry_prometheus::PrometheusExporter;
use opentelemetry_semantic_conventions as semcov;
use opentelemetry_zipkin::{B3Encoding, Propagator as ZipkinPropagator};
use prometheus::Registry;
use tokio::sync::OnceCell;
use url::Url;
static METRICS_BASIC_CONTROLLER: OnceCell<BasicController> = OnceCell::const_new();
static PROMETHEUS_EXPORTER: OnceCell<PrometheusExporter> = OnceCell::const_new();
static METER_PROVIDER: OnceCell<MeterProvider> = OnceCell::const_new();
static PROMETHEUS_REGISTRY: OnceCell<Registry> = OnceCell::const_new();
pub async fn setup(
config: &TelemetryConfig,
) -> anyhow::Result<(Option<Tracer>, Option<BasicController>)> {
pub async fn setup(config: &TelemetryConfig) -> anyhow::Result<Option<Tracer>> {
global::set_error_handler(|e| tracing::error!("{}", e))?;
let propagator = propagator(&config.tracing.propagators);
@ -57,20 +60,16 @@ pub async fn setup(
.await
.context("Failed to configure traces exporter")?;
let meter = meter(&config.metrics.exporter).context("Failed to configure metrics exporter")?;
if let Some(meter) = meter.as_ref() {
METRICS_BASIC_CONTROLLER.set(meter.clone())?;
}
init_meter(&config.metrics.exporter).context("Failed to configure metrics exporter")?;
Ok((tracer, meter))
Ok(tracer)
}
pub fn shutdown() {
global::shutdown_tracer_provider();
if let Some(controller) = METRICS_BASIC_CONTROLLER.get() {
let cx = Context::new();
controller.stop(&cx).unwrap();
if let Some(meter_provider) = METER_PROVIDER.get() {
meter_provider.shutdown().unwrap();
}
}
@ -100,11 +99,11 @@ async fn http_client() -> anyhow::Result<impl opentelemetry_http::HttpClient + '
Ok(client)
}
fn stdout_tracer() -> Tracer {
sdk::export::trace::stdout::new_pipeline()
.with_pretty_print(true)
.with_trace_config(trace_config())
.install_simple()
fn stdout_tracer_provider() -> TracerProvider {
let exporter = opentelemetry_stdout::SpanExporter::default();
TracerProvider::builder()
.with_simple_exporter(exporter)
.build()
}
fn otlp_tracer(endpoint: Option<&Url>) -> anyhow::Result<Tracer> {
@ -125,24 +124,24 @@ fn otlp_tracer(endpoint: Option<&Url>) -> anyhow::Result<Tracer> {
Ok(tracer)
}
fn jaeger_agent_tracer(host: &str, port: u16) -> anyhow::Result<Tracer> {
fn jaeger_agent_tracer_provider(host: &str, port: u16) -> anyhow::Result<TracerProvider> {
let pipeline = opentelemetry_jaeger::new_agent_pipeline()
.with_service_name(env!("CARGO_PKG_NAME"))
.with_trace_config(trace_config())
.with_endpoint((host, port));
let tracer = pipeline
.install_batch(opentelemetry::runtime::Tokio)
let tracer_provider = pipeline
.build_batch(opentelemetry::runtime::Tokio)
.context("Failed to configure Jaeger agent exporter")?;
Ok(tracer)
Ok(tracer_provider)
}
async fn jaeger_collector_tracer(
async fn jaeger_collector_tracer_provider(
endpoint: &str,
username: Option<&str>,
password: Option<&str>,
) -> anyhow::Result<Tracer> {
) -> anyhow::Result<TracerProvider> {
let http_client = http_client().await?;
let mut pipeline = opentelemetry_jaeger::new_collector_pipeline()
.with_service_name(env!("CARGO_PKG_NAME"))
@ -158,11 +157,11 @@ async fn jaeger_collector_tracer(
pipeline = pipeline.with_password(password);
}
let tracer = pipeline
.install_batch(opentelemetry::runtime::Tokio)
let tracer_provider = pipeline
.build_batch(opentelemetry::runtime::Tokio)
.context("Failed to configure Jaeger collector exporter")?;
Ok(tracer)
Ok(tracer_provider)
}
async fn zipkin_tracer(collector_endpoint: &Option<Url>) -> anyhow::Result<Tracer> {
@ -185,28 +184,43 @@ async fn zipkin_tracer(collector_endpoint: &Option<Url>) -> anyhow::Result<Trace
}
async fn tracer(config: &TracingExporterConfig) -> anyhow::Result<Option<Tracer>> {
let tracer = match config {
let tracer_provider = match config {
TracingExporterConfig::None => return Ok(None),
TracingExporterConfig::Stdout => stdout_tracer(),
TracingExporterConfig::Otlp { endpoint } => otlp_tracer(endpoint.as_ref())?,
TracingExporterConfig::Stdout => stdout_tracer_provider(),
TracingExporterConfig::Otlp { endpoint } => {
// The OTLP exporter already creates a tracer and installs it
return Ok(Some(otlp_tracer(endpoint.as_ref())?));
}
TracingExporterConfig::Jaeger(JaegerExporterProtocolConfig::UdpThriftCompact {
agent_host,
agent_port,
}) => jaeger_agent_tracer(agent_host, *agent_port)?,
}) => jaeger_agent_tracer_provider(agent_host, *agent_port)?,
TracingExporterConfig::Jaeger(JaegerExporterProtocolConfig::HttpThriftBinary {
endpoint,
username,
password,
}) => jaeger_collector_tracer(endpoint, username.as_deref(), password.as_deref()).await?,
}) => {
jaeger_collector_tracer_provider(endpoint, username.as_deref(), password.as_deref())
.await?
}
TracingExporterConfig::Zipkin { collector_endpoint } => {
zipkin_tracer(collector_endpoint).await?
// The Zipkin exporter already creates a tracer and installs it
return Ok(Some(zipkin_tracer(collector_endpoint).await?));
}
};
let tracer = tracer_provider.versioned_tracer(
env!("CARGO_PKG_NAME"),
Some(env!("CARGO_PKG_VERSION")),
Some(semcov::SCHEMA_URL),
None,
);
global::set_tracer_provider(tracer_provider);
Ok(Some(tracer))
}
fn otlp_meter(endpoint: Option<&url::Url>) -> anyhow::Result<BasicController> {
fn otlp_metric_reader(endpoint: Option<&url::Url>) -> anyhow::Result<PeriodicReader> {
use opentelemetry_otlp::WithExportConfig;
let mut exporter = opentelemetry_otlp::new_exporter().tonic();
@ -214,35 +228,17 @@ fn otlp_meter(endpoint: Option<&url::Url>) -> anyhow::Result<BasicController> {
exporter = exporter.with_endpoint(endpoint.to_string());
}
let controller = opentelemetry_otlp::new_pipeline()
.metrics(
sdk::metrics::selectors::simple::inexpensive(),
sdk::export::metrics::aggregation::cumulative_temporality_selector(),
opentelemetry::runtime::Tokio,
)
.with_resource(resource())
.with_exporter(exporter)
.build()
.context("Failed to configure OTLP metrics exporter")?;
let exporter = MetricsExporterBuilder::from(exporter).build_metrics_exporter(
Box::new(DefaultTemporalitySelector::new()),
Box::new(DefaultAggregationSelector::new()),
)?;
Ok(controller)
Ok(PeriodicReader::builder(exporter, opentelemetry::runtime::Tokio).build())
}
fn stdout_meter() -> anyhow::Result<BasicController> {
let exporter = sdk::export::metrics::stdout().build()?;
let controller = sdk::metrics::controllers::basic(sdk::metrics::processors::factory(
sdk::metrics::selectors::simple::inexpensive(),
exporter.temporality_selector(),
))
.with_resource(resource())
.with_exporter(exporter)
.build();
let cx = Context::new();
controller.start(&cx, opentelemetry::runtime::Tokio)?;
global::set_meter_provider(controller.clone());
Ok(controller)
fn stdout_metric_reader() -> PeriodicReader {
let exporter = opentelemetry_stdout::MetricsExporter::default();
PeriodicReader::builder(exporter, opentelemetry::runtime::Tokio).build()
}
pub fn prometheus_service<T>() -> tower::util::ServiceFn<
@ -250,15 +246,15 @@ pub fn prometheus_service<T>() -> tower::util::ServiceFn<
> {
use prometheus::{Encoder, TextEncoder};
if !PROMETHEUS_EXPORTER.initialized() {
if !PROMETHEUS_REGISTRY.initialized() {
tracing::warn!("A Prometheus resource was mounted on a listener, but the Prometheus exporter was not setup in the config");
}
tower::service_fn(move |_req| {
let response = if let Some(exporter) = PROMETHEUS_EXPORTER.get() {
let response = if let Some(registry) = PROMETHEUS_REGISTRY.get() {
let mut buffer = vec![];
let encoder = TextEncoder::new();
let metric_families = exporter.registry().gather();
let metric_families = registry.gather();
// That shouldn't panic, unless we're constructing invalid labels
encoder.encode(&metric_families, &mut buffer).unwrap();
@ -280,32 +276,41 @@ pub fn prometheus_service<T>() -> tower::util::ServiceFn<
})
}
fn prometheus_meter() -> anyhow::Result<BasicController> {
let controller = sdk::metrics::controllers::basic(sdk::metrics::processors::factory(
// All histogram metrics are in milliseconds. Each bucket is ~2x the previous one.
sdk::metrics::selectors::simple::histogram([
1.0, 3.0, 5.0, 10.0, 30.0, 50.0, 100.0, 300.0, 1000.0,
]),
sdk::export::metrics::aggregation::cumulative_temporality_selector(),
))
.with_resource(resource())
.build();
fn prometheus_metric_reader() -> anyhow::Result<PrometheusExporter> {
let registry = Registry::new();
PROMETHEUS_REGISTRY.set(registry.clone())?;
let exporter = opentelemetry_prometheus::exporter(controller.clone()).try_init()?;
PROMETHEUS_EXPORTER.set(exporter)?;
let exporter = opentelemetry_prometheus::exporter()
.with_registry(registry)
.without_scope_info()
.build()?;
Ok(controller)
Ok(exporter)
}
fn meter(config: &MetricsExporterConfig) -> anyhow::Result<Option<BasicController>> {
let controller = match config {
MetricsExporterConfig::None => None,
MetricsExporterConfig::Stdout => Some(stdout_meter()?),
MetricsExporterConfig::Otlp { endpoint } => Some(otlp_meter(endpoint.as_ref())?),
MetricsExporterConfig::Prometheus => Some(prometheus_meter()?),
fn init_meter(config: &MetricsExporterConfig) -> anyhow::Result<()> {
let mut meter_provider_builder = MeterProvider::builder();
match config {
MetricsExporterConfig::None => {}
MetricsExporterConfig::Stdout => {
meter_provider_builder = meter_provider_builder.with_reader(stdout_metric_reader());
}
MetricsExporterConfig::Otlp { endpoint } => {
meter_provider_builder =
meter_provider_builder.with_reader(otlp_metric_reader(endpoint.as_ref())?);
}
MetricsExporterConfig::Prometheus => {
meter_provider_builder =
meter_provider_builder.with_reader(prometheus_metric_reader()?);
}
};
Ok(controller)
let meter_provider = meter_provider_builder.with_resource(resource()).build();
METER_PROVIDER.set(meter_provider.clone())?;
global::set_meter_provider(meter_provider.clone());
Ok(())
}
fn trace_config() -> sdk::trace::Config {
@ -326,6 +331,7 @@ fn resource() -> Resource {
Box::new(sdk::resource::EnvResourceDetector::new()),
Box::new(sdk::resource::OsResourceDetector),
Box::new(sdk::resource::ProcessResourceDetector),
Box::new(sdk::resource::TelemetryResourceDetector),
],
);

View File

@ -13,6 +13,7 @@ futures-util = "0.3.28"
# Logging and tracing
tracing = "0.1.37"
opentelemetry = "0.20.0"
opentelemetry-semantic-conventions = "0.12.0"
# Error management
thiserror = "1.0.44"

View File

@ -29,7 +29,7 @@ use mas_storage_pg::PgRepository;
use mas_templates::Templates;
use opentelemetry::{
metrics::{Histogram, MetricsError, Unit},
Context, KeyValue,
KeyValue,
};
use rand::SeedableRng;
use sqlx::PgPool;
@ -60,7 +60,12 @@ impl AppState {
/// Returns an error if the metrics could not be initialized.
pub fn init_metrics(&mut self) -> Result<(), MetricsError> {
// XXX: do we want to put that somewhere else?
let meter = opentelemetry::global::meter("mas-handlers");
let meter = opentelemetry::global::meter_with_version(
env!("CARGO_PKG_NAME"),
Some(env!("CARGO_PKG_VERSION")),
Some(opentelemetry_semantic_conventions::SCHEMA_URL),
None,
);
let pool = self.pool.clone();
let usage = meter
.i64_observable_up_down_counter("db.connections.usage")
@ -75,13 +80,13 @@ impl AppState {
.init();
// Observe the number of active and idle connections in the pool
meter.register_callback(move |cx| {
meter.register_callback(&[usage.as_any(), max.as_any()], move |observer| {
let idle = u32::try_from(pool.num_idle()).unwrap_or(u32::MAX);
let used = pool.size() - idle;
let max_conn = pool.options().get_max_connections();
usage.observe(cx, i64::from(idle), &[KeyValue::new("state", "idle")]);
usage.observe(cx, i64::from(used), &[KeyValue::new("state", "used")]);
max.observe(cx, i64::from(max_conn), &[]);
observer.observe_i64(&usage, i64::from(idle), &[KeyValue::new("state", "idle")]);
observer.observe_i64(&usage, i64::from(used), &[KeyValue::new("state", "used")]);
observer.observe_i64(&max, i64::from(max_conn), &[]);
})?;
// Track the connection acquisition time
@ -212,7 +217,7 @@ impl FromRequestParts<AppState> for BoxRepository {
let duration_ms = duration.as_millis().try_into().unwrap_or(u64::MAX);
if let Some(histogram) = &state.conn_acquisition_histogram {
histogram.record(&Context::new(), duration_ms, &[]);
histogram.record(duration_ms, &[]);
}
Ok(repo

View File

@ -42,5 +42,7 @@ pub async fn get(
let content = templates.render_index(&ctx).await?;
tracing::info!("rendered index page");
Ok((cookie_jar, Html(content)))
}

View File

@ -14,6 +14,7 @@ tower = "0.4.13"
tokio = { version = "1.30.0", features = ["time"] }
opentelemetry = { version = "0.20.0", features = ["metrics"] }
opentelemetry-http = "0.9.0"
opentelemetry-semantic-conventions = "0.12.0"
pin-project-lite = "0.2.12"
[features]

View File

@ -27,6 +27,7 @@ fn meter() -> opentelemetry::metrics::Meter {
opentelemetry::global::meter_with_version(
env!("CARGO_PKG_NAME"),
Some(env!("CARGO_PKG_VERSION")),
Some(opentelemetry_semantic_conventions::SCHEMA_URL),
None,
)
}

View File

@ -14,7 +14,7 @@
use std::future::Future;
use opentelemetry::{metrics::Histogram, Context, KeyValue};
use opentelemetry::{metrics::Histogram, KeyValue};
use pin_project_lite::pin_project;
use tokio::time::Instant;
use tower::{Layer, Service};
@ -195,8 +195,7 @@ where
}
}
this.histogram
.record(&Context::new(), duration_ms, &attributes);
this.histogram.record(duration_ms, &attributes);
std::task::Poll::Ready(result)
}
}

View File

@ -16,7 +16,7 @@ use std::future::Future;
use opentelemetry::{
metrics::{Unit, UpDownCounter},
Context, KeyValue,
KeyValue,
};
use pin_project_lite::pin_project;
use tower::{Layer, Service};
@ -98,7 +98,7 @@ struct InFlightGuard {
impl InFlightGuard {
fn new(counter: UpDownCounter<i64>, attributes: Vec<KeyValue>) -> Self {
counter.add(&Context::new(), 1, &attributes);
counter.add(1, &attributes);
Self {
counter,
@ -109,7 +109,7 @@ impl InFlightGuard {
impl Drop for InFlightGuard {
fn drop(&mut self) {
self.counter.add(&Context::new(), -1, &self.attributes);
self.counter.add(-1, &self.attributes);
}
}

View File

@ -54,7 +54,8 @@ where
// Poll the inner future, with the span entered. This is effectively what
// [`tracing::Instrumented`] does.
let result = ready!(this.span.in_scope(|| this.inner.poll(cx)));
let _guard = this.span.enter();
let result = ready!(this.inner.poll(cx));
match &result {
Ok(response) => {