use super::shared::{make_grpc_request_span, should_trace_request};
use crate::tonic::common::get_status_code_from_headers;
use http::HeaderMap;
use qcs_api_client_common::tracing_configuration::{TracingConfiguration, TracingFilter};
use tracing::Span;
#[derive(Clone, Debug)]
pub struct MakeSpan {
enabled: bool,
filter: Option<TracingFilter>,
base_url: String,
}
impl<B> tower_http::trace::MakeSpan<B> for MakeSpan {
fn make_span(&mut self, request: &http::Request<B>) -> tracing::Span {
if self.enabled
&& should_trace_request(self.base_url.as_str(), request, self.filter.as_ref())
{
make_grpc_request_span(request)
} else {
tracing::Span::none()
}
}
}
#[derive(Clone, Debug)]
pub struct OnEos {
inner: tower_http::trace::DefaultOnEos,
}
impl tower_http::trace::OnEos for OnEos {
fn on_eos(
self,
trailers: Option<&HeaderMap>,
stream_duration: std::time::Duration,
span: &Span,
) {
if let Some(trailers) = trailers {
if let Ok(status_code) = get_status_code_from_headers(trailers) {
span.record("rpc.grpc.status_code", format!("{}", status_code as u8));
}
}
self.inner.on_eos(trailers, stream_duration, span);
}
}
pub type CustomTraceLayer = tower_http::trace::TraceLayer<
tower_http::classify::SharedClassifier<tower_http::classify::GrpcErrorsAsFailures>,
MakeSpan,
tower_http::trace::DefaultOnRequest,
tower_http::trace::DefaultOnResponse,
tower_http::trace::DefaultOnBodyChunk,
OnEos,
super::shared::OnFailure,
>;
pub type CustomTraceService = tower_http::trace::Trace<
tonic::transport::Channel,
tower_http::classify::SharedClassifier<tower_http::classify::GrpcErrorsAsFailures>,
MakeSpan,
tower_http::trace::DefaultOnRequest,
tower_http::trace::DefaultOnResponse,
tower_http::trace::DefaultOnBodyChunk,
OnEos,
super::shared::OnFailure,
>;
#[must_use]
pub fn build_layer(
base_url: String,
configuration: Option<&TracingConfiguration>,
) -> CustomTraceLayer {
tower_http::trace::TraceLayer::new_for_grpc()
.on_eos(OnEos {
inner: tower_http::trace::DefaultOnEos::default(),
})
.make_span_with(MakeSpan {
enabled: configuration.is_some(),
filter: configuration
.as_ref()
.and_then(|configuration| configuration.filter())
.cloned(),
base_url: base_url.clone(),
})
.on_failure(super::shared::OnFailure {
inner: tower_http::trace::DefaultOnFailure::default(),
})
.on_response(tower_http::trace::DefaultOnResponse::default())
}