conduit_log_requests/
lib.rs

1#![cfg_attr(test, deny(warnings))]
2
3#[macro_use] extern crate log;
4
5extern crate time;
6extern crate conduit;
7extern crate conduit_middleware as middleware;
8
9use std::error::Error;
10
11use conduit::{Request, Response};
12use middleware::Middleware;
13
14pub struct LogRequests(pub log::LogLevel);
15
16struct LogStart(u64);
17
18impl Middleware for LogRequests {
19    fn before(&self, req: &mut Request) -> Result<(), Box<Error+Send>> {
20        req.mut_extensions().insert(LogStart(time::precise_time_ns()));
21        Ok(())
22    }
23
24    fn after(&self, req: &mut Request, resp: Result<Response, Box<Error+Send>>)
25             -> Result<Response, Box<Error+Send>> {
26        let LogStart(start) = *req.mut_extensions().find::<LogStart>().unwrap();
27
28        match resp {
29            Ok(ref resp) => self.log_message(req, start, resp.status.0, None),
30            Err(ref e) => {
31                let msg: &Error = &**e;
32                self.log_message(req, start, 500, Some(msg))
33            }
34        }
35        resp
36    }
37
38}
39
40impl LogRequests {
41    fn log_message(&self, req: &mut Request, start: u64, status: u32,
42                   msg: Option<&Error>) {
43        let LogRequests(level) = *self;
44        let level = if msg.is_some() {log::LogLevel::Error} else {level};
45        log!(level, "{} [{}] {:?} {} - {}ms {}{}",
46             req.remote_addr(),
47             time::now().rfc3339(),
48             req.method(),
49             req.path(),
50             (time::precise_time_ns() - start) / 1000000,
51             status,
52             match msg {
53                 None => String::new(),
54                 Some(s) => format!(": {} {}", s.description(), s),
55             })
56    }
57}
58
59#[cfg(all(test, foo))] // FIXME: needs a thread-local logger
60mod tests {
61    extern crate conduit_test as test;
62
63    use {LogRequests};
64
65    use conduit::{Request, Response, Handler, Method};
66    use log::{Log, LogRecord};
67    use log;
68    use middleware;
69    use std::error::Error;
70    use std::old_io::{ChanWriter, ChanReader};
71    use std::sync::Mutex;
72    use std::sync::mpsc::{channel, Sender};
73    use std::thread::Thread;
74    use std;
75
76    struct MyWriter(Mutex<ChanWriter>);
77
78    impl Log for MyWriter {
79        fn enabled(&self, _: log::LogLevel, _: &str) -> bool { true }
80        fn log(&self, record: &LogRecord) {
81            let MyWriter(ref inner) = *self;
82            (write!(inner.lock(), "{}", record.args)).unwrap();
83        }
84    }
85
86    #[test]
87    fn test_log() {
88        let (sender, receiver) = channel();
89        let mut reader = ChanReader::new(receiver);
90
91        let mut builder = middleware::MiddlewareBuilder::new(handler);
92        builder.add(LogRequests(log::LogLevel::Error));
93
94        task(builder, sender);
95
96        let result = reader.read_to_string().ok().expect("No response");
97        let parts = result.as_slice().split(' ').map(|s| s.to_string()).collect::<Vec<String>>();
98
99        assert_eq!(parts[0].as_slice(), "127.0.0.1");
100        // Failing on travis?! bug in libtime?!
101        // assert!(parts.get(1).as_slice().len() == "[2014-07-01T22:34:06-07:00]".len(),
102        //         "bad length for {}", parts.get(1));
103        assert_eq!(parts[2].as_slice(), "Get");
104        assert_eq!(parts[3].as_slice(), "/foo");
105    }
106
107    fn task<H: Handler + 'static + Send>(handler: H, sender: Sender<Vec<u8>>) {
108        Thread::spawn(move|| {
109            log::set_logger(Box::new(MyWriter(Mutex::new(ChanWriter::new(sender)))));
110            let mut request = test::MockRequest::new(Method::Get, "/foo");
111            let _ = handler.call(&mut request);
112        });
113    }
114
115    fn handler(_: &mut Request) -> Result<Response, Box<Error+Send>> {
116        Ok(Response {
117            status: (200, "OK"),
118            headers: std::collections::HashMap::new(),
119            body: Box::new(std::old_io::util::NullReader)
120        })
121    }
122}