witchcraft_server/logging/
mod.rs1use crate::extensions::AuditLogEntry;
17use crate::logging::api::objects::{AuditLogV3, EventLogV2, RequestLogV2};
18use crate::shutdown_hooks::ShutdownHooks;
19use conjure_error::Error;
20use conjure_serde::json;
21use futures::executor::block_on;
22use futures::SinkExt;
23use lazycell::AtomicLazyCell;
24pub(crate) use logger::Appender;
25use once_cell::sync::OnceCell;
26use refreshable::Refreshable;
27use std::io;
28use std::io::Write as _;
29use std::sync::Arc;
30use tokio::sync::Mutex;
31use witchcraft_metrics::MetricRegistry;
32use witchcraft_server_config::install::InstallConfig;
33use witchcraft_server_config::runtime::LoggingConfig;
34
35pub use witchcraft_logging_api as api;
36
37mod cleanup;
38mod format;
39mod logger;
40pub mod mdc;
41mod metric;
42mod service;
43mod trace;
44
45pub(crate) static AUDIT_LOGGER: AtomicLazyCell<Arc<Mutex<Appender<AuditLogV3>>>> =
46 AtomicLazyCell::NONE;
47
48static EVENT_LOGGER: OnceCell<Appender<EventLogV2>> = OnceCell::new();
49static REQUEST_LOGGER: OnceCell<Arc<Appender<RequestLogV2>>> = OnceCell::new();
50
51pub(crate) const REQUEST_ID_KEY: &str = "_requestId";
52pub(crate) const SAMPLED_KEY: &str = "_sampled";
53
54pub(crate) struct Loggers {
55 pub request_logger: Arc<Appender<RequestLogV2>>,
56 pub audit_logger: Arc<Mutex<Appender<AuditLogV3>>>,
57}
58
59pub(crate) fn early_init() {
60 service::early_init()
61}
62
63pub(crate) async fn init(
64 metrics: &Arc<MetricRegistry>,
65 install: &InstallConfig,
66 runtime: &Refreshable<LoggingConfig, Error>,
67 hooks: &mut ShutdownHooks,
68) -> Result<Loggers, Error> {
69 metric::init(metrics, install, hooks).await?;
70 service::init(metrics, install, runtime, hooks).await?;
71 trace::init(metrics, install, runtime, hooks).await?;
72 let request_logger = logger::appender(install, metrics, hooks).await?;
73 let request_logger = Arc::new(request_logger);
74 let audit_logger = logger::appender(install, metrics, hooks).await?;
75 let audit_logger = Arc::new(Mutex::new(audit_logger));
76 let event_logger = logger::appender(install, metrics, hooks).await?;
77
78 REQUEST_LOGGER
79 .set(request_logger.clone())
80 .ok()
81 .expect("Request logger already initialized");
82
83 AUDIT_LOGGER
84 .fill(audit_logger.clone())
85 .ok()
86 .expect("Audit logger already initialized");
87
88 EVENT_LOGGER
89 .set(event_logger)
90 .ok()
91 .expect("Event logger already initialized");
92
93 cleanup::cleanup_logs().await;
94
95 Ok(Loggers {
96 request_logger,
97 audit_logger,
98 })
99}
100
101pub(crate) fn get_existing() -> Result<Loggers, Error> {
102 let audit_logger = AUDIT_LOGGER
103 .borrow()
104 .ok_or_else(|| Error::internal_safe("Audit logger not initialized"))?;
105
106 let request_logger = REQUEST_LOGGER
107 .get()
108 .ok_or_else(|| Error::internal_safe("Event logger not initialized"))?;
109
110 Ok(Loggers {
111 request_logger: request_logger.clone(),
112 audit_logger: audit_logger.clone(),
113 })
114}
115
116pub async fn audit_log(entry: AuditLogEntry) -> Result<(), Error> {
122 let audit_logger = AUDIT_LOGGER
123 .borrow()
124 .ok_or_else(|| Error::internal_safe("Audit logger not initialized"))?;
125
126 audit_logger
127 .lock()
128 .await
129 .feed(entry.0)
130 .await
131 .map_err(|_| Error::internal_safe("Audit logger is closed or not ready"))?;
132
133 Ok(())
134}
135
136pub fn audit_log_blocking(entry: AuditLogEntry) -> Result<(), Error> {
138 block_on(audit_log(entry))
139}
140
141pub fn event_log(entry: EventLogV2) {
145 match EVENT_LOGGER.get() {
146 Some(event_logger) => {
147 let _ = event_logger.try_send(entry);
148 }
149 None => {
150 let mut buf = json::to_vec(&entry).unwrap();
151 buf.push(b'\n');
152 let _ = io::stdout().write_all(&buf);
153 }
154 }
155}