freeswitch_log_parser/lib.rs
1//! Parser for FreeSWITCH log files.
2//!
3//! Handles the full complexity of `mod_logfile` output: five distinct line
4//! formats, multi-line CHANNEL_DATA and SDP dumps, truncated buffer collisions,
5//! and per-session state tracking — all with zero dependencies and no regex.
6//!
7//! # Architecture
8//!
9//! The parser is organized in three composable layers, each wrapping the previous:
10//!
11//! - **Layer 1** ([`parse_line`]) — stateless, zero-allocation single-line classifier
12//! - **Layer 2** ([`LogStream`]) — structural state machine that groups continuations,
13//! classifies messages, and detects multi-line blocks
14//! - **Layer 3** ([`SessionTracker`]) — per-UUID state machine that propagates
15//! dialplan context, channel state, and variables across entries; extensible
16//! via [`SessionTracker::with_relationship_hook`] for custom leg detection
17//!
18//! See `docs/design-rationale.md` in the repository for the full story on format
19//! discovery, parsing strategy, and why each layer exists.
20//!
21//! # Examples
22//!
23//! Read lines from stdin, process through all three layers, and print enriched entries:
24//!
25//! ```no_run
26//! use std::io::{self, BufRead};
27//! use freeswitch_log_parser::{LogStream, SessionTracker};
28//!
29//! let lines = io::stdin().lock().lines().map(|l| l.expect("read error"));
30//! let stream = LogStream::new(lines);
31//! let mut tracker = SessionTracker::new(stream);
32//!
33//! for enriched in tracker.by_ref() {
34//! let e = &enriched.entry;
35//! println!("{} [{}] {}", e.timestamp, e.message_kind, e.message);
36//! }
37//!
38//! let stats = tracker.stats();
39//! eprintln!("{} lines, {} unclassified",
40//! stats.lines_processed, stats.lines_unclassified);
41//! ```
42//!
43//! # Feature flags
44//!
45//! - **`cli`** — enables the `fslog` binary with clap, xz decompression, and regex filtering
46
47mod attached;
48mod chain;
49mod level;
50mod line;
51mod message;
52mod session;
53mod stream;
54
55pub use attached::{AttachedLines, AttachedLinesIter};
56pub use chain::{SegmentTracker, TrackedChain};
57pub use freeswitch_types::{
58 variables::SofiaVariable, CallDirection, CallState, ChannelState, ChannelVariable,
59};
60pub use level::{LogLevel, ParseLevelError};
61pub use line::{parse_line, LineKind, RawLine};
62pub use message::{classify_message, DtmfSource, MessageKind, SdpDirection, SipInviteDirection};
63pub use session::{EnrichedEntry, SessionSnapshot, SessionState, SessionTracker};
64pub use stream::{
65 Block, LogEntry, LogStream, ParseStats, UnclassifiedLine, UnclassifiedReason,
66 UnclassifiedTracking,
67};