Skip to main content

LogDispatcher

Struct LogDispatcher 

Source
pub struct LogDispatcher { /* private fields */ }
Expand description

Thread-safe fan-out dispatcher; ordinary sinks receive only sanitized events.

Implementations§

Source§

impl LogDispatcher

Source

pub fn new(policy: LogPolicy, sinks: Vec<Arc<dyn LogSink>>) -> Self

Creates a dispatcher with explicit filtering and sinks.

Examples found in repository?
examples/component_filter.rs (line 26)
19fn main() {
20    // All components start at V4, keeping normal output concise.
21    let mut policy = LogPolicy::new(Verbosity::V4);
22
23    // Synchronization may need temporary I/O and timing diagnostics.
24    policy.set_component("sync", Verbosity::V8);
25
26    let log = LogDispatcher::new(policy, vec![Arc::new(ConsoleSink::new())]);
27
28    let event = log.event(0, "sync");
29
30    // This V7 event is selected only because the sync override allows it.
31    event.verbosity(7).debug("batch details");
32}
More examples
Hide additional examples
examples/sensitive_diagnostics.rs (line 48)
24fn main() -> Result<(), appcore_log::LogError> {
25    let key_id = KeyId::new("example-log-key").map_err(|_| appcore_log::LogError::Encryption)?;
26
27    let provider =
28        StaticDntKeyProvider::new().with_key(key_id.clone(), SecretKey::new(demo_key()?));
29
30    // The sink bounds the encrypted snapshot by both bytes and event count.
31    let sink = SensitiveDntSink::new(
32        SensitiveDntSinkConfig {
33            path: std::env::temp_dir().join("appcore-sensitive-log.dnt"),
34            application_id: ApplicationId::new("example-log")
35                .map_err(|_| appcore_log::LogError::Encryption)?,
36            key_id,
37            max_bytes: 4096,
38            max_events: 8,
39            retention: 2,
40        },
41        provider,
42    )?;
43
44    // Sensitive mode must be explicit and has no console or JSONL fallback.
45    let mut policy = LogPolicy::default();
46    policy.sensitivity = Sensitivity::Sensitive;
47
48    let log = LogDispatcher::new(policy, vec![Arc::new(sink)]);
49
50    log.event(0, "security").verbosity(2).error("diagnostic");
51
52    Ok(())
53}
examples/async_file.rs (line 40)
19fn main() -> Result<(), LogError> {
20    let directory = std::path::PathBuf::from("target/appcore-log-example");
21    std::fs::create_dir_all(&directory).map_err(|_| LogError::Io)?;
22
23    let path = directory.join("async.jsonl");
24    let file = Arc::new(FileSink::new(FileSinkConfig {
25        path: path.clone(),
26        max_bytes: LOG_SIZE_8_MIB,
27        sync_each_write: true,
28        retention: 2,
29        archive: None,
30    })?);
31
32    // This queue retains at most 256 events and 1 MiB, including active I/O.
33    let asynchronous = Arc::new(AsyncSink::new(
34        AsyncSinkConfig {
35            max_events: 256,
36            max_bytes: 1024 * 1024,
37        },
38        file,
39    )?);
40    let dispatcher = LogDispatcher::new(LogPolicy::default(), vec![asynchronous.clone()]);
41    let log = dispatcher.event(0, "application");
42
43    log.info("application started");
44    log.warn("storage response is slow");
45
46    // The lifecycle owner drains durable writes before exiting.
47    asynchronous.shutdown()?;
48    let path = std::fs::canonicalize(path).map_err(|_| LogError::Io)?;
49    println!("log written to {}", path.display());
50    Ok(())
51}
Source

pub fn emit(&self, event: LogEvent)

Emits once. Critical failure accounting is retained even when a sink fails.

Source

pub fn event<'a>( &'a self, timestamp_ms: u64, component: impl Into<Cow<'a, str>>, ) -> LogBuilder<'a>

Creates a fluent event builder for a stable component and clock value.

Examples found in repository?
examples/component_filter.rs (line 28)
19fn main() {
20    // All components start at V4, keeping normal output concise.
21    let mut policy = LogPolicy::new(Verbosity::V4);
22
23    // Synchronization may need temporary I/O and timing diagnostics.
24    policy.set_component("sync", Verbosity::V8);
25
26    let log = LogDispatcher::new(policy, vec![Arc::new(ConsoleSink::new())]);
27
28    let event = log.event(0, "sync");
29
30    // This V7 event is selected only because the sync override allows it.
31    event.verbosity(7).debug("batch details");
32}
More examples
Hide additional examples
examples/basic.rs (line 27)
18fn main() -> Result<(), appcore_log::LogConfigError> {
19    // Safe V4 terminal logging is explicit and creates no global state.
20    let logger = LoggerConfig {
21        output: LogOutputMode::Terminal,
22        ..LoggerConfig::default()
23    }
24    .build()?;
25
26    // The builder defaults to V4 and can be kept for related events.
27    let log = logger.dispatcher().event(0, "application");
28
29    log.info("application started");
30    log.warn("connection is slower than expected");
31    log.error("document could not be saved");
32
33    Ok(())
34}
examples/output_modes.rs (line 34)
15fn main() -> Result<(), appcore_log::LogConfigError> {
16    // Replace this with Disabled, Terminal, File, TerminalAndFile or CrashOnly.
17    let output = LogOutputMode::CrashOnly;
18
19    let logger = LoggerConfig {
20        output,
21        file: Some(FileSinkConfig {
22            path: std::env::temp_dir().join("my-application-crash.jsonl"),
23            max_bytes: LOG_SIZE_2_MIB,
24            sync_each_write: true,
25            retention: 1,
26            archive: None,
27        }),
28        crash_events: 128,
29        crash_bytes: 512 * 1024,
30        ..LoggerConfig::default()
31    }
32    .build()?;
33
34    let log = logger.dispatcher().event(0, "application");
35
36    log.info("kept only in the bounded crash ring");
37
38    // Call this from the application's panic/crash boundary. In every other
39    // mode it is a no-op and returns zero.
40    let _written_events = logger.dump_crash()?;
41
42    Ok(())
43}
examples/sensitive_diagnostics.rs (line 50)
24fn main() -> Result<(), appcore_log::LogError> {
25    let key_id = KeyId::new("example-log-key").map_err(|_| appcore_log::LogError::Encryption)?;
26
27    let provider =
28        StaticDntKeyProvider::new().with_key(key_id.clone(), SecretKey::new(demo_key()?));
29
30    // The sink bounds the encrypted snapshot by both bytes and event count.
31    let sink = SensitiveDntSink::new(
32        SensitiveDntSinkConfig {
33            path: std::env::temp_dir().join("appcore-sensitive-log.dnt"),
34            application_id: ApplicationId::new("example-log")
35                .map_err(|_| appcore_log::LogError::Encryption)?,
36            key_id,
37            max_bytes: 4096,
38            max_events: 8,
39            retention: 2,
40        },
41        provider,
42    )?;
43
44    // Sensitive mode must be explicit and has no console or JSONL fallback.
45    let mut policy = LogPolicy::default();
46    policy.sensitivity = Sensitivity::Sensitive;
47
48    let log = LogDispatcher::new(policy, vec![Arc::new(sink)]);
49
50    log.event(0, "security").verbosity(2).error("diagnostic");
51
52    Ok(())
53}
examples/async_file.rs (line 41)
19fn main() -> Result<(), LogError> {
20    let directory = std::path::PathBuf::from("target/appcore-log-example");
21    std::fs::create_dir_all(&directory).map_err(|_| LogError::Io)?;
22
23    let path = directory.join("async.jsonl");
24    let file = Arc::new(FileSink::new(FileSinkConfig {
25        path: path.clone(),
26        max_bytes: LOG_SIZE_8_MIB,
27        sync_each_write: true,
28        retention: 2,
29        archive: None,
30    })?);
31
32    // This queue retains at most 256 events and 1 MiB, including active I/O.
33    let asynchronous = Arc::new(AsyncSink::new(
34        AsyncSinkConfig {
35            max_events: 256,
36            max_bytes: 1024 * 1024,
37        },
38        file,
39    )?);
40    let dispatcher = LogDispatcher::new(LogPolicy::default(), vec![asynchronous.clone()]);
41    let log = dispatcher.event(0, "application");
42
43    log.info("application started");
44    log.warn("storage response is slow");
45
46    // The lifecycle owner drains durable writes before exiting.
47    asynchronous.shutdown()?;
48    let path = std::fs::canonicalize(path).map_err(|_| LogError::Io)?;
49    println!("log written to {}", path.display());
50    Ok(())
51}
examples/file_logging.rs (line 52)
22fn main() -> Result<(), appcore_log::LogConfigError> {
23    // Keep generated output predictable and inside Cargo's ignored target tree.
24    let output_directory = PathBuf::from("target/appcore-log-example");
25    std::fs::create_dir_all(&output_directory).map_err(|_| LogConfigError::Sink(LogError::Io))?;
26
27    let active_file = output_directory.join("application.jsonl");
28
29    // Two rotations stay beside the active file. Older rotations move into
30    // archive/YYYY/MM and the complete archive never exceeds 120 files.
31    let archive_directory = output_directory.join("archive");
32    let mut policy = LogPolicy::new(Verbosity::V4);
33    policy.set_component("sync", Verbosity::V8);
34
35    let logger = LoggerConfig {
36        policy,
37        output: LogOutputMode::TerminalAndFile,
38        file: Some(FileSinkConfig {
39            path: active_file,
40            max_bytes: LOG_SIZE_8_MIB,
41            sync_each_write: false,
42            retention: 2,
43            archive: Some(FileArchiveConfig {
44                directory: archive_directory,
45                max_files: 120,
46            }),
47        }),
48        ..LoggerConfig::default()
49    }
50    .build()?;
51
52    let application = logger.dispatcher().event(0, "application");
53    let sync = logger.dispatcher().event(1, "sync.transport");
54
55    application.info("application ready; inspect target/appcore-log-example/application.jsonl");
56
57    // The parent component policy makes this V7 diagnostic visible.
58    sync.verbosity(7).debug("replication batch sent");
59
60    sync.warn("peer response was delayed");
61
62    let stats = logger.dispatcher().stats();
63    assert_eq!(stats.sink_failures, 0);
64
65    Ok(())
66}
Source

pub fn event_now<'a>( &'a self, clock: &dyn LogClock, component: impl Into<Cow<'a, str>>, ) -> LogBuilder<'a>

Creates a fluent event builder using an injected clock.

Source

pub fn enabled(&self, component: &str, verbosity: Verbosity) -> bool

Reports whether a component and verbosity would reach at least one sink.

Source

pub fn stats(&self) -> LogStats

Returns counters without taking global locks.

Examples found in repository?
examples/file_logging.rs (line 62)
22fn main() -> Result<(), appcore_log::LogConfigError> {
23    // Keep generated output predictable and inside Cargo's ignored target tree.
24    let output_directory = PathBuf::from("target/appcore-log-example");
25    std::fs::create_dir_all(&output_directory).map_err(|_| LogConfigError::Sink(LogError::Io))?;
26
27    let active_file = output_directory.join("application.jsonl");
28
29    // Two rotations stay beside the active file. Older rotations move into
30    // archive/YYYY/MM and the complete archive never exceeds 120 files.
31    let archive_directory = output_directory.join("archive");
32    let mut policy = LogPolicy::new(Verbosity::V4);
33    policy.set_component("sync", Verbosity::V8);
34
35    let logger = LoggerConfig {
36        policy,
37        output: LogOutputMode::TerminalAndFile,
38        file: Some(FileSinkConfig {
39            path: active_file,
40            max_bytes: LOG_SIZE_8_MIB,
41            sync_each_write: false,
42            retention: 2,
43            archive: Some(FileArchiveConfig {
44                directory: archive_directory,
45                max_files: 120,
46            }),
47        }),
48        ..LoggerConfig::default()
49    }
50    .build()?;
51
52    let application = logger.dispatcher().event(0, "application");
53    let sync = logger.dispatcher().event(1, "sync.transport");
54
55    application.info("application ready; inspect target/appcore-log-example/application.jsonl");
56
57    // The parent component policy makes this V7 diagnostic visible.
58    sync.verbosity(7).debug("replication batch sent");
59
60    sync.warn("peer response was delayed");
61
62    let stats = logger.dispatcher().stats();
63    assert_eq!(stats.sink_failures, 0);
64
65    Ok(())
66}
Source

pub fn sink_stats(&self) -> Vec<SinkStats>

Returns bounded failure counters for each configured sink.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.