1pub mod fairing;
2pub mod from_request;
3
4#[cfg(feature = "transactions")]
5pub mod transaction;
6
7pub use slog::{o, o as log_fields, Drain, Logger};
9pub use slog::{debug, trace};
11pub use slog::{error, info, warn};
13
14use rocket::{Request, Response};
15use std::sync::Arc;
16
17#[allow(unused_imports)]
18use std::future::Future;
19#[allow(unused_imports)]
20use std::pin::Pin;
21
22#[derive(Clone)]
23pub struct Slogger {
24 logger: Arc<Logger>,
25
26 #[cfg(feature = "callbacks")]
27 request_handlers: Vec<
28 Arc<
29 dyn for<'r> Fn(
30 Arc<Logger>,
31 &'r mut Request<'_>,
32 )
33 -> Pin<Box<dyn Future<Output = Option<Arc<Logger>>> + Send + 'r>>
34 + Send
35 + Sync
36 + 'static,
37 >,
38 >,
39
40 #[cfg(feature = "callbacks")]
41 response_handlers: Vec<
42 Arc<
43 dyn for<'r> Fn(
44 Arc<Logger>,
45 &'r Request<'_>,
46 &'r mut Response<'_>,
47 )
48 -> Pin<Box<dyn Future<Output = Option<Arc<Logger>>> + Send + 'r>>
49 + Send
50 + Sync
51 + 'static,
52 >,
53 >,
54}
55
56impl Slogger {
57 #[cfg(all(feature = "terminal", not(feature = "envlogger")))]
58 pub fn new_terminal_logger() -> Self {
59 use slog_term::{FullFormat, PlainSyncDecorator};
60
61 let plain_logger = PlainSyncDecorator::new(std::io::stdout());
62 let logger = Logger::root(FullFormat::new(plain_logger).build().fuse(), log_fields!());
63
64 Self::from_logger(logger)
65 }
66
67 #[cfg(all(feature = "terminal", feature = "envlogger"))]
68 pub fn new_terminal_logger() -> Self {
69 use slog_envlogger::EnvLogger;
70 use slog_term::{FullFormat, PlainSyncDecorator};
71
72 let plain_logger = PlainSyncDecorator::new(std::io::stdout());
73 let env_logger = EnvLogger::new(plain_logger);
74 let logger = Logger::root(FullFormat::new(env_logger).build().fuse(), log_fields!());
75
76 Self::from_logger(logger)
77 }
78
79 #[cfg(all(feature = "bunyan", not(feature = "envlogger")))]
80 pub fn new_bunyan_logger(name: &'static str) -> Self {
81 use std::sync::Mutex;
82
83 let bunyan_logger = slog_bunyan::with_name(name, std::io::stderr()).build();
84 let logger = Logger::root(Mutex::new(bunyan_logger).fuse(), log_fields!());
85
86 Self::from_logger(logger)
87 }
88
89 #[cfg(all(feature = "bunyan", feature = "envlogger"))]
90 pub fn new_bunyan_logger(name: &'static str) -> Self {
91 use slog_envlogger::EnvLogger;
92 use std::sync::Mutex;
93
94 let bunyan_logger = slog_bunyan::with_name(name, std::io::stderr()).build();
95 let env_logger = EnvLogger::new(bunyan_logger);
96 let logger = Logger::root(Mutex::new(env_logger).fuse(), log_fields!());
97
98 Self::from_logger(logger)
99 }
100
101 pub fn from_logger(logger: Logger) -> Self {
102 Self {
103 logger: Arc::new(logger),
104
105 #[cfg(feature = "callbacks")]
106 request_handlers: vec![],
107
108 #[cfg(feature = "callbacks")]
109 response_handlers: vec![],
110 }
111 }
112
113 pub fn get(&self) -> &Logger {
114 &self.logger
115 }
116
117 pub fn get_for_request(&self, request: &Request<'_>) -> Logger {
118 let content_type = request.content_type().map(|format| format.to_string());
119 let user_agent = request
120 .headers()
121 .get("user-agent")
122 .collect::<Vec<_>>()
123 .join("; ");
124
125 #[cfg(not(feature = "transactions"))]
126 let logger = self.logger.new(log_fields!(
127 "user-agent" => user_agent,
128 "content-type" => content_type,
129 ));
130
131 #[cfg(feature = "transactions")]
132 let logger = {
133 let transaction = transaction::RequestTransaction::new().attach_on(request);
134
135 self.logger.new(log_fields!(
136 "received" => transaction.received_as_string(),
137 "transaction" => transaction.id_as_string(),
138
139 "user-agent" => user_agent,
140 "content-type" => content_type,
141 ))
142 };
143
144 Self::new_logger_with_request_details(&logger, request)
145 }
146
147 pub fn get_for_response(&self, request: &Request<'_>, response: &Response<'_>) -> Logger {
148 let content_type = response.content_type().map(|format| format.to_string());
149 let status = response.status();
150
151 #[cfg(not(feature = "transactions"))]
152 let logger = self.logger.new(log_fields!(
153 "content-type" => content_type,
154 "reason" => status.reason().map(|reason| reason.to_string()),
155 "code" => status.code,
156 ));
157
158 #[cfg(feature = "transactions")]
159 let logger = {
160 let transaction = transaction::RequestTransaction::new().attach_on(request);
161
162 self.logger.new(log_fields!(
163 "elapsed_ns" => transaction.elapsed_ns(),
164 "received" => transaction.received_as_string(),
165 "transaction" => transaction.id_as_string(),
166 "content-type" => content_type,
167 "reason" => status.reason().map(|reason| reason.to_string()),
168 "code" => status.code,
169 ))
170 };
171
172 Self::new_logger_with_request_details(&logger, request)
173 }
174
175 fn new_logger_with_request_details(logger: &Logger, request: &Request<'_>) -> Logger {
176 if let Some(route) = request.route() {
177 logger.new(log_fields!(
178 "rank" => route.rank,
179 "route" => route.name.as_ref().map(|route| route.to_string()),
180 "path" => format!("{}", route.uri),
181 "method" => format!("{}", route.method),
182 "uri" => format!("{}", request.uri()),
183 ))
184 } else {
185 logger.new(log_fields!(
186 "method" => format!("{}", request.method()),
187 "uri" => format!("{}", request.uri()),
188 ))
189 }
190 }
191
192 #[cfg(feature = "callbacks")]
193 pub fn on_request(
194 mut self,
195 handler: impl for<'r> Fn(
196 Arc<Logger>,
197 &'r mut Request<'_>,
198 )
199 -> Pin<Box<dyn Future<Output = Option<Arc<Logger>>> + Send + 'r>>
200 + Send
201 + Sync
202 + 'static,
203 ) -> Self {
204 self.request_handlers.push(Arc::new(handler));
205 self
206 }
207
208 #[cfg(feature = "callbacks")]
209 pub fn on_response(
210 mut self,
211 handler: impl for<'r> Fn(
212 Arc<Logger>,
213 &'r Request<'_>,
214 &'r mut Response<'_>,
215 )
216 -> Pin<Box<dyn Future<Output = Option<Arc<Logger>>> + Send + 'r>>
217 + Send
218 + Sync
219 + 'static,
220 ) -> Self {
221 self.response_handlers.push(Arc::new(handler));
222 self
223 }
224}
225
226impl From<Logger> for Slogger {
227 fn from(logger: Logger) -> Self {
228 Slogger::from_logger(logger)
229 }
230}
231
232impl From<&Logger> for Slogger {
233 fn from(logger: &Logger) -> Self {
234 Slogger::from_logger(logger.clone())
235 }
236}
237
238impl std::ops::Deref for Slogger {
239 type Target = Logger;
240
241 fn deref(&self) -> &Logger {
242 &self.logger
243 }
244}