@@ -8,6 +8,58 @@ use crate::models::{Severity, SimplifiedLogEntry, SourceLocation};
88
99mod models;
1010
11+ /// A [`tracing_subscriber::Layer`] that formats tracing events and spans as
12+ /// [GCP Structured Logging] JSON entries and writes them using the provided
13+ /// [`MakeWriter`].
14+ ///
15+ /// Each tracing event or span lifecycle transition produces one newline-delimited
16+ /// JSON log entry with the following GCP fields:
17+ ///
18+ /// - `severity` — mapped from the tracing [`Level`] (see table below)
19+ /// - `message` — the event message, prefixed with the span name when emitted inside a span
20+ /// - `time` — RFC 3339 UTC timestamp
21+ /// - `logging.googleapis.com/labels` — always contains `pid`; contains `hostname` when the
22+ /// `hostname` feature is enabled (on by default); also includes all span and event fields
23+ /// - `logging.googleapis.com/sourceLocation` — file path, line number, and module path
24+ /// derived from tracing metadata
25+ ///
26+ /// ## Severity mapping
27+ ///
28+ /// | `tracing` level | GCP severity |
29+ /// |-----------------|--------------|
30+ /// | `TRACE` | `DEFAULT` |
31+ /// | `DEBUG` | `DEBUG` |
32+ /// | `INFO` | `INFO` |
33+ /// | `WARN` | `WARNING` |
34+ /// | `ERROR` | `ERROR` |
35+ ///
36+ /// ## Message format
37+ ///
38+ /// | Context | Emitted `message` |
39+ /// |---------------------|-------------------------------|
40+ /// | Event outside span | `message` |
41+ /// | Event inside span | `[SPAN_NAME - EVENT] message` |
42+ /// | Span opens | `[SPAN_NAME - START]` |
43+ /// | Span closes | `[SPAN_NAME - END]` |
44+ ///
45+ /// ## Usage
46+ ///
47+ /// `GCPFormattingLayer` must be paired with [`SpanDataLayer`] so that span fields are
48+ /// available when formatting events emitted inside a span. Always add [`SpanDataLayer`]
49+ /// **before** `GCPFormattingLayer` in the subscriber stack.
50+ ///
51+ /// ```no_run
52+ /// use tracing_subscriber::{Registry, layer::SubscriberExt};
53+ /// use tracing_gcp_formatter::{GCPFormattingLayer, SpanDataLayer};
54+ ///
55+ /// let subscriber = Registry::default()
56+ /// .with(SpanDataLayer::new())
57+ /// .with(GCPFormattingLayer::new(std::io::stdout));
58+ ///
59+ /// tracing::subscriber::set_global_default(subscriber).expect("setting subscriber");
60+ /// ```
61+ ///
62+ /// [GCP Structured Logging]: https://cloud.google.com/logging/docs/structured-logging
1163pub struct GCPFormattingLayer < W : for < ' a > MakeWriter < ' a > + ' static > {
1264 make_writer : W ,
1365 pid : u32 ,
@@ -18,6 +70,10 @@ impl<W> GCPFormattingLayer<W>
1870where
1971 W : for < ' a > MakeWriter < ' a > + ' static ,
2072{
73+ /// Creates a new `GCPFormattingLayer` that writes JSON log entries using `make_writer`.
74+ ///
75+ /// `make_writer` can be any type implementing
76+ /// [`MakeWriter`], such as [`std::io::stdout`] or [`std::io::stderr`].
2177 pub fn new ( make_writer : W ) -> Self {
2278 Self {
2379 make_writer,
@@ -275,9 +331,34 @@ impl Visit for EventVisitor {
275331 }
276332}
277333
334+ /// A [`tracing_subscriber::Layer`] that captures span fields and stores them in span
335+ /// extensions so that [`GCPFormattingLayer`] can include them in log entries emitted
336+ /// from within those spans.
337+ ///
338+ /// When an event fires inside a span, [`GCPFormattingLayer`] walks the span ancestry and
339+ /// collects all fields recorded by this layer, merging them into the `labels` of the
340+ /// produced JSON log entry. This layer carries no state of its own and is cheap to construct.
341+ ///
342+ /// ## Usage
343+ ///
344+ /// Always add `SpanDataLayer` **before** [`GCPFormattingLayer`] in the subscriber stack.
345+ /// The ordering matters: `SpanDataLayer` must store the span data before
346+ /// `GCPFormattingLayer` can read it.
347+ ///
348+ /// ```no_run
349+ /// use tracing_subscriber::{Registry, layer::SubscriberExt};
350+ /// use tracing_gcp_formatter::{GCPFormattingLayer, SpanDataLayer};
351+ ///
352+ /// let subscriber = Registry::default()
353+ /// .with(SpanDataLayer::new())
354+ /// .with(GCPFormattingLayer::new(std::io::stdout));
355+ ///
356+ /// tracing::subscriber::set_global_default(subscriber).expect("setting subscriber");
357+ /// ```
278358pub struct SpanDataLayer { }
279359
280360impl SpanDataLayer {
361+ /// Creates a new `SpanDataLayer`.
281362 pub fn new ( ) -> Self {
282363 Self { }
283364 }
0 commit comments