mirror of https://github.com/fafhrd91/actix-web
allow for passing xi tag into logger format to choose where closure result is inserted in log line
This commit is contained in:
parent
c65f59d9b8
commit
d69112aec7
|
@ -93,7 +93,6 @@ struct Inner {
|
||||||
format: Format,
|
format: Format,
|
||||||
exclude: HashSet<String>,
|
exclude: HashSet<String>,
|
||||||
exclude_regex: RegexSet,
|
exclude_regex: RegexSet,
|
||||||
closure: Vec<fn(req: &ServiceRequest) -> String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Logger {
|
impl Logger {
|
||||||
|
@ -103,7 +102,6 @@ impl Logger {
|
||||||
format: Format::new(format),
|
format: Format::new(format),
|
||||||
exclude: HashSet::new(),
|
exclude: HashSet::new(),
|
||||||
exclude_regex: RegexSet::empty(),
|
exclude_regex: RegexSet::empty(),
|
||||||
closure: vec![],
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,12 +125,21 @@ impl Logger {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a closure to be run on the request output of the logger.
|
/// Register a closure to be run on the request output of the logger.
|
||||||
/// Note: output from closure will be present at end of logger output. Multiple closure will be ran in the order they are registed.
|
/// Label passed into this function will be used to match output of given closure to label found in log format line with format %{label}xi.
|
||||||
pub fn register_request_closure(
|
pub fn custom_request_replace(
|
||||||
mut self,
|
mut self,
|
||||||
|
label: &'static str,
|
||||||
closure: fn(req: &ServiceRequest) -> String,
|
closure: fn(req: &ServiceRequest) -> String,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Rc::get_mut(&mut self.0).unwrap().closure.push(closure);
|
let inner = Rc::get_mut(&mut self.0).unwrap();
|
||||||
|
|
||||||
|
for tf in inner.format.0.iter_mut() {
|
||||||
|
if let FormatText::CustomLog(inner_label, _inner_closure) = tf {
|
||||||
|
if inner_label == label {
|
||||||
|
*tf = FormatText::CustomLog(label.to_string(), Some(closure))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,7 +155,6 @@ impl Default for Logger {
|
||||||
format: Format::default(),
|
format: Format::default(),
|
||||||
exclude: HashSet::new(),
|
exclude: HashSet::new(),
|
||||||
exclude_regex: RegexSet::empty(),
|
exclude_regex: RegexSet::empty(),
|
||||||
closure: vec![],
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,9 +216,6 @@ where
|
||||||
for unit in &mut format.0 {
|
for unit in &mut format.0 {
|
||||||
unit.render_request(now, &req);
|
unit.render_request(now, &req);
|
||||||
}
|
}
|
||||||
for closure in self.inner.closure.clone() {
|
|
||||||
format.0.push(FormatText::render_closure(closure, &req));
|
|
||||||
}
|
|
||||||
LoggerResponse {
|
LoggerResponse {
|
||||||
fut: self.service.call(req),
|
fut: self.service.call(req),
|
||||||
format: Some(format),
|
format: Some(format),
|
||||||
|
@ -343,7 +346,8 @@ impl Format {
|
||||||
/// Returns `None` if the format string syntax is incorrect.
|
/// Returns `None` if the format string syntax is incorrect.
|
||||||
pub fn new(s: &str) -> Format {
|
pub fn new(s: &str) -> Format {
|
||||||
log::trace!("Access log format: {}", s);
|
log::trace!("Access log format: {}", s);
|
||||||
let fmt = Regex::new(r"%(\{([A-Za-z0-9\-_]+)\}([aioe])|[atPrUsbTD]?)").unwrap();
|
let fmt =
|
||||||
|
Regex::new(r"%(\{([A-Za-z0-9\-_]+)\}([aioe]|xi)|[atPrUsbTD]?)").unwrap();
|
||||||
|
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
|
@ -371,6 +375,7 @@ impl Format {
|
||||||
HeaderName::try_from(key.as_str()).unwrap(),
|
HeaderName::try_from(key.as_str()).unwrap(),
|
||||||
),
|
),
|
||||||
"e" => FormatText::EnvironHeader(key.as_str().to_owned()),
|
"e" => FormatText::EnvironHeader(key.as_str().to_owned()),
|
||||||
|
"xi" => FormatText::CustomLog(key.as_str().to_owned(), None),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -400,7 +405,7 @@ impl Format {
|
||||||
/// A string of text to be logged. This is either one of the data
|
/// A string of text to be logged. This is either one of the data
|
||||||
/// fields supported by the `Logger`, or a custom `String`.
|
/// fields supported by the `Logger`, or a custom `String`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub enum FormatText {
|
pub enum FormatText {
|
||||||
Str(String),
|
Str(String),
|
||||||
Percent,
|
Percent,
|
||||||
|
@ -416,6 +421,7 @@ pub enum FormatText {
|
||||||
RequestHeader(HeaderName),
|
RequestHeader(HeaderName),
|
||||||
ResponseHeader(HeaderName),
|
ResponseHeader(HeaderName),
|
||||||
EnvironHeader(String),
|
EnvironHeader(String),
|
||||||
|
CustomLog(String, Option<fn(req: &ServiceRequest) -> String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatText {
|
impl FormatText {
|
||||||
|
@ -471,13 +477,6 @@ impl FormatText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_closure(
|
|
||||||
closure: fn(req: &ServiceRequest) -> String,
|
|
||||||
req: &ServiceRequest,
|
|
||||||
) -> FormatText {
|
|
||||||
FormatText::Str(closure(req))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_request(&mut self, now: OffsetDateTime, req: &ServiceRequest) {
|
fn render_request(&mut self, now: OffsetDateTime, req: &ServiceRequest) {
|
||||||
match *self {
|
match *self {
|
||||||
FormatText::RequestLine => {
|
FormatText::RequestLine => {
|
||||||
|
@ -531,6 +530,14 @@ impl FormatText {
|
||||||
};
|
};
|
||||||
*self = s;
|
*self = s;
|
||||||
}
|
}
|
||||||
|
FormatText::CustomLog(_, closure) => {
|
||||||
|
let s = if let Some(closure) = closure {
|
||||||
|
FormatText::Str(closure(req))
|
||||||
|
} else {
|
||||||
|
FormatText::Str("-".to_string())
|
||||||
|
};
|
||||||
|
*self = s;
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -724,7 +731,37 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_closure_logger_format() {
|
async fn test_custom_closure_log() {
|
||||||
|
let mut logger = Logger::new("%{CUSTOM}xi")
|
||||||
|
.custom_request_replace("CUSTOM", |_req: &ServiceRequest| -> String {
|
||||||
|
String::from("custom_log")
|
||||||
|
});
|
||||||
|
let mut format = Rc::get_mut(&mut logger.0).unwrap().format.0.clone();
|
||||||
|
|
||||||
|
let req = TestRequest::default().to_srv_request();
|
||||||
|
|
||||||
|
let now = OffsetDateTime::now_utc();
|
||||||
|
for unit in &mut format {
|
||||||
|
unit.render_request(now, &req);
|
||||||
|
}
|
||||||
|
|
||||||
|
let resp = HttpResponse::build(StatusCode::OK).force_close().finish();
|
||||||
|
for unit in &mut format {
|
||||||
|
unit.render_response(&resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
let render = |fmt: &mut Formatter<'_>| {
|
||||||
|
for unit in &format {
|
||||||
|
unit.render(fmt, 1024, now)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
let s = format!("{}", FormatDisplay(&render));
|
||||||
|
assert!(s.contains(&now.format("custom_log")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_closure_logger() {
|
||||||
let srv = |req: ServiceRequest| {
|
let srv = |req: ServiceRequest| {
|
||||||
ok(req.into_response(
|
ok(req.into_response(
|
||||||
HttpResponse::build(StatusCode::OK)
|
HttpResponse::build(StatusCode::OK)
|
||||||
|
@ -732,8 +769,8 @@ mod tests {
|
||||||
.finish(),
|
.finish(),
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test")
|
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D %{CUSTOM}xi")
|
||||||
.register_request_closure(|_req: &ServiceRequest| -> String {
|
.custom_request_replace("CUSTOM", |_req: &ServiceRequest| -> String {
|
||||||
String::from("custom_log")
|
String::from("custom_log")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue