use crate::telemetry::log::init::{LogHarness, build_log_with_drain, wrap_root_drain};
use crate::telemetry::log::internal::LoggerWithKvNestingTracking;
use crate::telemetry::settings::LoggingSettings;
use parking_lot::RwLock as ParkingRwLock;
use slog::{Discard, Drain, KV, Key, Level, Never, OwnedKVList, Record, Serializer};
use std::fmt::Arguments;
use std::sync::{Arc, RwLock};
pub(crate) type TestLogRecords = Arc<RwLock<Vec<TestLogRecord>>>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TestLogRecord {
pub level: Level,
pub message: String,
pub fields: Vec<(String, String)>,
}
#[derive(Default)]
struct TestFieldSerializer {
fields: Vec<(String, String)>,
}
impl Serializer for TestFieldSerializer {
fn emit_arguments(&mut self, key: Key, val: &Arguments) -> slog::Result {
self.fields.push((key.to_string(), val.to_string()));
Ok(())
}
}
struct TestLogDrain<D> {
records: TestLogRecords,
forward: Option<D>,
}
impl<D> Drain for TestLogDrain<D>
where
D: Drain<Ok = (), Err = Never>,
{
type Ok = ();
type Err = Never;
fn log(&self, record: &Record, kv: &OwnedKVList) -> Result<Self::Ok, Self::Err> {
let mut serializer = TestFieldSerializer::default();
kv.serialize(record, &mut serializer).unwrap();
record.kv().serialize(record, &mut serializer).unwrap();
self.records.write().unwrap().push(TestLogRecord {
level: record.level(),
message: format!("{}", record.msg()),
fields: serializer.fields,
});
if let Some(forward_drain) = &self.forward {
let _ = forward_drain.log(record, kv);
}
Ok(())
}
}
pub(crate) fn create_test_log(
settings: &LoggingSettings,
) -> (LoggerWithKvNestingTracking, TestLogRecords) {
let log_records = Arc::new(RwLock::new(vec![]));
let drain: TestLogDrain<Discard> = TestLogDrain {
records: Arc::clone(&log_records),
forward: None,
};
let drain = wrap_root_drain(settings, drain);
let logger = build_log_with_drain(settings.verbosity, slog::o!(), Arc::clone(&drain));
let log = LoggerWithKvNestingTracking::new(logger);
let _ = LogHarness::override_for_testing(LogHarness {
root_log: Arc::new(ParkingRwLock::new(log.clone())),
root_drain: drain,
settings: settings.clone(),
log_scope_stack: Default::default(),
});
(log, log_records)
}
#[cfg(feature = "tracing-rs-compat")]
pub(crate) fn create_test_log_for_tracing_compat(
settings: &LoggingSettings,
) -> (LoggerWithKvNestingTracking, TestLogRecords) {
use tracing_slog::TracingSlogDrain;
assert!(matches!(
settings.output,
crate::telemetry::settings::LogOutput::TracingRsCompat
));
let base_drain = TracingSlogDrain {};
let log_records = Arc::new(RwLock::new(vec![]));
let drain = TestLogDrain {
records: Arc::clone(&log_records),
forward: Some(base_drain.fuse()),
};
let drain = wrap_root_drain(settings, drain);
let logger = build_log_with_drain(settings.verbosity, slog::o!(), Arc::clone(&drain));
let log = LoggerWithKvNestingTracking::new(logger);
let _ = LogHarness::override_for_testing(LogHarness {
root_log: Arc::new(ParkingRwLock::new(log.clone())),
root_drain: drain,
settings: settings.clone(),
log_scope_stack: Default::default(),
});
(log, log_records)
}