Skip to main content

witchcraft_server/logging/
mod.rs

1// Copyright 2021 Palantir Technologies, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Logging APIs
16use 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
116/// Write the provided v3 audit log entry to the audit log using the global audit logger.
117///
118/// Returns an error if the global audit logger is not initialized.
119///
120/// The returned future completes once the audit log has been successfully queued.
121pub 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
136/// Blocking variant of [audit_log].
137pub fn audit_log_blocking(entry: AuditLogEntry) -> Result<(), Error> {
138    block_on(audit_log(entry))
139}
140
141/// Writes the provided V2 event log entry using the standard logging appender without blocking.
142///
143/// If the logging appender is not initialized, this instead writes out to stdout.
144pub 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}