Traceon - trace on json
An easy to use log and tracing formatter with a flattened json output, it only takes one line of code for good defaults, with an easy to use builder for configuration.
The main purpose of this crate is to simplify the concept of tracing, which is just adding context to log messages for better debugging and observability, this documentation will cover everything you need, but the detailed tracing docs are here.
The only two crates you'll need in your Cargo.toml are:
[]
= "0.1"
= "0.1"
And you can write your first trace with:
Which will give the default output of (this is configurable):
Or you can use the pretty defaults:
pretty;
22:22:03 INFO a simple message
file: examples/builder.rs:19
module: builder
Or you can use the builder to create your own format:
use
builder
// Source code filename and line number `src/main.rs::10`
file,
// Target and module path `mybinary::mymodule::submodule`
module,
// Concatenated span name where the event occured `parentspan::childspan`
span,
time,
// Change the casing of all the key names `camelCase` to `snake_case`
case: Case,
pretty: bool,
concat: ,
level: LevelFormat,
// Put anything that implements write here to redirect output
.writer;
Log levels are converted to numbers by default:
trace: 10
debug: 20
info: 30
warn: 40
error: 50
env-filter is used by default at the info level to filter any messages out at the debug or trace level, to change the level you can set an environment variable e.g. RUST_LOG=warn which would filter out info level as well, all the options are detailed here
Examples
#[instrument] macro
You can use the tracing::instrument macro with both async and normal functions to capture the arguments used in each function call:
async
async
Instrument trait
If you need to add additional context to an async function, you can create a span and instrument it:
use Instrument;
async
async
The above package_name comes from the environment variable provided by cargo, which gets it from Cargo.toml at compile time and saves it for runtime:
[]
= "traceon"
IMPORTANT! if you're calling an async functions with .await, only use the above two methods to create a span, more details here
Nested spans
To combine the output from the two examples above we can enter a span with the arguments added to the trace:
use Instrument;
async
async
You can see above that the child span name add was concatenated to the parent span name math_functions with the characters ::, if you prefer the span just overrides the parent you can turn this functionality off:
or set it to something different:
The add function from above could be rewritten like this:
async
This will cause the span to exit at the end of the function when _span is dropped, just remember to be very careful not to put any .await points when an EnteredSpan like _span above is being held.
Turn off fields
This is an example of changing the default fields using the builder pattern, and takes the opportunity to introduce tracing::event!
use LevelFormat;
use Level;
Write to a file
If you wanted to write to log files instead of std, it's as simple adding the dependency to Cargo.toml:
[]
= "0.2.2"
And initializing it via the builder:
The writer accepts anything that implements the Write trait
Compose with other layers
You can also use the formatting layer with other tracing layers as you get more comfortable with the tracing ecosystem, for example to change the filter:
use ;
Change the case of keys
Often you'll be consuming different crates that implement their own traces and you need all their keys to match a certain format, this example also demonstrates how to use different instances of traceon for a given scope with on_thread(), which returns a guard so the subscriber is only running on the current thread, and will be turned off when the guard is dropped
examples/casing.rs
use Case;
use Level;
Pretty output
Json output
Pretty Printing Output
For pretty printing the output like the examples above, install jq and run commands like:
|
Performance
This crate uses the idea originated from: LukeMathWalker/tracing-bunyan-formatter of storing fields from visited spans in a HashMap instead of a BTreeMap which is more suited for flattening fields, and results in very similar performance to the json formatter in tracing-subcriber:
logging to a sink
units = nanosecond or billionth of a second
logging to stdout
units = microsecond or millionth of a second
Nested spans three levels deep with concatenated fields:
