1#![doc = include_str!("../README.md")]
4
5extern crate self as telemetry_safe;
8
9pub use telemetry_safe_core::{
10 TelemetryDebug, TelemetryDisplay, ToTelemetry, prelude, telemetry, telemetry_debug,
11};
12pub use telemetry_safe_derive::ToTelemetry;
13
14#[cfg(test)]
15mod tests {
16 #![allow(dead_code)]
17
18 use super::{ToTelemetry, telemetry};
19 use std::collections::{BTreeMap, BTreeSet};
20 use std::fmt::{self, Formatter};
21
22 #[derive(ToTelemetry)]
23 struct AccountSnapshot {
24 id: u64,
25 state: AccountState,
26 #[telemetry(skip)]
27 secret_note: &'static str,
28 }
29
30 #[derive(ToTelemetry)]
31 enum Outcome {
32 Accepted { account: AccountSnapshot },
33 Rejected(RejectReason),
34 }
35
36 #[derive(ToTelemetry)]
37 struct RejectReason {
38 code: RejectCode,
39 }
40
41 struct AccountState(&'static str);
42
43 impl ToTelemetry for AccountState {
44 fn fmt_telemetry(&self, f: &mut Formatter<'_>) -> fmt::Result {
45 f.write_str(self.0)
46 }
47 }
48
49 struct RejectCode(&'static str);
50
51 impl ToTelemetry for RejectCode {
52 fn fmt_telemetry(&self, f: &mut Formatter<'_>) -> fmt::Result {
53 f.write_str(self.0)
54 }
55 }
56
57 #[test]
58 fn derived_struct_skips_sensitive_fields() {
59 let snapshot = AccountSnapshot {
60 id: 42,
61 state: AccountState("active"),
62 secret_note: "pii",
63 };
64
65 assert_eq!(
66 telemetry(&snapshot).to_string(),
67 r#"AccountSnapshot { id: 42, state: active }"#
68 );
69 }
70
71 #[test]
72 fn derived_enum_formats_variants() {
73 let outcome = Outcome::Rejected(RejectReason {
74 code: RejectCode("policy"),
75 });
76
77 assert_eq!(
78 telemetry(&outcome).to_string(),
79 r#"Rejected(RejectReason { code: policy })"#
80 );
81 }
82
83 #[test]
84 fn collections_require_safe_elements() {
85 let mut map = BTreeMap::new();
86 map.insert(
87 1_u64,
88 AccountSnapshot {
89 id: 7,
90 state: AccountState("pending"),
91 secret_note: "hidden",
92 },
93 );
94
95 let mut set = BTreeSet::new();
96 set.insert(1_u64);
97
98 assert_eq!(
99 telemetry(&map).to_string(),
100 r#"{1: AccountSnapshot { id: 7, state: pending }}"#
101 );
102 assert_eq!(telemetry(&set).to_string(), "{1}");
103 }
104
105 #[test]
106 fn display_wrapper_can_be_used_in_format_args() {
107 let snapshot = AccountSnapshot {
108 id: 1,
109 state: AccountState("active"),
110 secret_note: "hidden",
111 };
112
113 let rendered = format!("account={}", telemetry(&snapshot));
114
115 assert_eq!(rendered, "account=AccountSnapshot { id: 1, state: active }");
116 }
117}