1#![warn(missing_docs)]
83
84#[macro_use]
85extern crate slog;
86extern crate slog_stream;
87extern crate chrono;
88
89mod decorator;
90mod serializer;
91mod color_palette;
92mod style;
93
94use std::io;
95use std::sync::Mutex;
96
97use slog::Record;
98use slog::OwnedKeyValueList;
99use slog_stream::{Decorator, RecordDecorator};
100
101use decorator::HtmlDecorator;
102use serializer::Serializer;
103use style::StyleTable;
104pub use style::Style;
105pub use color_palette::ColorPalette;
106
107pub enum FormatMode {
109 Compact,
111 Full,
113}
114
115pub struct Format<D: Decorator> {
117 mode: FormatMode,
118 value_stack: Mutex<Vec<Vec<u8>>>,
119 decorator: D,
120 fn_timestamp: Box<TimestampFn>,
121}
122
123impl<D: Decorator> Format<D> {
124 pub fn new(mode: FormatMode, decorator: D, fn_timestamp: Box<TimestampFn>) -> Self {
126 Format {
127 mode: mode,
128 value_stack: Mutex::new(Vec::new()),
129 decorator: decorator,
130 fn_timestamp: fn_timestamp,
131 }
132 }
133
134 fn format_full(&self,
135 io: &mut io::Write,
136 record: &Record,
137 logger_values: &OwnedKeyValueList)
138 -> io::Result<()> {
139
140 let r_decorator = self.decorator.decorate(record);
141
142 try!(io.write_all(b"<pre style=\"margin-bottom:-0.5em\">"));
143
144 try!(r_decorator.fmt_timestamp(io, &*self.fn_timestamp));
145 try!(r_decorator.fmt_level(io, &|io| write!(io, " {} ", record.level().as_short_str())));
146 try!(r_decorator.fmt_msg(io, &|io| write!(io, "{}", record.msg())));
147
148 let mut serializer = Serializer::new(io, r_decorator);
149
150 for (k, v) in logger_values.iter() {
151 try!(serializer.print_comma());
152 try!(v.serialize(record, k, &mut serializer));
153 }
154
155 for &(k, v) in record.values().iter() {
156 try!(serializer.print_comma());
157 try!(v.serialize(record, k, &mut serializer));
158 }
159
160 let (mut io, _) = serializer.finish();
161
162 io.write_all(b"</pre>\n")
163 }
164
165 fn format_compact(&self,
166 io: &mut io::Write,
167 record: &Record,
168 logger_values: &OwnedKeyValueList)
169 -> io::Result<()> {
170
171 let mut value_stack = self.value_stack.lock().expect("failed to lock value_stack");
172 let mut record_value_stack = try!(self.record_value_stack(record, logger_values));
173 record_value_stack.reverse();
174 let indent = record_value_stack.len();
175
176 let mut changed = false;
177 for i in 0..record_value_stack.len() {
178 if value_stack.len() <= i || value_stack[i] != record_value_stack[i] {
179 changed = true;
180 }
181
182 if changed {
183 try!(io.write_all(b"<pre style=\"margin-bottom:-0.5em\">"));
184 try!(self.print_indent(io, i));
185 try!(io.write_all(&record_value_stack[i]));
186 try!(io.write_all(b"</pre>\n"));
187 }
188 }
189 if changed || value_stack.len() != record_value_stack.len() {
190 *value_stack = record_value_stack;
191 }
192
193 let r_decorator = self.decorator.decorate(record);
194
195 try!(io.write_all(b"<pre style=\"margin-bottom:-0.5em\">"));
196
197 try!(self.print_indent(io, indent));
198 try!(r_decorator.fmt_timestamp(io, &*self.fn_timestamp));
199 try!(r_decorator.fmt_level(io, &|io| write!(io, " {} ", record.level().as_short_str())));
200 try!(r_decorator.fmt_msg(io, &|io| write!(io, "{}", record.msg())));
201
202 let mut serializer = Serializer::new(io, r_decorator);
203
204 for &(k, v) in record.values().iter() {
205 try!(serializer.print_comma());
206 try!(v.serialize(record, k, &mut serializer));
207 }
208
209 let (mut io, _) = serializer.finish();
210
211 io.write_all(b"</pre>\n")
212 }
213
214 fn record_value_stack(&self,
216 record: &slog::Record,
217 logger_values_ref: &slog::OwnedKeyValueList)
218 -> io::Result<Vec<Vec<u8>>> {
219
220 let mut value_stack = if let Some(logger_values) = logger_values_ref.values() {
221 let r_decorator = self.decorator.decorate(record);
222 let buf: Vec<u8> = Vec::with_capacity(128);
223 let mut serializer = Serializer::new(buf, r_decorator);
224
225 let mut clean = true;
226 let mut logger_values = logger_values;
227 loop {
228 let (k, v) = logger_values.head();
229 if !clean {
230 try!(serializer.print_comma());
231 }
232 try!(v.serialize(record, k, &mut serializer));
233 clean = false;
234 logger_values = if let Some(v) = logger_values.tail() {
235 v
236 } else {
237 break;
238 }
239 }
240 let (buf, _) = serializer.finish();
241 vec![buf]
242 } else {
243 Vec::new()
244 };
245
246 if let Some(ref parent) = *logger_values_ref.parent() {
247 let mut value = try!(self.record_value_stack(record, parent));
248 value_stack.append(&mut value);
249 }
250
251 Ok(value_stack)
252 }
253
254 fn print_indent(&self, io: &mut io::Write, indent: usize) -> io::Result<()> {
255 for _ in 0..indent {
256 try!(write!(io, " "));
257 }
258 Ok(())
259 }
260}
261
262impl<D: Decorator> slog_stream::Format for Format<D> {
263 fn format(&self,
264 io: &mut io::Write,
265 record: &Record,
266 logger_values: &OwnedKeyValueList)
267 -> io::Result<()> {
268 match self.mode {
269 FormatMode::Compact => self.format_compact(io, record, logger_values),
270 FormatMode::Full => self.format_full(io, record, logger_values),
271 }
272 }
273}
274
275pub type TimestampFn = Fn(&mut io::Write) -> io::Result<()> + Send + Sync;
277
278const TIMESTAMP_FORMAT: &'static str = "%b %d %H:%M:%S%.3f";
279
280pub fn timestamp_local(io: &mut io::Write) -> io::Result<()> {
284 write!(io, "{}", chrono::Local::now().format(TIMESTAMP_FORMAT))
285}
286
287pub fn timestamp_utc(io: &mut io::Write) -> io::Result<()> {
291 write!(io, "{}", chrono::UTC::now().format(TIMESTAMP_FORMAT))
292}
293
294pub struct FormatBuilder {
296 mode: FormatMode,
297 color_palette: ColorPalette,
298 style: StyleTable,
299 fn_timestamp: Box<TimestampFn>,
300}
301
302impl FormatBuilder {
303 fn new() -> Self {
305 FormatBuilder {
306 mode: FormatMode::Full,
307 color_palette: ColorPalette::default(),
308 style: StyleTable::default(),
309 fn_timestamp: Box::new(timestamp_local),
310 }
311 }
312
313 pub fn full(mut self) -> Self {
315 self.mode = FormatMode::Full;
316 self
317 }
318
319 pub fn compact(mut self) -> Self {
321 self.mode = FormatMode::Compact;
322 self
323 }
324
325 pub fn color_palette(mut self, color_palette: ColorPalette) -> Self {
327 self.color_palette = color_palette;
328 self
329 }
330
331 pub fn level_style(mut self, style: Style) -> Self {
333 self.style.level = style;
334 self
335 }
336
337 pub fn timestamp_style(mut self, style: Style) -> Self {
339 self.style.timestamp = style;
340 self
341 }
342
343 pub fn message_style(mut self, style: Style) -> Self {
345 self.style.message = style;
346 self
347 }
348
349 pub fn key_style(mut self, style: Style) -> Self {
351 self.style.key = style;
352 self
353 }
354
355 pub fn value_style(mut self, style: Style) -> Self {
357 self.style.value = style;
358 self
359 }
360
361 pub fn separator_style(mut self, style: Style) -> Self {
363 self.style.separator = style;
364 self
365 }
366
367 pub fn use_utc_timestamp(mut self) -> Self {
369 self.fn_timestamp = Box::new(timestamp_utc);
370 self
371 }
372
373 pub fn use_local_timestamp(mut self) -> Self {
375 self.fn_timestamp = Box::new(timestamp_local);
376 self
377 }
378
379 pub fn use_custom_timestamp<F>(mut self, f: F) -> Self
381 where F: Fn(&mut io::Write) -> io::Result<()> + 'static + Send + Sync
382 {
383 self.fn_timestamp = Box::new(f);
384 self
385 }
386
387 pub fn build(self) -> Format<HtmlDecorator> {
389 Format {
390 mode: self.mode,
391 value_stack: Mutex::new(Vec::new()),
392 decorator: HtmlDecorator::new(self.color_palette, self.style),
393 fn_timestamp: self.fn_timestamp,
394 }
395 }
396}
397
398impl Default for FormatBuilder {
399 fn default() -> Self {
400 Self::new()
401 }
402}
403
404pub fn new() -> FormatBuilder {
406 FormatBuilder::new()
407}
408
409pub fn default() -> Format<HtmlDecorator> {
411 FormatBuilder::new().build()
412}