Skip to content

Commit ed7ea86

Browse files
authored
Merge pull request #662 from jbr/only-log-once
Only run the log middleware once per request
2 parents 0ff17a3 + 530f931 commit ed7ea86

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

src/log/middleware.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use crate::{Middleware, Next, Request};
33

44
/// Log all incoming requests and responses.
55
///
6-
/// This middleware is enabled by default in Tide.
6+
/// This middleware is enabled by default in Tide. In the case of
7+
/// nested applications, this middleware will only run once for each
8+
/// request.
79
///
810
/// # Examples
911
///
@@ -16,6 +18,8 @@ pub struct LogMiddleware {
1618
_priv: (),
1719
}
1820

21+
struct LogMiddlewareHasBeenRun;
22+
1923
impl LogMiddleware {
2024
/// Create a new instance of `LogMiddleware`.
2125
#[must_use]
@@ -26,17 +30,22 @@ impl LogMiddleware {
2630
/// Log a request and a response.
2731
async fn log<'a, State: Clone + Send + Sync + 'static>(
2832
&'a self,
29-
ctx: Request<State>,
33+
mut req: Request<State>,
3034
next: Next<'a, State>,
3135
) -> crate::Result {
32-
let path = ctx.url().path().to_owned();
33-
let method = ctx.method().to_string();
36+
if req.ext::<LogMiddlewareHasBeenRun>().is_some() {
37+
return Ok(next.run(req).await);
38+
}
39+
req.set_ext(LogMiddlewareHasBeenRun);
40+
41+
let path = req.url().path().to_owned();
42+
let method = req.method().to_string();
3443
log::info!("<-- Request received", {
3544
method: method,
3645
path: path,
3746
});
3847
let start = std::time::Instant::now();
39-
let response = next.run(ctx).await;
48+
let response = next.run(req).await;
4049
let status = response.status();
4150
if status.is_server_error() {
4251
if let Some(error) = response.error() {

tests/log.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@ use async_std::prelude::*;
22
use std::time::Duration;
33

44
mod test_utils;
5+
use test_utils::ServerTestingExt;
56

67
#[async_std::test]
7-
async fn start_server_log() {
8+
async fn log_tests() {
89
let mut logger = logtest::start();
10+
test_server_listen(&mut logger).await;
11+
test_only_log_once(&mut logger).await;
12+
}
913

14+
async fn test_server_listen(logger: &mut logtest::Logger) {
1015
let port = test_utils::find_port().await;
1116
let app = tide::new();
1217
let res = app
@@ -23,3 +28,31 @@ async fn start_server_log() {
2328
format!("Server listening on http://[::1]:{}", port)
2429
);
2530
}
31+
32+
async fn test_only_log_once(logger: &mut logtest::Logger) {
33+
let mut app = tide::new();
34+
app.at("/").nest({
35+
let mut app = tide::new();
36+
app.at("/").get(|_| async { Ok("nested") });
37+
app
38+
});
39+
app.get("/").await;
40+
41+
let entries: Vec<_> = logger.collect();
42+
43+
assert_eq!(
44+
1,
45+
entries
46+
.iter()
47+
.filter(|entry| entry.args() == "<-- Request received")
48+
.count()
49+
);
50+
51+
assert_eq!(
52+
1,
53+
entries
54+
.iter()
55+
.filter(|entry| entry.args() == "--> Response sent")
56+
.count()
57+
);
58+
}

0 commit comments

Comments
 (0)