homestar_runtime/
logger.rs

1//! Logger initialization.
2
3use crate::settings;
4use std::{io, path::PathBuf};
5use tracing_appender::non_blocking::{NonBlocking, WorkerGuard};
6use tracing_subscriber::{layer::SubscriberExt as _, prelude::*, EnvFilter};
7
8const LOG_FILE: &str = "homestar.log";
9const DIRECTIVE_EXPECT: &str = "Invalid tracing directive";
10// Sets simplified logging filter and format for Every CLI
11const EVERY_CLI: &str = "EVERY_CLI";
12
13/// Logger interface.
14#[derive(Debug)]
15pub struct Logger;
16/// File-logger interface.
17#[derive(Debug)]
18pub struct FileLogger;
19
20impl Logger {
21    /// Initialize a [tracing_subscriber::Registry] with a [logfmt] layer and
22    /// write to [io::stdout].
23    ///
24    /// [logfmt]: <https://brandur.org/logfmt>
25    pub fn init(settings: &settings::Monitoring) -> WorkerGuard {
26        let (writer, guard) = tracing_appender::non_blocking(io::stdout());
27        init(writer, guard, settings)
28    }
29}
30
31impl FileLogger {
32    /// Initialize a [tracing_subscriber::Registry] with a [logfmt] layer and
33    /// write to file.
34    ///
35    /// [logfmt]: <https://brandur.org/logfmt>
36    pub fn init(dir: PathBuf, settings: &settings::Monitoring) -> WorkerGuard {
37        let file_appender = tracing_appender::rolling::daily(dir, LOG_FILE);
38        let (writer, guard) = tracing_appender::non_blocking(file_appender);
39        init(writer, guard, settings)
40    }
41}
42
43fn init(
44    writer: NonBlocking,
45    guard: WorkerGuard,
46    #[allow(unused_variables)] settings: &settings::Monitoring,
47) -> WorkerGuard {
48    // RUST_LOG ignored when EVERY_CLI is true
49    let every_cli: bool = std::env::var(EVERY_CLI).is_ok_and(|val| val == "true");
50
51    // TODO: Add support for customizing logger(s) / specialzed formatters.
52    let format_layer = if every_cli {
53        tracing_logfmt::builder()
54            .with_level(true)
55            .with_target(false)
56            .with_span_name(false)
57            .with_span_path(false)
58            .with_location(false)
59            .with_module_path(false)
60            .layer()
61            .with_writer(writer)
62    } else {
63        tracing_logfmt::builder()
64            .with_level(true)
65            .with_target(true)
66            .with_span_name(true)
67            .with_span_path(true)
68            .with_location(true)
69            .with_module_path(true)
70            .layer()
71            .with_writer(writer)
72    };
73
74    let filter = if every_cli {
75        EnvFilter::new("off")
76            .add_directive(
77                "homestar_runtime::runner[run_worker]=info"
78                    .parse()
79                    .expect(DIRECTIVE_EXPECT),
80            )
81            .add_directive(
82                "homestar_runtime::worker[run]=info"
83                    .parse()
84                    .expect(DIRECTIVE_EXPECT),
85            )
86            .add_directive(
87                "homestar_runtime::worker[spawn_workflow_tasks]=info"
88                    .parse()
89                    .expect(DIRECTIVE_EXPECT),
90            )
91            .add_directive(
92                "homestar_wasm[wasi_log]=trace"
93                    .parse()
94                    .expect(DIRECTIVE_EXPECT),
95            )
96    } else {
97        EnvFilter::try_from_default_env().unwrap_or_else(|_| {
98            EnvFilter::new("info")
99                .add_directive("homestar_wasm=info".parse().expect(DIRECTIVE_EXPECT))
100                .add_directive("libp2p=info".parse().expect(DIRECTIVE_EXPECT))
101                .add_directive(
102                    "libp2p_gossipsub::behaviour=info"
103                        .parse()
104                        .expect(DIRECTIVE_EXPECT),
105                )
106                .add_directive("tarpc=info".parse().expect(DIRECTIVE_EXPECT))
107                .add_directive("tower_http=info".parse().expect(DIRECTIVE_EXPECT))
108                .add_directive("moka=info".parse().expect(DIRECTIVE_EXPECT))
109                .add_directive("jsonrpsee=info".parse().expect(DIRECTIVE_EXPECT))
110        })
111    };
112
113    #[cfg(all(
114        feature = "console",
115        not(test),
116        not(feature = "test-utils"),
117        tokio_unstable
118    ))]
119    let filter = filter
120        .add_directive("tokio=trace".parse().expect(DIRECTIVE_EXPECT))
121        .add_directive("runtime=trace".parse().expect(DIRECTIVE_EXPECT));
122
123    let registry = tracing_subscriber::Registry::default()
124        .with(filter)
125        .with(format_layer);
126
127    #[cfg(all(
128        feature = "console",
129        not(test),
130        not(feature = "test-utils"),
131        tokio_unstable
132    ))]
133    {
134        let console_layer = console_subscriber::ConsoleLayer::builder()
135            .retention(std::time::Duration::from_secs(60))
136            .server_addr(([127, 0, 0, 1], settings.console_subscriber_port))
137            .spawn();
138
139        registry.with(console_layer).init();
140    }
141
142    #[cfg(any(
143        not(feature = "console"),
144        test,
145        not(tokio_unstable),
146        feature = "test-utils",
147    ))]
148    {
149        registry.init();
150    }
151
152    guard
153}