timber_rust/service/fallback.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Dante Doménech Martinez dante19031999@gmail.com
3
4use crate::Message;
5use crate::service::ServiceError;
6use chrono::{SecondsFormat, Utc};
7
8/// A strategy for handling log delivery failures.
9///
10/// The `Fallback` trait defines how the system should react when a log service
11/// is unable to process a [message][`Message`] after exhausting all retry attempts.
12///
13/// ### Use Cases
14/// - **Local Logging**: Writing failed logs to `stdout`, `stderr`, or a local file.
15/// - **Alerting**: Triggering a secondary notification system if critical logs are lost.
16/// - **Buffering**: Storing failed [messages][`Message`] in a persistent queue for later recovery.
17///
18/// ### Thread Safety
19/// Since the worker thread calls this trait's method, implementations must be
20/// thread-safe if they involve shared state.
21pub trait Fallback {
22 /// Handles a [message][`Message`] that could not be delivered to the primary service.
23 ///
24 /// This method is invoked by the background worker when a [`ServiceError`] occurs
25 /// that cannot be recovered through retries.
26 ///
27 /// # Default Implementation
28 ///
29 /// The default implementation prints a formatted critical error message to **stderr**.
30 /// It includes:
31 /// 1. The specific [`ServiceError`] description.
32 /// 2. An RFC3339-compliant timestamp with nanosecond precision.
33 /// 3. The log level and the original message content.
34 ///
35 /// This ensures that even if the remote collector is unreachable,
36 /// the logs are preserved in the system's standard error stream.
37 ///
38 /// # Parameters
39 /// - `error`: The specific error that caused the delivery failure.
40 /// - `message`: The original log [message][`Message`] that failed to be delivered.
41 fn fallback(&self, error: &ServiceError, message: &Message) {
42 let now: chrono::DateTime<Utc> = message.instant().into();
43 eprintln!(
44 "[CRITICAL LOGGER FAILURE] {}: {} [ {} ] {}",
45 error,
46 now.to_rfc3339_opts(SecondsFormat::Nanos, true),
47 message.level(),
48 message.content()
49 );
50 }
51}