Crates.io | rocket-slogger |
lib.rs | rocket-slogger |
version | 1.0.0 |
source | src |
created_at | 2021-11-29 02:31:04.634263 |
updated_at | 2024-06-06 04:31:28.249425 |
description | Middleware (fairing) for Rocket.rs 0.5 web servers to have integrated slog logging of request activity |
homepage | |
repository | https://github.com/iferc/rocket-slogger |
max_upload_size | |
id | 489071 |
size | 68,684 |
Structured logging middleware for the Rocket web framework.
When this fairing (middleware) is attached to an instance of Rocket, detailed log messages will automatically be generated for every request received and every response sent. The logger can also be injected into individual routes to generate additional custom logs at time of request.
On start-up, all configurations are shown as an initial log message. This both lists out the current configuration, and can serve as a sort of signal that the web server has been started/restarted. Next is a log message detailing the routes available, then one of error status catchers, then one of the host and port the server is listening on.
Rust toolchain required. See https://rustup.rs/ for installation instructions.
Add this crate to your Rust project:
rocket-slogger = "0.1.0"
Instantiate the fairing (middleware) with a slog
-compatible Logger
, then add it to your Rocket server:
// Wrap your `slog`-compatible Logger with the fairing
let fairing = Slogger::from_logger(logger);
// Load config from the usual places, such as Rocket.toml and the environment
let mut config = Config::from(Config::figment());
// The fairing does not turn off Rocket's pretty print logs by default
config.log_level = LogLevel::Off;
rocket::custom(config)
.attach(fairing)
...
terminal
feature is enabledThe helper function Slogger::new_terminal_logger()
will setup the logger to output plain text for each
log message that looks like the following:
Mar 15 04:32:00.815 INFO Request, method: GET, path: /, content-type: None, user-agent: vscode-restclient
Mar 15 04:32:00.815 INFO Response, size: 11, method: GET, path: /, route: always_greet, rank: -9, code: 200, reason: OK, content-type: text/plain; charset=utf-8
bunyan
feature is enabledThe helper function Slogger::new_bunyan_logger()
will setup the logger to output
bunyan-style JSON objects for each log message that looks like the following:
{"msg":"Request","v":0,"name":"My App","level":30,"time":"2023-03-15T04:29:35.865466064Z","hostname":"my-computer","pid":810142,"method":"GET","path":"/","content-type":null,"user-agent":"vscode-restclient"}
{"msg":"Response","v":0,"name":"My App","level":30,"time":"2023-03-15T04:29:35.867971878Z","hostname":"my-computer","pid":810142,"method":"GET","path":"/","route":"always_greet","rank":-9,"code":200,"reason":"OK","content-type":"text/plain; charset=utf-8","size":11}
Otherwise the Slogger
fairing can be built with any slog
-compatible
Logger
with Slogger::from_logger(logger)
.
There are minimal implementations of a Rocket web server with this logging middleware attached
in various configurations inside the ./examples
folder.
Keep in mind that some of the examples require features to be enabled.
For example, the command to run the bunyan-callbacks-features
is
cargo run --example bunyan-callbacks-features --features bunyan,callbacks
.
For each request received, a log message is generated containing the following information:
For each response sent, a log message is generated containing the following information:
transactions
feature is enabledFor each request received, in addition to the above, the following information will also be generated:
For each response sent, in addition to the above, the following information will also be generated:
local_time
feature is enabledThe exact date and time with time zone of when the middleware received the request is shown in the systems local time zone.
Note however that the time
field of when the log was made remains in the UTC time zone.
callbacks
feature is enabledFunctions can be attached to the fairing either on request or on response.
These callback functions get access to the slog::Logger
containing all of the above fields, as well as
a reference to the response and/or request. This enables the callback functions to return the same or
a new slog::Logger
instance with any new properties added before the log message is generated.
Slogger::new_bunyan_logger(env!("CARGO_PKG_NAME"))
.on_request(|logger, _request| {
// currently requires a pinned box to have an async context
Box::pin(async move {
// here any async function calls or server state can be fetched
// so that it can be added to the logger that will form the response log
let new_logger = logger.new(rocket_slogger::log_fields!(
"field:from-closure" => "some dynamic data derived at request time",
"in:request" => "more dynamic metrics",
));
// the new logger must be returned in an Option<Arc<Logger>>
Some(Arc::new(new_logger))
})
})
.on_response(|logger, _request, _response| {
// currently requires a pinned box to have an async context
Box::pin(async move {
// here any async function calls or server state can be fetched
// so that it can be added to the logger that will form the response log
let new_logger = logger.new(rocket_slogger::log_fields!(
"field:from-closure" => "some dynamic data derived at response time",
"in:response" => "more dynamic metrics",
));
// the new logger must be returned in an Option<Arc<Logger>>
Some(Arc::new(new_logger))
})
})
The Box::pin( async move { ... } )
structure allows for calling async
functions, such as executing a database query.
If you know of a cleaner or simpler way of providing async
callback functions, the suggestions are very much welcome!