1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! `turnframe-telemetry`: metrics, tracing and dashboards for a Turnframe runtime.
//!
//! The runtime reports what it did through one small contract in
//! [`turnframe_core::observe`]; this crate ships the implementations of it an
//! application wants in production, plus the data to build a dashboard from
//! them. Every metric of §26.2, the latencies of §28, the identifiers of §26.1
//! as tracing fields, one span per provider call described with the
//! OpenTelemetry GenAI conventions, and a vendor-neutral [`TraceGrouping`] that
//! reaches every span rather than only the trace root.
//!
//! Two rules decide what it will not do, and
//! [`docs/telemetry.md`](https://github.com/turnframe-rs/turnframe/blob/main/docs/telemetry.md)
//! says why. **Prompt and completion text stays out by default** —
//! [`ContentRecorder`] is the only way in, is disabled unless an application
//! enables it, and passes every string through a redactor the application
//! wrote. **No user text and no case text ever becomes a metric label**, which
//! is enforced three ways rather than asked for.
//!
//! ```rust
//! use std::sync::Arc;
//! use std::time::Duration;
//!
//! use turnframe_core::ids::WorkflowKey;
//! use turnframe_core::observe::{Observer, Signal, SignalLabels};
//! use turnframe_telemetry::{CompositeObserver, MetricsObserver, TracingObserver, metrics};
//!
//! // Once, after the metrics exporter is installed.
//! metrics::describe_all();
//!
//! let observer: Arc<dyn Observer> = Arc::new(
//! CompositeObserver::new()
//! .with(MetricsObserver::new())
//! .with(TracingObserver::new()),
//! );
//!
//! // The runtime then reports what it did:
//! let labels = SignalLabels::workflow(WorkflowKey::from("trip"));
//! observer.observe_labeled(&Signal::TurnReceived, &labels);
//! observer.observe_duration(&Signal::TurnDuration, Duration::from_millis(412), &labels);
//! ```
//!
//! In tests, swap the composite for a [`RecordingObserver`] and assert on the
//! signals the code under test produced.
//!
//! # Modules
//!
//! * [`crate::metrics`]: the [`MetricsObserver`], the label rules and the metric
//! catalogue that generates this crate's README table.
//! * [`crate::tracing`]: the [`TracingObserver`], the §26.1 identifier fields and
//! the turn and stage span helpers.
//! * [`crate::attrs`]: every attribute key in one place, so an adapter and an
//! application spell them identically.
//! * [`crate::composite`]: [`CompositeObserver`] and [`RecordingObserver`].
//! * [`crate::dashboard`]: a data-only description of the §26.3 dashboard.
//! * [`crate::otel`] (feature `otel`): the same signals as OpenTelemetry
//! instruments, and the grouping carried in baggage and stamped onto every
//! span by [`GroupingSpanProcessor`].
pub use crate;
pub use crate;
pub use crate;
pub use crate;
pub use crate;
/// Borrows an optional string-like identifier as a `&str`.
///
/// Written against [`AsRef<str>`] rather than a concrete type so it keeps
/// working whether a `turnframe-core` label field is a `String` or one of the
/// string newtypes of [`turnframe_core::ids`].
pub
/// Renders a unit-variant enum as its serde name (e.g. `RiskClass::ReadOnly` →
/// `"read_only"`).
///
/// Deriving the label from the serialization instead of a `match` means a new
/// variant in a `turnframe-core` enum gets a correct label without a change
/// here, and no `#[non_exhaustive]` wildcard can silently mislabel one.
/// Anything that does not serialize to a plain string yields `None` and is
/// dropped.
pub Sized>