From d1e0087bd5df116e22709feec13162ec72bfb425 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 7 Aug 2020 21:41:29 +0100 Subject: [PATCH] tracing: Add support for span fields --- src/rust/include/tracing.h | 31 +++++++++++++++-- src/rust/src/tracing_ffi.rs | 69 +++++++++++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 5 deletions(-) diff --git a/src/rust/include/tracing.h b/src/rust/include/tracing.h index 3764d5066..63ccc5988 100644 --- a/src/rust/include/tracing.h +++ b/src/rust/include/tracing.h @@ -68,7 +68,10 @@ typedef struct TracingSpanGuard TracingSpanGuard; /// Creates a span for a callsite. /// /// The span must be freed when it goes out of scope. -TracingSpanHandle* tracing_span_create(const TracingCallsite* callsite); +TracingSpanHandle* tracing_span_create( + const TracingCallsite* callsite, + const char* const* field_values, + size_t fields_len); /// Clones the given span. /// @@ -216,7 +219,7 @@ class Span Span() : inner(nullptr, tracing_span_free) {} /// Use the `TracingSpan` macro instead of calling this constructor directly. - Span(const TracingCallsite* callsite) : inner(tracing_span_create(callsite), tracing_span_free) {} + Span(const TracingCallsite* callsite, const char* const* field_values, size_t fields_len) : inner(tracing_span_create(callsite, field_values, fields_len), tracing_span_free) {} Span(Span& span) : inner(std::move(span.inner)) {} Span(const Span& span) : inner(tracing_span_clone(span.inner.get()), tracing_span_free) {} @@ -257,9 +260,31 @@ class Span /// strings. #define TracingSpan(level, target, name) ([&] { \ static constexpr const char* const FIELDS[] = {}; \ + const char* T_VALUES[] = {}; \ static TracingCallsite* CALLSITE = \ T_CALLSITE(name, target, level, FIELDS, true); \ - return tracing::Span(CALLSITE); \ + return tracing::Span( \ + CALLSITE, T_VALUES, T_ARRLEN(T_VALUES)); \ +}()) + +/// Expands to a `tracing::Span` object which is used to record a span. +/// The `Span::Enter` method on that object records that the span has been +/// entered, and returns a RAII guard object, which will exit the span when +/// dropped. +/// +/// Arguments: (level, target, name, key, value[, key2, value2, ...]) +/// +/// level, target, name, and all keys MUST be static constants, and MUST be +/// valid UTF-8 strings. +#define TracingSpanFields(level, target, name, ...) ([&] { \ + static constexpr const char* const FIELDS[] = \ + {T_FIELD_NAMES(__VA_ARGS__)}; \ + const char* T_VALUES[] = \ + {T_FIELD_VALUES(__VA_ARGS__)}; \ + static TracingCallsite* CALLSITE = \ + T_CALLSITE(name, target, level, FIELDS, true); \ + return tracing::Span( \ + CALLSITE, T_VALUES, T_ARRLEN(T_VALUES)); \ }()) #endif diff --git a/src/rust/src/tracing_ffi.rs b/src/rust/src/tracing_ffi.rs index 2f7ecf731..fb810ab09 100644 --- a/src/rust/src/tracing_ffi.rs +++ b/src/rust/src/tracing_ffi.rs @@ -270,6 +270,9 @@ pub extern "C" fn tracing_callsite( } macro_rules! repeat { + (0, $val:expr) => { + [] + }; (1, $val:expr) => { [$val] }; @@ -435,14 +438,76 @@ macro_rules! repeat { } #[no_mangle] -pub extern "C" fn tracing_span_create(callsite: *const FfiCallsite) -> *mut Span { +pub extern "C" fn tracing_span_create( + callsite: *const FfiCallsite, + field_values: *const *const c_char, + fields_len: usize, +) -> *mut Span { let callsite = unsafe { &*callsite }; + let field_values = unsafe { slice::from_raw_parts(field_values, fields_len) }; let meta = callsite.metadata(); assert!(meta.is_span()); let span = if level_enabled!(*meta.level()) && callsite.is_enabled() { - Span::new(meta, &meta.fields().value_set(&[])) + let mut fi = meta.fields().iter(); + let mut vi = field_values + .iter() + .map(|&p| unsafe { CStr::from_ptr(p) }) + .map(|cs| cs.to_string_lossy()); + + macro_rules! new_span { + ($n:tt) => { + Span::new( + meta, + &meta.fields().value_set(&repeat!( + $n, + ( + &fi.next().unwrap(), + Some(&vi.next().unwrap().as_ref() as &dyn Value) + ) + )), + ) + }; + } + + // https://github.com/tokio-rs/tracing/issues/782 might help improve things here. + match field_values.len() { + 0 => new_span!(0), + 1 => new_span!(1), + 2 => new_span!(2), + 3 => new_span!(3), + 4 => new_span!(4), + 5 => new_span!(5), + 6 => new_span!(6), + 7 => new_span!(7), + 8 => new_span!(8), + 9 => new_span!(9), + 10 => new_span!(10), + 11 => new_span!(11), + 12 => new_span!(12), + 13 => new_span!(13), + 14 => new_span!(14), + 15 => new_span!(15), + 16 => new_span!(16), + 17 => new_span!(17), + 18 => new_span!(18), + 19 => new_span!(19), + 20 => new_span!(20), + 21 => new_span!(21), + 22 => new_span!(22), + 23 => new_span!(23), + 24 => new_span!(24), + 25 => new_span!(25), + 26 => new_span!(26), + 27 => new_span!(27), + 28 => new_span!(28), + 29 => new_span!(29), + 30 => new_span!(30), + 31 => new_span!(31), + 32 => new_span!(32), + _ => unimplemented!(), + } } else { Span::none() };