1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-09 04:22:45 +03:00

Better tracing attributes in the HTTP client

This commit is contained in:
Quentin Gliech
2023-04-18 14:13:10 +02:00
parent 08f58db08b
commit 09270b2493
2 changed files with 86 additions and 8 deletions

View File

@@ -98,6 +98,7 @@ async fn try_main() -> anyhow::Result<()> {
tracing_opentelemetry::layer() tracing_opentelemetry::layer()
.with_tracer(tracer) .with_tracer(tracer)
.with_tracked_inactivity(false) .with_tracked_inactivity(false)
.with_exception_fields(true)
.with_filter(LevelFilter::INFO) .with_filter(LevelFilter::INFO)
}); });

View File

@@ -14,8 +14,12 @@
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
use http::{header::USER_AGENT, HeaderValue, Request}; use headers::{ContentLength, HeaderMapExt, Host, UserAgent};
use mas_tower::{MakeSpan, TraceContextLayer, TraceContextService, TraceLayer, TraceService}; use http::{header::USER_AGENT, HeaderValue, Request, Response};
use hyper::client::connect::HttpInfo;
use mas_tower::{
EnrichSpan, MakeSpan, TraceContextLayer, TraceContextService, TraceLayer, TraceService,
};
use tokio::sync::Semaphore; use tokio::sync::Semaphore;
use tower::{ use tower::{
limit::{ConcurrencyLimit, GlobalConcurrencyLimitLayer}, limit::{ConcurrencyLimit, GlobalConcurrencyLimitLayer},
@@ -26,10 +30,18 @@ use tower_http::{
set_header::{SetRequestHeader, SetRequestHeaderLayer}, set_header::{SetRequestHeader, SetRequestHeaderLayer},
timeout::{Timeout, TimeoutLayer}, timeout::{Timeout, TimeoutLayer},
}; };
use tracing::Span;
pub type ClientService<S> = SetRequestHeader< pub type ClientService<S> = SetRequestHeader<
ConcurrencyLimit< ConcurrencyLimit<
FollowRedirect<TraceService<TraceContextService<Timeout<S>>, MakeSpanForRequest>>, FollowRedirect<
TraceService<
TraceContextService<Timeout<S>>,
MakeSpanForRequest,
EnrichSpanOnResponse,
EnrichSpanOnError,
>,
>,
>, >,
HeaderValue, HeaderValue,
>; >;
@@ -38,22 +50,85 @@ pub type ClientService<S> = SetRequestHeader<
pub struct MakeSpanForRequest; pub struct MakeSpanForRequest;
impl<B> MakeSpan<Request<B>> for MakeSpanForRequest { impl<B> MakeSpan<Request<B>> for MakeSpanForRequest {
fn make_span(&self, request: &Request<B>) -> tracing::Span { fn make_span(&self, request: &Request<B>) -> Span {
// TODO: better attributes let headers = request.headers();
let host = headers.typed_get::<Host>().map(tracing::field::display);
let user_agent = headers
.typed_get::<UserAgent>()
.map(tracing::field::display);
let content_length = headers.typed_get().map(|ContentLength(len)| len);
let net_sock_peer_name = request.uri().host();
tracing::info_span!( tracing::info_span!(
"http.client.request", "http.client.request",
"otel.kind" = "client",
"otel.status_code" = tracing::field::Empty,
"http.method" = %request.method(), "http.method" = %request.method(),
"http.uri" = %request.uri(), "http.url" = %request.uri(),
"http.status_code" = tracing::field::Empty,
"http.host" = host,
"http.request_content_length" = content_length,
"http.response_content_length" = tracing::field::Empty,
"net.transport" = "ip_tcp",
"net.sock.family" = tracing::field::Empty,
"net.sock.peer.name" = net_sock_peer_name,
"net.sock.peer.addr" = tracing::field::Empty,
"net.sock.peer.port" = tracing::field::Empty,
"net.sock.host.addr" = tracing::field::Empty,
"net.sock.host.port" = tracing::field::Empty,
"user_agent.original" = user_agent,
"rust.error" = tracing::field::Empty,
) )
} }
} }
#[derive(Debug, Clone)]
pub struct EnrichSpanOnResponse;
impl<B> EnrichSpan<Response<B>> for EnrichSpanOnResponse {
fn enrich_span(&self, span: &Span, response: &Response<B>) {
span.record("otel.status_code", "OK");
span.record("http.status_code", response.status().as_u16());
if let Some(ContentLength(content_length)) = response.headers().typed_get() {
span.record("http.response_content_length", content_length);
}
if let Some(http_info) = response.extensions().get::<HttpInfo>() {
let local = http_info.local_addr();
let remote = http_info.remote_addr();
let family = if local.is_ipv4() { "inet" } else { "inet6" };
span.record("net.sock.family", family);
span.record("net.sock.peer.addr", remote.ip().to_string());
span.record("net.sock.peer.port", remote.port());
span.record("net.sock.host.addr", local.ip().to_string());
span.record("net.sock.host.port", local.port());
} else {
tracing::warn!("No HttpInfo injected in response extensions");
}
}
}
#[derive(Debug, Clone)]
pub struct EnrichSpanOnError;
impl<E> EnrichSpan<E> for EnrichSpanOnError
where
E: std::error::Error + 'static,
{
fn enrich_span(&self, span: &Span, error: &E) {
span.record("otel.status_code", "ERROR");
span.record("rust.error", error as &dyn std::error::Error);
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ClientLayer { pub struct ClientLayer {
user_agent_layer: SetRequestHeaderLayer<HeaderValue>, user_agent_layer: SetRequestHeaderLayer<HeaderValue>,
concurrency_limit_layer: GlobalConcurrencyLimitLayer, concurrency_limit_layer: GlobalConcurrencyLimitLayer,
follow_redirect_layer: FollowRedirectLayer, follow_redirect_layer: FollowRedirectLayer,
trace_layer: TraceLayer<MakeSpanForRequest>, trace_layer: TraceLayer<MakeSpanForRequest, EnrichSpanOnResponse, EnrichSpanOnError>,
trace_context_layer: TraceContextLayer, trace_context_layer: TraceContextLayer,
timeout_layer: TimeoutLayer, timeout_layer: TimeoutLayer,
} }
@@ -80,7 +155,9 @@ impl ClientLayer {
), ),
concurrency_limit_layer: GlobalConcurrencyLimitLayer::with_semaphore(semaphore), concurrency_limit_layer: GlobalConcurrencyLimitLayer::with_semaphore(semaphore),
follow_redirect_layer: FollowRedirectLayer::new(), follow_redirect_layer: FollowRedirectLayer::new(),
trace_layer: TraceLayer::new(MakeSpanForRequest), trace_layer: TraceLayer::new(MakeSpanForRequest)
.on_response(EnrichSpanOnResponse)
.on_error(EnrichSpanOnError),
trace_context_layer: TraceContextLayer::new(), trace_context_layer: TraceContextLayer::new(),
timeout_layer: TimeoutLayer::new(Duration::from_secs(10)), timeout_layer: TimeoutLayer::new(Duration::from_secs(10)),
} }