timber_rust/config/
entry.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Dante Doménech Martinez dante19031999@gmail.com
3
4#[cfg(feature = "loki")]
5use crate::config::duration::FlexibleDuration;
6#[cfg(feature = "aws")]
7use crate::config::timestamp::Timestamp;
8#[cfg(feature = "aws")]
9use crate::service::CloudWatchConfig;
10#[cfg(feature = "loki")]
11use crate::service::LokiConfig;
12#[cfg(feature = "loki")]
13use crate::BasicAuth;
14use crate::Concurrency;
15use serde::{Deserialize, Serialize};
16
17/// Represents the destination and configuration for a logging channel.
18///
19/// This enum defines where log entries are sent and how they are processed.
20/// It supports various outputs ranging from standard streams to cloud-based
21/// collectors like Grafana Loki.
22///
23/// See [`LogManager`][`crate::LogManager`] (represents a channel).
24#[derive(Clone, Debug, Serialize, Deserialize)]
25pub enum Entry {
26    /// A "black hole" destination.
27    /// All logs sent to this channel are silently discarded.
28    ///
29    /// See: [`SilentLogger`][`crate::SilentLogger`].
30    Silent {},
31
32    /// Standard Output (stdout).
33    /// Logs are printed directly to the terminal's standard output stream.
34    ///
35    /// - See: [`service::write::Cout`][`crate::service::write::Cout`]
36    /// - See: [`logger::Direct`][`crate::logger::Direct`]
37    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
38    StdOut {
39        /// The execution strategy: [`Concurrency::Sync`] for immediate writes,
40        /// or [`Concurrency::Async`] for background-threaded logging.
41        concurrency: Concurrency,
42        /// Optional override for the maximum number of write retries.
43        /// If `None`, the factory default (usually 3) is used.
44        max_retries: Option<usize>,
45        /// Optional override for the number of background worker threads.
46        /// If `None`, the factory default (usually 1) is used.
47        /// **Note:** A value of 1 is recommended to prevent interlaced output.
48        worker_count: Option<usize>,
49    },
50
51    /// Standard Error (stderr).
52    /// Logs are printed to the terminal's standard error stream, typically
53    /// used for diagnostics or errors.
54    ///
55    /// - See: [`service::write::Cerr`][`crate::service::write::Cerr`].
56    /// - See: [`logger::Direct`][`crate::logger::Direct`]
57    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
58    StdErr {
59        /// The execution strategy: [`Concurrency::Sync`] for immediate writes,
60        /// or [`Concurrency::Async`] for background-threaded logging.
61        concurrency: Concurrency,
62        /// Optional override for the maximum number of write retries.
63        /// If `None`, the factory default (usually 3) is used.
64        max_retries: Option<usize>,
65        /// Optional override for the number of background worker threads.
66        /// If `None`, the factory default (usually 1) is used.
67        /// **Note:** A value of 1 is recommended to prevent interlaced output.
68        worker_count: Option<usize>,
69    },
70
71    /// Unbuffered File Output.
72    /// Logs are written directly to a file on disk. Each write is typically
73    /// immediate, ensuring data integrity at the cost of higher I/O overhead.
74    ///
75    /// - See: [`service::write::File`][`crate::service::FileWrite`].
76    /// - See: [`logger::Direct`][`crate::logger::Direct`]
77    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
78    File {
79        /// Path to the file where to dump the log.
80        path: String,
81        /// The execution strategy: [`Concurrency::Sync`] for immediate writes,
82        /// or [`Concurrency::Async`] for background-threaded logging.
83        concurrency: Concurrency,
84        /// Optional override for the maximum number of write retries.
85        /// If `None`, the factory default (usually 3) is used.
86        max_retries: Option<usize>,
87        /// Optional override for the number of background worker threads.
88        /// If `None`, the factory default (usually 1) is used.
89        /// **Note:** A value of 1 is recommended to prevent interlaced output.
90        worker_count: Option<usize>,
91    },
92
93    /// Performance-Optimized Buffered File Output.
94    /// Logs are accumulated in a memory buffer before being flushed to disk.
95    ///
96    /// ### ⚠️ Warning
97    /// Use with caution. Because logs are held in memory, a sudden application
98    /// crash or panic may result in the loss of the most recent log entries.
99    ///
100    /// Unbuffered File Output.
101    /// Logs are written directly to a file on disk. Each write is typically
102    /// immediate, ensuring data integrity at the cost of higher I/O overhead.
103    ///
104    /// - See: [`service::write::BufferedFile`][`crate::service::write::BufferedFile`].
105    /// - See: [`service::IoWrite`][`crate::service::IoWrite`].
106    /// - See: [`std::fs::File`]
107    /// - See: [`std::io::BufWriter`]
108    /// - See: [`logger::Direct`][`crate::logger::Direct`]
109    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
110    BufferedFile {
111        /// Path to the file where to dump the log.
112        path: String,
113        /// The execution strategy: [`Concurrency::Sync`] for immediate writes,
114        /// or [`Concurrency::Async`] for background-threaded logging.
115        concurrency: Concurrency,
116        /// Optional override for the maximum number of write retries.
117        /// If `None`, the factory default (usually 3) is used.
118        max_retries: Option<usize>,
119        /// Optional override for the number of background worker threads.
120        /// If `None`, the factory default (usually 1) is used.
121        /// **Note:** A value of 1 is recommended to prevent interlaced output.
122        worker_count: Option<usize>,
123    },
124
125    /// Memory Buffer.
126    /// Captures logs into an internal string buffer, useful for testing
127    /// or displaying logs within an application UI.
128    ///
129    /// - See: [`service::write::StringFmt`][`crate::service::write::StringFmt`].
130    /// - See: [`logger::Direct`][`crate::logger::Direct`]
131    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
132    String {
133        /// The execution strategy: [`Concurrency::Sync`] for immediate writes,
134        /// or [`Concurrency::Async`] for background-threaded logging.
135        concurrency: Concurrency,
136        /// Optional override for the maximum number of write retries.
137        /// If `None`, the factory default (usually 3) is used.
138        max_retries: Option<usize>,
139        /// Optional override for the number of background worker threads.
140        /// If `None`, the factory default (usually 1) is used.
141        /// **Note:** A value of 1 is recommended to prevent interlaced output.
142        worker_count: Option<usize>,
143        /// String capacity
144        capacity: Option<usize>,
145    },
146
147    /// Memory Buffer (vector).
148    /// Captures logs into an internal vector, useful for testing.
149    ///
150    /// - See: [`service::Vector`][`crate::service::Vector`].
151    /// - See: [`logger::Direct`][`crate::logger::Direct`]
152    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
153    Vector {
154        /// The execution strategy: [`Concurrency::Sync`] for immediate writes,
155        /// or [`Concurrency::Async`] for background-threaded logging.
156        concurrency: Concurrency,
157        /// Optional override for the maximum number of write retries.
158        /// If `None`, the factory default (usually 3) is used.
159        max_retries: Option<usize>,
160        /// Optional override for the number of background worker threads.
161        /// If `None`, the factory default (usually 1) is used.
162        /// **Note:** A value of 1 is recommended to prevent interlaced output.
163        worker_count: Option<usize>,
164        /// Vector capacity
165        capacity: Option<usize>,
166    },
167
168    /// Grafana Loki Integration.
169    /// Pushes logs to a remote Loki instance via HTTP/HTTPS.
170    ///
171    /// This variant is only available when the `loki` feature is enabled.
172    ///
173    /// - See: [`LokiLogger`][`crate::logger::Loki`].
174    /// - See: [`LokiService`][`crate::service::Loki`].
175    /// - See: [`LokiConfig`][`crate::service::LokiConfig`].
176    /// - See: [`logger::Direct`][`crate::logger::Direct`]
177    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
178    #[cfg(feature = "loki")]
179    #[cfg_attr(docsrs, doc(cfg(feature = "loki")))]
180    Loki {
181        /// The full HTTP/HTTPS endpoint for the Loki push API
182        /// (e.g., `https://logs-prod-us-central1.grafana.net/loki/api/v1/push`).
183        url: String,
184        /// The name of the application. This becomes a static label used for
185        /// filtering logs in Grafana.
186        app: String,
187        /// The job name associated with the process. Useful for distinguishing
188        /// between different instances of the same application.
189        job: String,
190        /// The deployment environment (e.g., "production", "staging", "development").
191        /// Helps isolate logs across different stages of the lifecycle.
192        env: String,
193        /// Optional credentials for Basic Authentication.
194        basic_auth: Option<BasicAuth>,
195        /// Optional Bearer token for API authentication (e.g., for Grafana Cloud).
196        bearer_auth: Option<String>,
197        /// The maximum time allowed to establish a connection to the Loki server.
198        connection_timeout: FlexibleDuration,
199        /// The maximum time allowed for a single push request to complete.
200        request_timeout: FlexibleDuration,
201        /// How many times a failed push should be retried before falling back.
202        /// This is handled by the internal dispatch logic.
203        max_retries: usize,
204        /// The number of background worker threads dedicated to pushing logs.
205        /// Higher counts increase throughput but consume more network resources.
206        worker_count: usize,
207    },
208
209    /// AWS Cloudwatch Integration.
210    /// Pushes logs to a remote Cloudwatch Integration instance via AWS SDK.
211    ///
212    /// This variant is only available when the `aws` feature is enabled.
213    ///
214    /// - See: [`CloudwatchLogger`][`crate::logger::CloudWatch`].
215    /// - See: [`CloudwatchService`][`crate::service::CloudWatch`].
216    /// - See: [`CloudwatchConfig`][`crate::service::LokiConfig`].
217    /// - See: [`logger::Direct`][`crate::logger::Direct`]
218    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
219    #[cfg(feature = "aws")]
220    #[cfg_attr(docsrs, doc(cfg(feature = "aws")))]
221    CloudWatchEnv {
222        /// Log group for the cloudwatch service. The config is loaded from ENV.
223        log_group: String,
224    },
225
226    /// AWS Cloudwatch Integration.
227    /// Pushes logs to a remote Cloudwatch Integration instance via AWS SDK.
228    ///
229    /// This variant is only available when the `aws` feature is enabled.
230    ///
231    /// - See: [`CloudwatchLogger`][`crate::logger::CloudWatch`].
232    /// - See: [`CloudwatchService`][`crate::service::CloudWatch`].
233    /// - See: [`CloudwatchConfig`][`crate::service::LokiConfig`].
234    /// - See: [`logger::Direct`][`crate::logger::Direct`]
235    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
236    #[cfg(feature = "aws")]
237    #[cfg_attr(docsrs, doc(cfg(feature = "aws")))]
238    CloudWatchConfig {
239        /// AWS Access Key ID used for authentication.
240        access_key_id: String,
241        /// AWS Secret Access Key. This field is sensitive and hidden in Debug logs.
242        access_key_secret: String,
243        /// Optional session token for temporary credentials (STS).
244        session_token: Option<String>,
245        /// Optional expiration timestamp for the credentials in seconds.
246        expires_in: Option<Timestamp>,
247        /// The name of the CloudWatch Log Group where logs will be sent.
248        log_group: String,
249        /// The AWS Region (e.g., "us-east-1").
250        region: String,
251    },
252
253    /// AWS CloudWatch (via Standard Output).
254    ///
255    /// Formats logs as single-line JSON objects and prints them to `stdout`.
256    /// This is the preferred method for AWS Lambda, ECS (with `awslogs` driver),
257    /// and Fargate, as it avoids the overhead of the AWS SDK while maintaining
258    /// structured logs.
259    ///
260    /// - See: [`CloudWatchCout`][`crate::service::CloudWatchCout`].
261    /// - See: [`CloudWatchCoutMessageFormatter`][`crate::service::CloudWatchCoutMessageFormatter`].
262    /// - See: [`logger::Direct`][`crate::logger::Direct`]
263    /// - See: [`logger::Queued`][`crate::`logger::Queued`]
264    #[cfg(feature = "awscout")]
265    #[cfg_attr(docsrs, doc(cfg(feature = "awscout")))]
266    CloudWatchCout {
267        /// The execution strategy: [`Concurrency::Sync`] for immediate writes,
268        /// or [`Concurrency::Async`] for background-threaded logging.
269        concurrency: Concurrency,
270        /// Optional override for the maximum number of write retries.
271        /// If `None`, the factory default (usually 3) is used.
272        max_retries: Option<usize>,
273        /// Optional override for the number of background worker threads.
274        /// If `None`, the factory default (usually 1) is used.
275        /// **Note:** A value of 1 is recommended to prevent interlaced output.
276        worker_count: Option<usize>,
277    },
278
279    /// Placeholder for missing functionality.
280    /// Used when a configuration specifies a model (like `loki`) but the
281    /// required crate feature was not enabled at compile time.
282    DisabledFeature {
283        /// The name of the feature that is currently missing.
284        feature: String,
285    },
286}
287
288impl Entry {
289    /// Creates a configuration for a silent logger that discards all input.
290    ///
291    /// Useful as a placeholder or for completely disabling output in specific environments.
292    pub fn silent() -> Self {
293        Entry::Silent {}
294    }
295
296    /// Configures logging to the Standard Output stream (stdout).
297    ///
298    /// This is the primary target for CLI applications and containerized services.
299    pub fn stdout(concurrency: Concurrency) -> Self {
300        Entry::StdOut {
301            concurrency,
302            max_retries: None,
303            worker_count: None,
304        }
305    }
306
307    /// Configures logging to the Standard Error stream (stderr).
308    ///
309    /// Recommended for diagnostic messages to keep the main stdout stream clean for data.
310    pub fn stderr(concurrency: Concurrency) -> Self {
311        Entry::StdErr {
312            concurrency,
313            max_retries: None,
314            worker_count: None,
315        }
316    }
317
318    /// Configures an in-memory string buffer for captured logs.
319    ///
320    /// Useful for small-scale log capturing where a full Vector of messages is not required.
321    pub fn string(concurrency: Concurrency) -> Self {
322        Entry::String {
323            concurrency,
324            max_retries: None,
325            worker_count: None,
326            capacity: None,
327        }
328    }
329
330    /// Configures a raw file logger at the specified path.
331    ///
332    /// Opens the file in append mode. Ensure the process has appropriate write permissions.
333    pub fn file(concurrency: Concurrency, path: String) -> Self {
334        Entry::File {
335            path,
336            concurrency,
337            max_retries: None,
338            worker_count: None,
339        }
340    }
341
342    /// Configures a buffered file logger at the specified path.
343    ///
344    /// Wraps the file in a buffer to reduce the frequency of underlying system calls,
345    /// significantly improving performance during high-volume bursts.
346    pub fn buffered_file(concurrency: Concurrency, path: String) -> Self {
347        Entry::BufferedFile {
348            path,
349            concurrency,
350            max_retries: None,
351            worker_count: None,
352        }
353    }
354
355    /// Configures a logger that captures structured `Message` objects in a `Vec`.
356    ///
357    /// This is the "gold standard" for unit testing, allowing for precise assertions
358    /// on log levels and contents.
359    pub fn vector(concurrency: Concurrency) -> Self {
360        Entry::Vector {
361            concurrency,
362            max_retries: None,
363            worker_count: None,
364            capacity: None,
365        }
366    }
367
368    /// Integrates a Grafana Loki configuration into the entry list.
369    ///
370    /// This converts a high-level [`LokiConfig`] into the flat enum representation.
371    #[cfg(feature = "loki")]
372    #[cfg_attr(docsrs, doc(cfg(feature = "loki")))]
373    pub fn loki(config: LokiConfig) -> Self {
374        Entry::Loki {
375            url: config.url,
376            app: config.app,
377            job: config.job,
378            env: config.env,
379            basic_auth: config.basic_auth,
380            bearer_auth: config.bearer_auth,
381            connection_timeout: config.connection_timeout.into(),
382            request_timeout: config.request_timeout.into(),
383            max_retries: config.max_retries,
384            worker_count: config.worker_count,
385        }
386    }
387
388    /// Configures Amazon CloudWatch using explicit credentials.
389    ///
390    /// Use this when credentials are provided manually or via a secret manager.
391    #[cfg(feature = "aws")]
392    #[cfg_attr(docsrs, doc(cfg(feature = "aws")))]
393    pub fn cloudwatch_config(config: CloudWatchConfig) -> Self {
394        Entry::CloudWatchConfig {
395            access_key_id: config.access_key_id,
396            access_key_secret: config.access_key_secret,
397            session_token: config.session_token,
398            expires_in: config.expires_in.map(|t| Timestamp::from(t)),
399            log_group: config.log_group,
400            region: config.region,
401        }
402    }
403
404    /// Configures Amazon CloudWatch using credentials sourced from the environment.
405    ///
406    /// Standard AWS environment variables (AWS_ACCESS_KEY_ID, etc.) will be used automatically.
407    #[cfg(feature = "aws")]
408    #[cfg_attr(docsrs, doc(cfg(feature = "aws")))]
409    pub fn cloudwatch_env(log_group: String) -> Self {
410        Entry::CloudWatchEnv { log_group }
411    }
412
413    /// Configures a CloudWatch-formatted logger that writes to stdout.
414    ///
415    /// This allows logs to be formatted for AWS CloudWatch even if they are
416    /// being emitted to a local terminal or captured by a separate log agent.
417    #[cfg(feature = "aws")]
418    #[cfg_attr(docsrs, doc(cfg(feature = "aws")))]
419    pub fn cloudwatch_cout(concurrency: Concurrency) -> Self {
420        Entry::CloudWatchCout {
421            concurrency,
422            worker_count: None,
423            max_retries: None,
424        }
425    }
426}