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
//! Cross-cutting telemetry sink trait.
//!
//! [`TelemetrySink`] is the single observer interface for all telemetry the
//! SDK emits. Apps implement it (or install [`NoopTelemetrySink`]) and the SDK
//! pushes every [`TelemetryRecord`] through it.
//!
//! Emit wiring lives in follow-up work; this module ships the types only.
use TelemetryRecord;
use crateEvent;
/// Sink for structured telemetry records.
///
/// Implementations must be cheap when called from hot paths — the SDK does not
/// buffer or rate-limit before dispatch beyond its own sampling layer, so
/// expensive work (I/O, serialization to external formats) should be
/// deferred to a background task owned by the implementor.
///
/// # Reentrancy and locking contract
///
/// The SDK may invoke [`TelemetrySink::emit`] while holding internal locks
/// (most notably the shared-state mutex on the `Protocol` fan-out path).
/// Implementations MUST NOT:
///
/// - block on slow I/O (network, disk, logging sinks that fsync), or
/// - reenter SDK methods on the same `OfflineProtocol` instance.
///
/// A blocking `emit` stalls every protocol operation that needs the lock.
/// Sinks that need to do real work should push the record onto a bounded
/// channel and return immediately, leaving the heavy lifting to a
/// background task owned by the implementor.
///
/// Implementations *should* also not panic, but the SDK defends against
/// this: every internal dispatch to `emit` runs under `catch_unwind`, so a
/// panicking sink is logged at `error!`, the offending record is dropped,
/// and the protocol continues. A panicking sink therefore loses telemetry
/// and degrades observability but does not corrupt SDK state. Panic
/// isolation only applies under `panic = unwind` — release profiles that
/// set `panic = abort` (including the `minisize` profile used for mobile)
/// abort the process on any panic, including one from a sink.
///
/// # Record passing
///
/// The record is passed by reference so implementations that only read fields
/// do not incur a clone. Implementations that need ownership (for example to
/// forward the record to another thread) should call [`Clone::clone`]
/// explicitly.
/// Default sink that discards every record.
///
/// Used by the SDK when no telemetry sink has been installed. Proves the
/// zero-cost baseline: the compiler inlines the empty body at every call site
/// that can statically resolve the concrete type, and the indirect dispatch
/// cost through `Arc<dyn TelemetrySink>` is a single virtual call that returns
/// immediately.
;