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

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 Directives
  • 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

Derive Macros