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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//! Shared tracing configuration and metric recording for observability.
//!
//! Centralizes the log target used by the crate so subscribers can filter
//! observability events without pulling in unrelated application logs, and
//! provides the seam through which a consumer collects counts.
//!
//! # Why a seam rather than a metrics crate
//!
//! Every subsystem here reports through bounded `tracing` events, which a
//! consumer can filter but not readily aggregate. A metric is the other thing:
//! a count to add up without parsing logs. This crate takes no metrics
//! dependency, because a library should not choose one on its consumer's
//! behalf; a consumer installs a [`MetricsRecorder`] and forwards each count
//! to whatever it already runs. With no recorder installed, recording is a
//! branch and a return.
use ;
/// Target used by observability spans and logs.
pub const LOG_TARGET: &str = "pg_embed::observability";
/// Outcome of one password-reuse decision.
///
/// This is an enum rather than a string so the label set is bounded by
/// construction: a caller cannot route a password, a path, or any other
/// unbounded value into a metric through it. `ProbeFailed` and
/// `UnreadableFile` stay distinct even though both map to
/// [`BootstrapErrorKind::ClusterPasswordUnreadable`](crate::BootstrapErrorKind),
/// because failing to search the data directory and failing to read the
/// password file are different operational problems.
/// A count this crate records.
///
/// Every variant carries a bounded label set and nothing else. Marked
/// `#[non_exhaustive]` so later releases can add counts without breaking a
/// consumer's `match`.
/// Receives each [`Metric`] the crate records.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex};
///
/// use pg_embedded_setup_unpriv::observability::{
/// Metric,
/// MetricsRecorder,
/// install_metrics_recorder,
/// };
///
/// #[derive(Default)]
/// struct Collected(Mutex<Vec<Metric>>);
///
/// impl MetricsRecorder for Collected {
/// fn record(&self, metric: Metric) {
/// self.0
/// .lock()
/// .unwrap_or_else(|err| err.into_inner())
/// .push(metric);
/// }
/// }
///
/// let recorder = Arc::new(Collected::default());
/// let _guard = install_metrics_recorder(Arc::clone(&recorder) as Arc<dyn MetricsRecorder>);
/// // The guard restores the previous recorder when it drops.
/// ```
/// The installed recorder, if any.
static RECORDER: = new;
/// Restores the previous recorder when dropped.
///
/// Installing returns a guard rather than being permanent so a test can
/// install a collector without leaking it into the next test, matching how
/// this crate's other process-wide hooks behave.
/// Installs `recorder` and returns a guard that restores the previous one.
///
/// Installation is process-wide and nests: the guard puts back whatever was
/// installed before it, so an inner scope cannot strand an outer collector.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex};
///
/// use pg_embedded_setup_unpriv::observability::{
/// Metric,
/// MetricsRecorder,
/// install_metrics_recorder,
/// };
///
/// #[derive(Default)]
/// struct Counting(Mutex<usize>);
///
/// impl MetricsRecorder for Counting {
/// fn record(&self, _metric: Metric) {
/// *self.0.lock().unwrap_or_else(|err| err.into_inner()) += 1;
/// }
/// }
///
/// let outer = Arc::new(Counting::default());
/// let outer_guard = install_metrics_recorder(Arc::clone(&outer) as Arc<dyn MetricsRecorder>);
///
/// let inner = Arc::new(Counting::default());
/// let inner_guard = install_metrics_recorder(Arc::clone(&inner) as Arc<dyn MetricsRecorder>);
/// // Counts recorded here reach `inner`, not `outer`.
/// drop(inner_guard);
/// // `outer` is installed again from here until `outer_guard` drops.
/// drop(outer_guard);
/// // Nothing is installed now, and recording is a branch and a return.
/// ```
/// Records `metric` with the installed recorder, or does nothing.
///
/// The installed handle is cloned out and the read lock released before the
/// consumer's `record` runs. Holding the lock across that call would deadlock
/// any recorder that installs another recorder or drops a guard from inside
/// its callback, because both take the write lock on the same thread.
pub