Crate diem_logger
source ·Expand description
This crates provides an API for logging in diem.
Instrumenting with Logs
Basic instrumenting with Logs
A set of logging macros (info!
, error!
, warn!
, debug!
, and trace!
) is provided for
emitting logs at different levels. All of these macros support the addition of providing
structured data along with a formatted text message. For guidelines on which level to use,
see the coding guidelines.
The below examples do no type checking for structured log fields, and instead just serialize whatever is given.
use diem_logger::info;
let world = "world!";
// Formatted message, similar to `printf!`
info!("hello {}", world);
// => '{"level":"info", "message": "hello world!"}'
// Structured data can be logged using the format 'key = value'
// where value implements Serialize. This can be used for indexing and search later.
let value1 = 5;
info!(key1 = value1);
// => '{"level":"info", "data": {"key1": 5}}'
// You can even set multiple key/value pairs and a format message together
let value2 = false;
info!(key1 = value1, key2 = value2, "hello {}", world);
// => '{"level":"info", "data": {"key1": 5, "key2": false}, "message": "hello world!"}'
// Structured data can also use `Display` or `Debug` outputs instead.
// Using the sigil `?` for debug and `%` for display.
let value1 = 5;
info!(debug_key = ?value1, display_key = %value1);
// => '{"level":"info", "data": {"display_key": 5, "debug_key": 5}}'
Note
Arguments used in a formatted message are not captured and included as structured data.
Everything after the format string literal e.g. "hello {}"
are only used in the format string.
Preferred instrumenting with Logs (Typed Schemas)
The Schema
trait can be used to implement typed logging schemas. This can either be
implemented by hand or derived using the Schema
derive proc-macro, implementing the Schema
trait for the struct as well as providing setters for all fields.
use diem_logger::{info, Schema};
#[derive(Schema)]
struct LogSchema<'a> {
// Log using this type's Serialize impl
a: usize,
// Log using this type's Debug impl
#[schema(debug)]
b: Option<Vec<bool>>,
// Log using this type's Display impl
#[schema(display)]
c: Option<&'a str>,
}
let log = LogSchema { a: 5, b: None, c: None };
// Automatic setters are named based on the field names, and handle `Option`
// None fields will be ignored
info!(log.c("radiant"));
// => '{"level":"info", "data": { "a": 5, "c": "radiant"}}'
#[derive(Schema)]
struct OtherSchema<'a> {
val: Option<&'a str>
}
let log = LogSchema { a: 5, b: None, c: None };
let other = OtherSchema { val: None };
// Schemas can be combined
info!(
other.val("awesome"), // First schema
log // Second schema has fields added to it all
);
// => '{"level":"info", "data": { "a": 5, "val":"awesome"}}'
let log = LogSchema { a: 5, b: None, c: None };
let other = OtherSchema { val: None };
// Schemas can be combined with one off fields and messages like above
info!(
other.val("awesome"), // First schema
log, // Second schema has fields added to it all
new_field = "new", // Basic structured fields
"Message: {}", // Format messages
"Some message" // Format message fields (not added to indexed fields)
);
// => {"level":"info", "message": "Message: Some message",
// "data": { "a": 5, "val":"awesome", "new_field": "new"}}'
Sampling logs
Sometimes logging a large amount of data is expensive. In order to log information only part
of the time, we’ve added a sample!
macro that’s configurable on how often we want to execute some code.
SampleRate
determines how often the sampled statement will occur.
use diem_logger::{info, sample, sample::{SampleRate, Sampling}};
use std::time::Duration;
// Sampled based on frequency of events, log only every 2 logs
sample!(SampleRate::Frequency(2), info!("Long log"));
// Sampled based on time passed, log at most once a minute
sample!(SampleRate::Duration(Duration::from_secs(60)), info!("Long log"));
Configuration
In order for logs to be captured and emitted a Logger needs to be instantiated. This can be
done by using the Logger
type:
use diem_logger::{Level, Logger};
Logger::builder().level(Level::Info).build();
Modules
- Periodic sampling for logs, metrics, and other use cases through a simple macro
Macros
- Log at the
debug
level - Log at the
error
level - Writes event to event stream Example: event!(“committed”, block=“b”);
- Log at the
info
level - Log at the given level, it’s recommended to use a specific level macro instead
- Samples a given function at a
SampleRate
, useful for periodically emitting logs or metrics on high throughput pieces of code. - Log at the
trace
level - Log at the
warn
level
Structs
- A builder for a
DiemLogger
, configures what, where, and how to write logs. - An individual structured logging event from a log line. Includes the
- A logging filter to determine which logs to keep or remove based on
Directive
s - The key part of a logging key value pair e.g.
info!(key = value)
- The logging key value pair e.g.
info!(key = value)
- Associated metadata with every log to identify what kind of log and where it came from
Enums
- Logging levels, used for stratifying logs, and disabling less important ones for performance reasons
- A definition of the most verbose
Level
allowed, or completely off. - The value part of a logging key value pair e.g.
info!(key = value)
Constants
- Default size of log write channel, if the channel is full, logs will be dropped
Traits
- A schema of key-value pairs.
- A visitor for the key-value pairs in a
Schema
. - An trait encapsulating the operations required for writing logs.
Functions
- Flush the global
Logger