Struct actix_contrib_logger::middleware::Logger
source · pub struct Logger(_);
Expand description
Middleware for logging request and response summaries to the terminal.
Actually it’s a copy & paste from the official Logger
middleware (original source code),
but it allows to choose the logging level depending on the HTTP status code responded
(see Logger::custom_level()
and Logger::custom_error_resp_level()
),
and by default server errors are logged with ERROR
level.
Moreover, error in response log are also configurable, and by default logged as ERROR
in server side failures.
This middleware uses the log
crate to output information. Enable log
’s output for the
“http_logger” scope using env_logger
or similar crate.
Default Format
The default
Logger uses the following format:
%a "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T
Example Output:
127.0.0.1:54278 "GET /test HTTP/1.1" 404 20 "-" "HTTPie/2.2.0" 0.001074
Examples
use actix_web::App;
use actix_contrib_logger::middleware::Logger;
use env_logger::Env;
// access logs are printed with the INFO level so ensure it is enabled by default
env_logger::init_from_env(Env::new().default_filter_or("info"));
let app = App::new()
// .wrap(Logger::default())
.wrap(Logger::new("%a %{User-Agent}i"));
Format
Variable | Description |
---|---|
%% | The percent sign |
%a | Peer IP address (or IP address of reverse proxy if used) |
%t | Time when the request started processing (in RFC 3339 format) |
%r | First line of request (Example: GET /test HTTP/1.1 ) |
%s | Response status code |
%b | Size of response in bytes, including HTTP headers |
%T | Time taken to serve the request, in seconds to 6 decimal places |
%D | Time taken to serve the request, in milliseconds |
%U | Request URL |
%{r}a | “Real IP” remote address * |
%{FOO}i | request.headers["FOO"] |
%{FOO}o | response.headers["FOO"] |
%{FOO}e | env_var["FOO"] |
%{FOO}xi | Custom request replacement labelled “FOO” |
%{FOO}xo | Custom response replacement labelled “FOO” |
Security
* “Real IP” remote address is calculated using
ConnectionInfo::realip_remote_addr()
If you use this value, ensure that all requests come from trusted hosts. Otherwise, it is trivial for the remote client to falsify their source IP address.
Implementations§
source§impl Logger
impl Logger
sourcepub fn exclude<T: Into<String>>(self, path: T) -> Self
pub fn exclude<T: Into<String>>(self, path: T) -> Self
Ignore and do not log access info for specified path.
sourcepub fn exclude_regex<T: Into<String>>(self, path: T) -> Self
pub fn exclude_regex<T: Into<String>>(self, path: T) -> Self
Ignore and do not log access info for paths that match regex.
sourcepub fn log_target(self, target: impl Into<Cow<'static, str>>) -> Self
pub fn log_target(self, target: impl Into<Cow<'static, str>>) -> Self
Sets the logging target to target
.
By default, the log target is http_logger
.
Examples
Using .log_target("http")
would have this effect on request logs:
- [2015-10-21T07:28:00Z INFO http_logger] 127.0.0.1 "GET / HTTP/1.1" 200 88 "-" "dmc/1.0" 0.001985
+ [2015-10-21T07:28:00Z INFO http] 127.0.0.1 "GET / HTTP/1.1" 200 88 "-" "dmc/1.0" 0.001985
^^^^
sourcepub fn custom_request_replace(
self,
label: &str,
f: impl Fn(&ServiceRequest) -> String + 'static
) -> Self
pub fn custom_request_replace( self, label: &str, f: impl Fn(&ServiceRequest) -> String + 'static ) -> Self
Register a function that receives a ServiceRequest and returns a String for use in the
log line. The label passed as the first argument should match a replacement substring in
the logger format like %{label}xi
.
It is convention to print “-” to indicate no output instead of an empty string.
Examples
Logger::new("example %{JWT_ID}xi")
.custom_request_replace("JWT_ID", |req| parse_jwt_id(req.headers().get("Authorization")));
sourcepub fn custom_response_replace(
self,
label: &str,
f: impl Fn(&ServiceResponse) -> String + 'static
) -> Self
pub fn custom_response_replace( self, label: &str, f: impl Fn(&ServiceResponse) -> String + 'static ) -> Self
Register a function that receives a ServiceResponse
and returns a string for use in the
log line.
The label passed as the first argument should match a replacement substring in
the logger format like %{label}xo
.
It is convention to print “-” to indicate no output instead of an empty string.
The replacement function does not have access to the response body.
Examples
fn log_if_error(res: &ServiceResponse) -> String {
if res.status().as_u16() >= 400 {
"ERROR".to_string()
} else {
"-".to_string()
}
}
Logger::new("example %{ERROR_STATUS}xo")
.custom_response_replace("ERROR_STATUS", |res| log_if_error(res) );
sourcepub fn custom_level(self, f: fn(_: StatusCode) -> Level) -> Self
pub fn custom_level(self, f: fn(_: StatusCode) -> Level) -> Self
Register a function that receives a StatusCode
to define what Level
to use to log an HTTP event.
By default all HTTP requests are logged with INFO
severity except the ones ended
with server errors (600 > status code >= 500
) that are logged with ERROR
severity.
With this function the level used is customized.
Examples
In the following example ERROR
level is used for server errors, WARN
for
HTTP 404 responses (Not Found), and for the rest INFO
level:
use actix_contrib_logger::middleware::Logger;
use http::StatusCode;
use log::Level;
let logger = Logger::default()
.custom_level(|status| {
if status.is_server_error() {
Level::Error
} else if status == StatusCode::NOT_FOUND {
Level::Warn
} else {
Level::Info
}
});
Requests logs will look like:
[2023-08-13T07:28:00Z INFO http_logger] 127.0.0.1 "GET / HTTP/1.1" 200 802 "-" "Mozilla/5.0 ..." 0.001985
[2023-08-13T07:29:10Z ERROR http_logger] 127.0.0.1 "POST /users HTTP/1.1" 500 86 "-" "curl/7.68.0" 0.002023
[2023-08-13T07:29:10Z WARN http_logger] 127.0.0.1 "PUT /users HTTP/1.1" 404 55 "-" "HTTPie/3.2.1" 0.002023
sourcepub fn custom_error_resp_level(self, f: fn(_: StatusCode) -> Level) -> Self
pub fn custom_error_resp_level(self, f: fn(_: StatusCode) -> Level) -> Self
Register a function that receives a StatusCode
to define what Level
to use to log an error in the response.
By default all error in responses are logged with DEBUG
severity except the ones ended
with server errors (600 > status code >= 500
) that are logged with ERROR
severity.
With this function the level used is customized.
Examples
In the following example ERROR
level is used for server errors, INFO
level
instead of DEBUG
for the rest:
use actix_contrib_logger::middleware::Logger;
use http::StatusCode;
use log::Level;
let logger = Logger::default()
.custom_error_resp_level(|status| {
if status.is_server_error() {
Level::Error
} else {
Level::Info
}
});
Requests logs with errors will look like (the error in response logs are the first and the third lines):
[2023-08-13T21:51:02Z INFO http_logger] Error in "400 Bad Request" response: Validation("Tenant already exists.")
[2023-08-13T21:51:02Z INFO http_logger] 127.0.0.1 "POST /tenants HTTP/1.1" 400 56 "-" "HTTPie/3.2.1" 0.002368
[2023-08-13T20:59:53Z ERROR http_logger] Error in "500 Internal Server Error" response: DB(PoolTimedOut)
[2023-08-13T07:59:53Z ERROR http_logger] 127.0.0.1 "POST /users HTTP/1.1" 500 86 "-" "curl/7.68.0" 0.002023