1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
//! Logging macros for **Stakker**
//!
//! There are five severity-based logging macros ([`trace!`],
//! [`debug!`], [`info!`], [`warn!`] and [`error!`]) and one macro
//! designed for logging records that have a fixed tag and no freeform
//! text ([`audit!`]). Examples:
//!
//! ```ignore
//! error!([cx], addr: %src_addr, port, "Failed to connect: {}", err);
//! audit!([cx], TcpConnectFailure, addr: %src_addr, port);
//! ```
//!
//! The severity-based macros like [`error!`] all work the same way.
//! The `[cx]` comes first, followed by an optional target
//! specification (`target: "target-name"`), followed by optional
//! key-value pairs, followed by a format-string and its arguments.
//!
//! For [`audit!`], `[cx]` comes first, followed by a tag for the
//! record, followed by key-value pairs. The tag will normally be a
//! plain identifier, but it could also be a literal string or an
//! expression in parentheses which will be formatted to generate the
//! tag.
//!
//! `[cx]` can refer to either an actor context (`stakker::Cx`) or a
//! [`LogCx`]. Where the call is not being made from a context that
//! provides a `LogID`, `[core]` may be passed instead of `[cx]`,
//! which gives a `LogID` of zero. It's possible to log against a
//! specific actor or other `LogID` source by using `[source, core]`
//! instead of `[cx]`, which takes the `LogID` from that source using
//! a `source.access_log_id()` call. (In general the `[a]` form must
//! support `a.access_log_id()` and `a.access_core()`, and the `[a,b]`
//! form must support `a.access_log_id()` and `b.access_core()`.)
//!
//! For key-value pairs, the most general form is `"key": expr`, but
//! there are a number of shortcuts as follows:
//!
//! Shortcut | Equivalent
//! --- | ---
//! `size: file_size` | `"size": file_size`
//! `size` | `"size": size`
//! `packet.size` | `"size": packet.size`
//! `tcp.packet.size` | `"size": tcp.packet.size`
//! `%src_addr` | `"src_addr": format_args!("{}", src_addr)`
//! `src_addr: %addr` | `"src_addr": format_args!("{}", addr)`
//! `?stream` | `"stream": format_args!("{:?}", stream)`
//! `stream: ?input_stream` | `"stream": format_args!("{:?}", input_stream)`
//!
//! Conversion of values is determined by implementation of the
//! [`Visitable`] trait. All Rust primitives and standard collections
//! are supported by [`Visitable`]. For your own types, there are two
//! possibilities: either implement `Display` or `Debug` and use `%`
//! or `?`, or else implement [`Visitable`] directly. The advantage
//! of implementing [`Visitable`] is that in addition to mapping to a
//! primitive instead of a string, you could also output a structured
//! value such as an array or map to represent your type.
//!
//! # Logging output
//!
//! You can write you own code which accepts a `&dyn Fn(&mut dyn
//! LogVisitor)`, and calls it to receive all the logging data. There
//! are also provided types for JSON output ([`KvToJson`]) and simple
//! human-readable output ([`KvSingleLine`]).
//!
//! [`KvSingleLine`]: struct.KvSingleLine.html
//! [`KvToJson`]: struct.KvToJson.html
//! [`LogCx`]: struct.LogCx.html
//! [`Visitable`]: trait.Visitable.html
//! [`audit!`]: macro.audit.html
//! [`debug!`]: macro.debug.html
//! [`error!`]: macro.error.html
//! [`info!`]: macro.info.html
//! [`trace!`]: macro.trace.html
//! [`warn!`]: macro.warn.html
mod kvdisp;
mod kvjson;
mod logcx;
mod macros;
mod visit;
pub use kvdisp::KvSingleLine;
pub use kvjson::KvToJson;
pub use logcx::LogCx;
pub use visit::Visitable;
// Re-export so that macros can access stakker::LogLevel
#[doc(hidden)]
pub use stakker;
// TODO: Add loggers that log to 'log' crate, 'slog' crate,
// 'tracing-core', etc
#[cfg(test)]
mod test;