use std::time::Instant;
use super::defs::{ATTR_FUSE_REQUEST, FUSE_REQUEST_LATENCY};
use metrics::histogram;
use tracing::span::Attributes;
use tracing::{Id, Level, Subscriber};
use tracing_subscriber::Layer;
use tracing_subscriber::filter::Targets;
use tracing_subscriber::layer::Context;
use tracing_subscriber::registry::{LookupSpan, SpanRef};
const FUSE_MODULE_NAME: &str = "mountpoint_s3_fs::fuse";
#[derive(Debug)]
struct MetricsTracingSpanLayer;
impl MetricsTracingSpanLayer {
fn should_instrument_request_time<'a, S: LookupSpan<'a>>(span: Option<SpanRef<'a, S>>) -> bool {
if let Some(data) = span
&& data.metadata().target() == FUSE_MODULE_NAME
&& data.parent().is_none()
{
return true;
}
false
}
}
impl<S> Layer<S> for MetricsTracingSpanLayer
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
fn on_new_span(&self, _attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
if Self::should_instrument_request_time(ctx.span(id)) {
let data = ctx.span(id).unwrap();
data.extensions_mut().insert(RequestTime(Instant::now()));
}
}
fn on_close(&self, id: Id, ctx: Context<'_, S>) {
if Self::should_instrument_request_time(ctx.span(&id)) {
let data = ctx.span(&id).unwrap();
let RequestTime(start_time) = *data.extensions().get::<RequestTime>().unwrap();
histogram!(FUSE_REQUEST_LATENCY, ATTR_FUSE_REQUEST => data.name())
.record(start_time.elapsed().as_micros() as f64);
}
}
}
pub fn metrics_tracing_span_layer<S>() -> impl Layer<S>
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
MetricsTracingSpanLayer.with_filter(Targets::new().with_target(FUSE_MODULE_NAME, Level::WARN))
}
#[derive(Debug, Clone, Copy)]
struct RequestTime(Instant);