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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This crates provides an API for logging in libra.
//! # 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](https://developers.libra.org/docs/community/coding-guidelines#logging).
//!
//! The below examples do no type checking for structured log fields, and instead just serialize
//! whatever is given.
//! ```
//! use libra_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 libra_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 libra_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 libra_logger::{Level, Logger};
//!
//! Logger::builder().level(Level::Info).build();
//! ```

#![forbid(unsafe_code)]

pub mod prelude {
    pub use crate::{
        debug, error, event, info,
        libra_logger::FileWriter,
        sample,
        sample::{SampleRate, Sampling},
        security::SecurityEvent,
        trace, warn,
    };
}
pub mod json_log;

mod event;
mod filter;
mod kv;
mod libra_logger;
mod logger;
mod macros;
mod metadata;
pub mod sample;

mod security;
mod struct_log;

pub use crate::libra_logger::{
    LibraLogger, LibraLogger as Logger, LibraLoggerBuilder, Writer, CHANNEL_SIZE,
};
pub use event::Event;
pub use filter::{Filter, LevelFilter};
pub use metadata::{Level, Metadata};

pub use kv::{Key, KeyValue, Schema, Value, Visitor};
pub use libra_log_derive::Schema;
pub use security::SecurityEvent;

mod counters;