ffi: Add filtering of tracing events and spans

This commit is contained in:
Jonas Platte
2023-03-23 16:43:04 +01:00
committed by Jonas Platte
parent 50f29e5a11
commit 29068265db

View File

@@ -7,8 +7,6 @@ use once_cell::sync::OnceCell;
use tracing::{callsite::DefaultCallsite, field::FieldSet, Callsite};
use tracing_core::{identify_callsite, metadata::Kind as MetadataKind};
type StaticMetadata = &'static tracing::Metadata<'static>;
#[uniffi::export]
fn log_event(
file: String,
@@ -18,23 +16,27 @@ fn log_event(
target: String,
message: String,
) {
static METADATA: Mutex<BTreeMap<Location, StaticMetadata>> = Mutex::new(BTreeMap::new());
static CALLSITES: Mutex<BTreeMap<Location, &'static DefaultCallsite>> =
Mutex::new(BTreeMap::new());
let loc = Location::new(file, line, column);
let metadata = get_or_init_metadata(&METADATA, loc, level, target, |loc| {
let callsite = get_or_init_metadata(&CALLSITES, loc, level, target, |loc| {
(format!("event {}:{}", loc.file, loc.line), &["message"], MetadataKind::EVENT)
});
let metadata = callsite.metadata();
let fields = metadata.fields();
let message_field = fields.field("message").unwrap();
#[allow(trivial_casts)] // The compiler is lying, it can't infer this cast
let values = [(&message_field, Some(&message as &dyn tracing::Value))];
if span_or_event_enabled(callsite) {
let fields = metadata.fields();
let message_field = fields.field("message").unwrap();
#[allow(trivial_casts)] // The compiler is lying, it can't infer this cast
let values = [(&message_field, Some(&message as &dyn tracing::Value))];
// This function is hidden from docs, but we have to use it
// because there is no other way of obtaining a `ValueSet`.
// It's not entirely clear why it is private. See this issue:
// https://github.com/tokio-rs/tracing/issues/2363
let values = fields.value_set(&values);
tracing::Event::dispatch(metadata, &values);
// This function is hidden from docs, but we have to use it
// because there is no other way of obtaining a `ValueSet`.
// It's not entirely clear why it is private. See this issue:
// https://github.com/tokio-rs/tracing/issues/2363
let values = fields.value_set(&values);
tracing::Event::dispatch(metadata, &values);
}
}
#[uniffi::export]
@@ -46,25 +48,34 @@ fn make_span(
target: String,
name: String,
) -> Arc<Span> {
static METADATA: Mutex<BTreeMap<Location, StaticMetadata>> = Mutex::new(BTreeMap::new());
static CALLSITES: Mutex<BTreeMap<Location, &'static DefaultCallsite>> =
Mutex::new(BTreeMap::new());
let loc = Location::new(file, line, column);
let metadata =
get_or_init_metadata(&METADATA, loc, level, target, |_loc| (name, &[], MetadataKind::SPAN));
let callsite = get_or_init_metadata(&CALLSITES, loc, level, target, |_loc| {
(name, &[], MetadataKind::SPAN)
});
let metadata = callsite.metadata();
// This function is hidden from docs, but we have to use it (see above).
let values = metadata.fields().value_set(&[]);
Arc::new(Span(tracing::Span::new(metadata, &values)))
let span = if span_or_event_enabled(callsite) {
// This function is hidden from docs, but we have to use it (see above).
let values = metadata.fields().value_set(&[]);
tracing::Span::new(metadata, &values)
} else {
tracing::Span::none()
};
Arc::new(Span(span))
}
type FieldNames = &'static [&'static str];
fn get_or_init_metadata(
mutex: &Mutex<BTreeMap<Location, StaticMetadata>>,
mutex: &Mutex<BTreeMap<Location, &'static DefaultCallsite>>,
loc: Location,
level: LogLevel,
target: String,
get_details: impl FnOnce(&Location) -> (String, FieldNames, MetadataKind),
) -> StaticMetadata {
) -> &'static DefaultCallsite {
mutex.lock().unwrap().entry(loc).or_insert_with_key(|loc| {
let (name, field_names, span_kind) = get_details(loc);
let callsite = Box::leak(Box::new(LateInitCallsite(OnceCell::new())));
@@ -78,11 +89,28 @@ fn get_or_init_metadata(
FieldSet::new(field_names, identify_callsite!(callsite)),
span_kind,
)));
callsite.0.set(DefaultCallsite::new(metadata)).expect("callsite was not set before");
metadata
callsite.0.try_insert(DefaultCallsite::new(metadata)).expect("callsite was not set before")
})
}
fn span_or_event_enabled(callsite: &'static DefaultCallsite) -> bool {
use tracing::{
dispatcher,
level_filters::{LevelFilter, STATIC_MAX_LEVEL},
};
let meta = callsite.metadata();
let level = *meta.level();
if level > STATIC_MAX_LEVEL || level > LevelFilter::current() {
false
} else {
let interest = callsite.interest();
interest.is_always()
|| !interest.is_never() && dispatcher::get_default(|default| default.enabled(meta))
}
}
pub struct Span(tracing::Span);
impl Span {