subscriber: add docs on registry span ID generation (#1453)

## Motivation

Currently, `tracing-subscriber`'s `Registry` type doesn't document how
span IDs are generated, or the uniqueness guarantees for span IDs. This
can cause confusion for users trying to implement `Subscribe`rs and
other code that interacts with the `Registry`'s generated span IDs.

## Solution

This branch adds a new documentation section to the `Registry` docs
describing how IDs are generated and when they are guaranteed to be
unique. In particular, the new section explicitly states that the
registry's IDs will not uniquely identify a span historically, because
IDs may be reused when a span has closed, and that the registry's
`tracing` span IDs should not be used as span IDs in a distributed
tracing system.

While I was working on these docs, I also fixed a link on adding
subscribers to a registry that went to a specific method on
`FmtSubscriber`, rather than to the more general docs on how
subscribers are composed with collectors.

Thanks to @Folyd for suggesting this docs improvement!

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Co-authored-by: David Barsky <me@davidbarsky.com>
This commit is contained in:
Eliza Weisman 2021-08-06 09:38:44 -07:00
parent 504bb3ee9a
commit 4556cb3dc2

View File

@ -23,26 +23,68 @@ use tracing_core::{
///
/// A `Registry` is a [`Subscriber`] around which multiple [`Layer`]s
/// implementing various behaviors may be [added]. Unlike other types
/// implementing `Subscriber` `Registry` does not actually record traces itself:
/// instead, it collects and stores span data that is exposed to any `Layer`s
/// implementing `Subscriber`, `Registry` does not actually record traces itself:
/// instead, it collects and stores span data that is exposed to any [`Layer`]s
/// wrapping it through implementations of the [`LookupSpan`] trait.
/// The `Registry` is responsible for storing span metadata, recording
/// relationships between spans, and tracking which spans are active and whicb
/// are closed. In addition, it provides a mechanism for `Layer`s to store
/// relationships between spans, and tracking which spans are active and which
/// are closed. In addition, it provides a mechanism for [`Layer`]s to store
/// user-defined per-span data, called [extensions], in the registry. This
/// allows `Layer`-specific data to benefit from the `Registry`'s
/// allows [`Layer`]-specific data to benefit from the `Registry`'s
/// high-performance concurrent storage.
///
/// This registry is implemented using a [lock-free sharded slab][slab], and is
/// highly optimized for concurrent access.
///
/// # Span ID Generation
///
/// Span IDs are not globally unique, but the registry ensures that
/// no two currently active spans have the same ID within a process.
///
/// One of the primary responsibilities of the registry is to generate [span
/// IDs]. Therefore, it's important for other code that interacts with the
/// registry, such as [`Layer`]s, to understand the guarantees of the
/// span IDs that are generated.
///
/// The registry's span IDs are guaranteed to be unique **at a given point
/// in time**. This means that an active span will never be assigned the
/// same ID as another **currently active** span. However, the registry
/// **will** eventually reuse the IDs of [closed] spans, although an ID
/// will never be reassigned immediately after a span has closed.
///
/// Spans are not [considered closed] by the `Registry` until *every*
/// [`Span`] reference with that ID has been dropped.
///
/// Thus: span IDs generated by the registry should be considered unique
/// only at a given point in time, and only relative to other spans
/// generated by the same process. Two spans with the same ID will not exist
/// in the same process concurrently. However, if historical span data is
/// being stored, the same ID may occur for multiple spans times in that
/// data. If spans must be uniquely identified in historical data, the user
/// code storing this data must assign its own unique identifiers to those
/// spans. A counter is generally sufficient for this.
///
/// Similarly, span IDs generated by the registry are not unique outside of
/// a given process. Distributed tracing systems may require identifiers
/// that are unique across multiple processes on multiple machines (for
/// example, [OpenTelemetry's `SpanId`s and `TraceId`s][ot]). `tracing` span
/// IDs generated by the registry should **not** be used for this purpose.
/// Instead, code which integrates with a distributed tracing system should
/// generate and propagate its own IDs according to the rules specified by
/// the distributed tracing system. These IDs can be associated with
/// `tracing` spans using [fields] and/or [stored span data].
///
/// [span IDs]: https://docs.rs/tracing-core/latest/tracing_core/span/struct.Id.html
/// [slab]: https://docs.rs/crate/sharded-slab/
/// [`Subscriber`]:
/// https://docs.rs/crate/tracing-core/latest/tracing_core/subscriber/trait.Subscriber.html
/// [`Layer`]: ../trait.Layer.html
/// [added]: ../trait.Layer.html#method.with_subscriber
/// [`LookupSpan`]: trait.LookupSpan.html
/// [extensions]: extensions/index.html
/// [`Layer`]: crate::Layer
/// [added]: crate::layer::Layer#composing-layers
/// [extensions]: super::Extensions
/// [closed]: https://docs.rs/tracing/latest/tracing/span/index.html#closing-spans
/// [considered closed]: https://docs.rs/tracing-core/latest/tracing_core/subscriber/trait.Subscriber.html#method.try_close
/// [`Span`]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html
/// [ot]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#spancontext
/// [fields]: https://docs.rs/tracing-core/latest/tracing-core/field/index.html
/// [stored span data]: crate::registry::SpanData::extensions_mut
#[cfg(feature = "registry")]
#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
#[derive(Debug)]