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};