Skip to main content

solti_observe/
lib.rs

1//! # solti-observe
2//!
3//! Observability primitives for the solti task execution system.
4//!
5//! This crate wires [`tracing`] into solti, covering three concerns:
6//!
7//! 1. **Logger initialization** - [`init_logger`] installs a global tracing
8//!    subscriber configured via [`LoggerConfig`] (format, level filter,
9//!    timezone, color).
10//! 2. **Event logging** - [`TracingEventSubscriber`] (feature `subscriber`)
11//!    maps every [`taskvisor`] supervision event to a structured tracing call
12//!    at the appropriate severity level.
13//! 3. **Timezone sync** - [`timezone_sync`] (feature `timezone-sync`) is a
14//!    periodic task that re-detects the local UTC offset so log timestamps
15//!    stay correct across DST transitions.
16//!
17//! ## Architecture
18//!
19//! ```text
20//!  main()
21//!  ├─ init_local_offset()              // before tokio runtime
22//!  └─ tokio::Runtime::new()
23//!      └─ async_main()
24//!          ├─ init_logger(&cfg)        // installs global tracing subscriber
25//!          │   ├─ Text  → fmt::Layer (colored, RFC 3339 timestamps)
26//!          │   ├─ Json  → fmt::Layer::json()
27//!          │   └─ Journald → tracing_journald::layer() (Linux only)
28//!          │
29//!          ├─ TracingEventSubscriber   // feature: subscriber
30//!          │   └─ on_event() → trace!/debug!/info!/warn!/error!
31//!          │
32//!          └─ timezone_sync()          // feature: timezone-sync
33//!              └─ periodic re-detection of local UTC offset
34//!  ```
35//!
36//! ## Public API
37//!
38//! | Item                                     | Feature         | Description                                              |
39//! |------------------------------------------|-----------------|----------------------------------------------------------|
40//! | [`LoggerConfig`]                         | -               | Logger configuration (format, level, timezone, color)    |
41//! | [`init_logger`]                          | -               | Install global tracing subscriber                        |
42//! | [`init_local_offset`]                    | -               | Detect local UTC offset (call before tokio runtime)      |
43//! | [`LoggerFormat`]                         | -               | Output format: `Text` / `Json` / `Journald`              |
44//! | [`LoggerLevel`]                          | -               | Validated `EnvFilter` expression wrapper                 |
45//! | [`LoggerTimeZone`]                       | -               | Timestamp timezone: `Utc` / `Local`                      |
46//! | [`LoggerError`]                          | -               | Error type for logger initialization                     |
47//! | [`TracingEventSubscriber`]               | `subscriber`    | Logs [`taskvisor`] events via tracing                    |
48//! | [`timezone_sync`]                        | `timezone-sync` | Periodic task that re-detects the local UTC offset       |
49//!
50//! ## Feature flags
51//!
52//! | Flag            | Default | Dependencies                        | Effect                                        |
53//! |-----------------|---------|-------------------------------------|-----------------------------------------------|
54//! | `subscriber`    | off     | `taskvisor`, `async-trait`          | Enables [`TracingEventSubscriber`]            |
55//! | `timezone-sync` | off     | `taskvisor`, `tokio-util`, `solti-model` | Enables [`timezone_sync`] periodic task  |
56//!
57//! ## Quick start
58//!
59//! ```text
60//! use solti_observe::{LoggerConfig, LoggerLevel, init_local_offset, init_logger};
61//!
62//! fn main() -> Result<(), Box<dyn std::error::Error>> {
63//!     // 1) Must be called before spawning threads (tokio runtime).
64//!     init_local_offset();
65//!
66//!     tokio::runtime::Runtime::new()?.block_on(async {
67//!         // 2) Initialize logger
68//!         let cfg = LoggerConfig {
69//!             level: LoggerLevel::new("info")?,
70//!             ..Default::default()
71//!         };
72//!         init_logger(&cfg)?;
73//!
74//!         tracing::info!("ready");
75//!         Ok(())
76//!     })
77//! }
78//! ```
79//!
80//! ## Local timezone support
81//!
82//! On most Unix platforms, detecting the local UTC offset requires reading `/etc/localtime`,
83//! which is unsafe in multi-threaded processes.
84//!
85//! To workaround this:
86//! 1. Call [`init_local_offset`] in `main()` **before** `tokio::runtime::Runtime::new()`.
87//! 2. Optionally submit the [`timezone_sync`] task to periodically re-detect
88//!    the offset (handles DST transitions in long-running daemons).
89//!
90//! If [`init_local_offset`] is not called, timestamps fall back to UTC with a warning printed to stderr on first use.
91//!
92//! ## Also
93//!
94//! - [`tracing`] the underlying structured logging framework.
95//! - [`taskvisor::Subscribe`] trait that [`TracingEventSubscriber`] implements.
96//! - `solti-prometheus` is a complementary metrics subscriber for the same event stream.
97//! - See `examples/http-server` for a complete integration example.
98
99mod logger;
100pub use logger::{
101    LoggerConfig, LoggerError, LoggerFormat, LoggerLevel, LoggerTimeZone, init_local_offset,
102    init_logger,
103};
104
105// Periodic task that re-detects the local UTC offset.
106// Enable with: `--features timezone-sync`
107#[cfg(feature = "timezone-sync")]
108pub use logger::timezone_sync;
109
110#[cfg(feature = "subscriber")]
111mod subscriber;
112#[cfg(feature = "subscriber")]
113pub use subscriber::{TracingEventSubscriber, View, log_event};