Skip to content

Commit bce5be3

Browse files
committed
feat: add a utility to create child logger without magic string of the src
1 parent 6df1fbc commit bce5be3

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

mithril-common/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub mod crypto_helper;
5757
pub mod entities;
5858
#[macro_use]
5959
pub mod era;
60+
pub mod logging;
6061
pub mod messages;
6162
pub mod protocol;
6263
pub mod resource_pool;

mithril-common/src/logging.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//! Logging utilities for the Mithril project.
2+
3+
use slog::Logger;
4+
5+
/// Extension trait for `slog::Logger`
6+
pub trait LoggerExtensions {
7+
/// Create a new child logger with a `src` key containing the component name.
8+
fn new_with_component_name<T>(&self) -> Self;
9+
}
10+
11+
impl LoggerExtensions for Logger {
12+
fn new_with_component_name<T>(&self) -> Self {
13+
self.new(slog::o!("src" => component_name::<T>()))
14+
}
15+
}
16+
17+
fn component_name<T>() -> &'static str {
18+
let complete_name = std::any::type_name::<T>();
19+
complete_name.split("::").last().unwrap_or(complete_name)
20+
}
21+
22+
#[cfg(test)]
23+
mod tests {
24+
use super::*;
25+
use crate::test_utils::{TempDir, TestLogger};
26+
use slog::info;
27+
28+
struct TestStruct;
29+
#[allow(
30+
dead_code,
31+
reason = "A field is needed to add the lifetime but is unused"
32+
)]
33+
struct TestStructWithLifetime<'a>(&'a str);
34+
enum TestEnum {}
35+
36+
mod test_mod {
37+
pub struct ScopedTestStruct;
38+
pub enum ScopedTestEnum {}
39+
}
40+
41+
impl TestStruct {
42+
fn self_component_name() -> &'static str {
43+
component_name::<Self>()
44+
}
45+
}
46+
47+
#[test]
48+
fn extract_component_name_remove_namespaces() {
49+
assert_eq!(component_name::<TestStruct>(), "TestStruct");
50+
assert_eq!(component_name::<TestEnum>(), "TestEnum");
51+
assert_eq!(
52+
component_name::<test_mod::ScopedTestStruct>(),
53+
"ScopedTestStruct"
54+
);
55+
assert_eq!(
56+
component_name::<test_mod::ScopedTestEnum>(),
57+
"ScopedTestEnum"
58+
);
59+
assert_eq!(TestStruct::self_component_name(), "TestStruct");
60+
assert_eq!(
61+
component_name::<TestStructWithLifetime>(),
62+
"TestStructWithLifetime"
63+
);
64+
}
65+
66+
#[test]
67+
fn logger_extension_new_with_component_name() {
68+
let log_path =
69+
TempDir::create("common_logging", "logger_extension_new_with_component_name")
70+
.join("test.log");
71+
{
72+
let root_logger = TestLogger::file(&log_path);
73+
let child_logger = root_logger.new_with_component_name::<TestStruct>();
74+
info!(child_logger, "Child log");
75+
}
76+
77+
let logs = std::fs::read_to_string(&log_path).unwrap();
78+
assert!(
79+
logs.contains("src") && logs.contains("TestStruct"),
80+
"log should contain `src` key for `TestStruct` as component name was provided, logs:\n{logs}"
81+
);
82+
}
83+
}

0 commit comments

Comments
 (0)