1use std::sync::atomic::{AtomicU8, Ordering};
10
11pub const LEVEL_TRACE: u8 = 0;
12pub const LEVEL_DEBUG: u8 = 1;
13pub const LEVEL_INFO: u8 = 2;
14pub const LEVEL_WARN: u8 = 3;
15pub const LEVEL_ERROR: u8 = 4;
16pub const LEVEL_OFF: u8 = 5;
17
18const DEFAULT_LEVEL: u8 = LEVEL_WARN;
20const UNINIT: u8 = u8::MAX;
22
23static LOG_LEVEL: AtomicU8 = AtomicU8::new(UNINIT);
24
25fn parse_level(s: &str) -> Option<u8> {
26 match s.trim().to_ascii_lowercase().as_str() {
27 "trace" => Some(LEVEL_TRACE),
28 "debug" => Some(LEVEL_DEBUG),
29 "info" => Some(LEVEL_INFO),
30 "warn" | "warning" => Some(LEVEL_WARN),
31 "error" => Some(LEVEL_ERROR),
32 "off" | "none" | "silent" => Some(LEVEL_OFF),
33 _ => None,
34 }
35}
36
37#[inline]
40pub fn log_level() -> u8 {
41 match LOG_LEVEL.load(Ordering::Relaxed) {
42 UNINIT => {
43 let lvl = std::env::var("VECTOR_LOG")
44 .ok()
45 .and_then(|v| parse_level(&v))
46 .unwrap_or(DEFAULT_LEVEL);
47 LOG_LEVEL.store(lvl, Ordering::Relaxed);
48 lvl
49 }
50 v => v,
51 }
52}
53
54#[inline]
56pub fn level_enabled(level: u8) -> bool {
57 level >= log_level()
58}
59
60pub fn set_log_level(level: u8) {
62 LOG_LEVEL.store(level, Ordering::Relaxed);
63}
64
65pub fn set_log_level_str(s: &str) -> bool {
68 match parse_level(s) {
69 Some(l) => {
70 set_log_level(l);
71 true
72 }
73 None => false,
74 }
75}
76
77static PERSIST_SINK: std::sync::OnceLock<Box<dyn Fn(&str) + Send + Sync>> =
84 std::sync::OnceLock::new();
85
86pub fn set_persist_sink(sink: impl Fn(&str) + Send + Sync + 'static) {
88 let _ = PERSIST_SINK.set(Box::new(sink));
89}
90
91pub fn persist(line: &str) {
93 if let Some(sink) = PERSIST_SINK.get() {
94 sink(line);
95 }
96}
97
98pub fn timestamp_utc() -> String {
102 let secs = std::time::SystemTime::now()
103 .duration_since(std::time::UNIX_EPOCH)
104 .map(|d| d.as_secs())
105 .unwrap_or(0);
106 format_unix_utc(secs)
107}
108
109pub fn format_unix_utc(secs: u64) -> String {
111 let days = (secs / 86_400) as i64;
112 let tod = secs % 86_400;
113 let z = days + 719_468;
115 let era = if z >= 0 { z } else { z - 146_096 } / 146_097;
116 let doe = (z - era * 146_097) as u64; let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365; let y = yoe as i64 + era * 400;
119 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); let mp = (5 * doy + 2) / 153; let d = doy - (153 * mp + 2) / 5 + 1; let m = if mp < 10 { mp + 3 } else { mp - 9 }; let y = if m <= 2 { y + 1 } else { y };
124 format!(
125 "{:04}-{:02}-{:02} {:02}:{:02}:{:02}Z",
126 y,
127 m,
128 d,
129 tod / 3600,
130 (tod % 3600) / 60,
131 tod % 60
132 )
133}
134
135#[cfg(test)]
136mod ts_tests {
137 use super::format_unix_utc;
138
139 #[test]
140 fn formats_known_instants() {
141 assert_eq!(format_unix_utc(0), "1970-01-01 00:00:00Z");
142 assert_eq!(format_unix_utc(1_000_000_000), "2001-09-09 01:46:40Z");
143 assert_eq!(format_unix_utc(1_709_164_800), "2024-02-29 00:00:00Z");
145 assert_eq!(format_unix_utc(1_735_689_599), "2024-12-31 23:59:59Z");
146 assert_eq!(format_unix_utc(1_767_225_600), "2026-01-01 00:00:00Z");
147 }
148}