Skip to content

Commit

Permalink
core: document the callsite module (#2088)
Browse files Browse the repository at this point in the history
Currently, there isn't a lot of documentation explaining what callsites
and registration are for, and how they work. There's some documentation
explaining this stuff, but it's all on the `register_callsite` *method*,
rather than in the `callsite` module itself. We should fix that.

This branch adds new documentation to `tracing-core`'s `callsite`
module. Hopefully this should shine some light on how this part of
tracing works.

Thanks to @JamesHallowell for fixing some typos!

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
  • Loading branch information
hawkw committed Apr 22, 2022
1 parent 55fdc75 commit 465f10a
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 3 deletions.
115 changes: 113 additions & 2 deletions tracing-core/src/callsite.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,85 @@
//! Callsites represent the source locations from which spans or events
//! originate.
//!
//! # What Are Callsites?
//!
//! Every span or event in `tracing` is associated with a [`Callsite`]. A
//! callsite is a small `static` value that is responsible for the following:
//!
//! * Storing the span or event's [`Metadata`],
//! * Uniquely [identifying](Identifier) the span or event definition,
//! * Caching the collector's [`Interest`][^1] in that span or event, to avoid
//! re-evaluating filters,
//! * Storing a [`Registration`] that allows the callsite to be part of a global
//! list of all callsites in the program.
//!
//! # Registering Callsites
//!
//! When a span or event is recorded for the first time, its callsite
//! [`register`]s itself with the global callsite registry. Registering a
//! callsite calls the [`Collect::register_callsite`][`register_callsite`]
//! method with that callsite's [`Metadata`] on every currently active
//! collector. This serves two primary purposes: informing collectors of the
//! callsite's existence, and performing static filtering.
//!
//! ## Callsite Existence
//!
//! If a [`Collect`] implementation wishes to allocate storage for each
//! unique span/event location in the program, or pre-compute some value
//! that will be used to record that span or event in the future, it can
//! do so in its [`register_callsite`] method.
//!
//! ## Performing Static Filtering
//!
//! The [`register_callsite`] method returns an [`Interest`] value,
//! which indicates that the collector either [always] wishes to record
//! that span or event, [sometimes] wishes to record it based on a
//! dynamic filter evaluation, or [never] wishes to record it.
//!
//! When registering a new callsite, the [`Interest`]s returned by every
//! currently active collector are combined, and the result is stored at
//! each callsite. This way, when the span or event occurs in the
//! future, the cached [`Interest`] value can be checked efficiently
//! to determine if the span or event should be recorded, without
//! needing to perform expensive filtering (i.e. calling the
//! [`Collect::enabled`] method every time a span or event occurs).
//!
//! ### Rebuilding Cached Interest
//!
//! When a new [`Dispatch`] is created (i.e. a new collector becomes
//! active), any previously cached [`Interest`] values are re-evaluated
//! for all callsites in the program. This way, if the new collector
//! will enable a callsite that was not previously enabled, the
//! [`Interest`] in that callsite is updated. Similarly, when a
//! collector is dropped, the interest cache is also re-evaluated, so
//! that any callsites enabled only by that collector are disabled.
//!
//! In addition, the [`rebuild_interest_cache`] function in this module can be
//! used to manually invalidate all cached interest and re-register those
//! callsites. This function is useful in situations where a collector's
//! interest can change, but it does so relatively infrequently. The collector
//! may wish for its interest to be cached most of the time, and return
//! [`Interest::always`][always] or [`Interest::never`][never] in its
//! [`register_callsite`] method, so that its [`Collect::enabled`] method
//! doesn't need to be evaluated every time a span or event is recorded.
//! However, when the configuration changes, the collector can call
//! [`rebuild_interest_cache`] to re-evaluate the entire interest cache with its
//! new configuration. This is a relatively costly operation, but if the
//! configuration changes infrequently, it may be more efficient than calling
//! [`Collect::enabled`] frequently.
//!
//! [^1]: Returned by the [`Collect::register_callsite`][`register_callsite`]
//! method.
//!
//! [`Metadata`]: crate::metadata::Metadata
//! [`Interest`]: crate::collect::Interest
//! [`Collect`]: crate::collect::Collect
//! [`register_callsite`]: crate::collect::Collect::register_callsite
//! [`Collect::enabled`]: crate::collect::Collect::enabled
//! [always]: crate::collect::Interest::always
//! [sometimes]: crate::collect::Interest::sometimes
//! [never]: crate::collect::Interest::never
//! [`Dispatch`]: crate::dispatch::Dispatch
use crate::{
collect::Interest,
dispatch::{self, Dispatch},
Expand All @@ -18,10 +98,17 @@ type Callsites = LinkedList;
///
/// These functions are only intended to be called by the callsite registry, which
/// correctly handles determining the common interest between all collectors.
///
/// See the [module-level documentation](crate::callsite) for details on
/// callsites.
pub trait Callsite: Sync {
/// Sets the [`Interest`] for this callsite.
///
/// See the [documentation on callsite interest caching][cache-docs] for
/// details.
///
/// [`Interest`]: super::collect::Interest
/// [cache-docs]: crate::callsite#performing-static-filtering
fn set_interest(&self, interest: Interest);

/// Returns the [metadata] associated with the callsite.
Expand Down Expand Up @@ -54,8 +141,12 @@ pub struct Identifier(
/// Every [`Callsite`] implementation must provide a `&'static Registration`
/// when calling [`register`] to add itself to the global callsite registry.
///
/// See [the documentation on callsite registration][registry-docs] for details
/// on how callsites are registered.
///
/// [`Callsite`]: crate::callsite::Callsite
/// [`register`]: crate::callsite::register
/// [registry-docs]: crate::callsite#registering-callsites
pub struct Registration<T = &'static dyn Callsite> {
callsite: T,
next: AtomicPtr<Registration<T>>,
Expand Down Expand Up @@ -99,21 +190,31 @@ mod inner {
/// implementation at runtime, then it **must** call this function after that
/// value changes, in order for the change to be reflected.
///
/// See the [documentation on callsite interest caching][cache-docs] for
/// additional information on this function's usage.
///
/// [`max_level_hint`]: crate::collect::Collect::max_level_hint
/// [`Callsite`]: crate::callsite::Callsite
/// [`enabled`]: crate::collect::Collect::enabled
/// [`Interest::sometimes()`]: crate::collect::Interest::sometimes
/// [`Collect`]: crate::collect::Collect
/// [cache-docs]: crate::callsite#rebuilding-cached-interest
pub fn rebuild_interest_cache() {
let mut dispatchers = REGISTRY.dispatchers.write().unwrap();
let callsites = &REGISTRY.callsites;
rebuild_interest(callsites, &mut dispatchers);
}

/// Register a new `Callsite` with the global registry.
/// Register a new [`Callsite`] with the global registry.
///
/// This should be called once per callsite after the callsite has been
/// constructed.
///
/// See the [documentation on callsite registration][reg-docs] for details
/// on the global callsite registry.
///
/// [`Callsite`]: crate::callsite::Callsite
/// [reg-docs]: crate::callsite#registering-callsites
pub fn register(registration: &'static Registration) {
let dispatchers = REGISTRY.dispatchers.read().unwrap();
rebuild_callsite_interest(&dispatchers, registration.callsite);
Expand Down Expand Up @@ -196,20 +297,30 @@ mod inner {
/// implementation at runtime, then it **must** call this function after that
/// value changes, in order for the change to be reflected.
///
/// See the [documentation on callsite interest caching][cache-docs] for
/// additional information on this function's usage.
///
/// [`max_level_hint`]: crate::collector::Collector::max_level_hint
/// [`Callsite`]: crate::callsite::Callsite
/// [`enabled`]: crate::collector::Collector::enabled
/// [`Interest::sometimes()`]: crate::collect::Interest::sometimes
/// [collector]: crate::collect::Collect
/// [`Collect`]: crate::collect::Collect
/// [cache-docs]: crate::callsite#rebuilding-cached-interest
pub fn rebuild_interest_cache() {
register_dispatch(dispatch::get_global());
}

/// Register a new `Callsite` with the global registry.
/// Register a new [`Callsite`] with the global registry.
///
/// This should be called once per callsite after the callsite has been
/// constructed.
///
/// See the [documentation on callsite registration][reg-docs] for details
/// on the global callsite registry.
///
/// [`Callsite`]: crate::callsite::Callsite
/// [reg-docs]: crate::callsite#registering-callsites
pub fn register(registration: &'static Registration) {
rebuild_callsite_interest(dispatch::get_global(), registration.callsite);
REGISTRY.push(registration);
Expand Down
13 changes: 12 additions & 1 deletion tracing-core/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ use core::ptr::NonNull;
/// Additionally, collectors which wish to perform a behaviour once for each
/// callsite, such as allocating storage for data related to that callsite,
/// can perform it in `register_callsite`.
///
/// See also the [documentation on the callsite registry][cs-reg] for details
/// on [`register_callsite`].
///
/// - [`clone_span`] is called every time a span ID is cloned, and [`try_close`]
/// is called when a span ID is dropped. By default, these functions do
/// nothing. However, they can be used to implement reference counting for
Expand All @@ -67,10 +71,11 @@ use core::ptr::NonNull;
/// [`enabled`]: Collect::enabled
/// [`clone_span`]: Collect::clone_span
/// [`try_close`]: Collect::try_close
/// [cs-reg]: crate::callsite#registering-callsites
pub trait Collect: 'static {
// === Span registry methods ==============================================

/// Registers a new callsite with this collector, returning whether or not
/// Registers a new [callsite] with this collector, returning whether or not
/// the collector is interested in being notified about the callsite.
///
/// By default, this function assumes that the collector's [filter]
Expand Down Expand Up @@ -124,18 +129,24 @@ pub trait Collect: 'static {
/// return `Interest::Never`, as a new collector may be added that _is_
/// interested.
///
/// See the [documentation on the callsite registry][cs-reg] for more
/// details on how and when the `register_callsite` method is called.
///
/// # Notes
///
/// This function may be called again when a new collector is created or
/// when the registry is invalidated.
///
/// If a collector returns `Interest::never` for a particular callsite, it
/// _may_ still see spans and events originating from that callsite, if
/// another collector expressed interest in it.
///
/// [callsite]: crate::callsite
/// [filter]: Self::enabled
/// [metadata]: super::metadata::Metadata
/// [`enabled`]: Self::enabled
/// [`rebuild_interest_cache`]: super::callsite::rebuild_interest_cache
/// [cs-reg]: crate::callsite#registering-callsites
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
if self.enabled(metadata) {
Interest::always()
Expand Down

0 comments on commit 465f10a

Please sign in to comment.