1336d762aSopenharmony_ci//! Formatting for log records. 2336d762aSopenharmony_ci//! 3336d762aSopenharmony_ci//! This module contains a [`Formatter`] that can be used to format log records 4336d762aSopenharmony_ci//! into without needing temporary allocations. Usually you won't need to worry 5336d762aSopenharmony_ci//! about the contents of this module and can use the `Formatter` like an ordinary 6336d762aSopenharmony_ci//! [`Write`]. 7336d762aSopenharmony_ci//! 8336d762aSopenharmony_ci//! # Formatting log records 9336d762aSopenharmony_ci//! 10336d762aSopenharmony_ci//! The format used to print log records can be customised using the [`Builder::format`] 11336d762aSopenharmony_ci//! method. 12336d762aSopenharmony_ci//! Custom formats can apply different color and weight to printed values using 13336d762aSopenharmony_ci//! [`Style`] builders. 14336d762aSopenharmony_ci//! 15336d762aSopenharmony_ci//! ``` 16336d762aSopenharmony_ci//! use std::io::Write; 17336d762aSopenharmony_ci//! 18336d762aSopenharmony_ci//! let mut builder = env_logger::Builder::new(); 19336d762aSopenharmony_ci//! 20336d762aSopenharmony_ci//! builder.format(|buf, record| { 21336d762aSopenharmony_ci//! writeln!(buf, "{}: {}", 22336d762aSopenharmony_ci//! record.level(), 23336d762aSopenharmony_ci//! record.args()) 24336d762aSopenharmony_ci//! }); 25336d762aSopenharmony_ci//! ``` 26336d762aSopenharmony_ci//! 27336d762aSopenharmony_ci//! [`Formatter`]: struct.Formatter.html 28336d762aSopenharmony_ci//! [`Style`]: struct.Style.html 29336d762aSopenharmony_ci//! [`Builder::format`]: ../struct.Builder.html#method.format 30336d762aSopenharmony_ci//! [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html 31336d762aSopenharmony_ci 32336d762aSopenharmony_ciuse std::cell::RefCell; 33336d762aSopenharmony_ciuse std::fmt::Display; 34336d762aSopenharmony_ciuse std::io::prelude::*; 35336d762aSopenharmony_ciuse std::rc::Rc; 36336d762aSopenharmony_ciuse std::{fmt, io, mem}; 37336d762aSopenharmony_ci 38336d762aSopenharmony_ciuse log::Record; 39336d762aSopenharmony_ci 40336d762aSopenharmony_cimod humantime; 41336d762aSopenharmony_cipub(crate) mod writer; 42336d762aSopenharmony_ci 43336d762aSopenharmony_cipub use self::humantime::glob::*; 44336d762aSopenharmony_cipub use self::writer::glob::*; 45336d762aSopenharmony_ci 46336d762aSopenharmony_ciuse self::writer::{Buffer, Writer}; 47336d762aSopenharmony_ci 48336d762aSopenharmony_cipub(crate) mod glob { 49336d762aSopenharmony_ci pub use super::{Target, TimestampPrecision, WriteStyle}; 50336d762aSopenharmony_ci} 51336d762aSopenharmony_ci 52336d762aSopenharmony_ci/// Formatting precision of timestamps. 53336d762aSopenharmony_ci/// 54336d762aSopenharmony_ci/// Seconds give precision of full seconds, milliseconds give thousands of a 55336d762aSopenharmony_ci/// second (3 decimal digits), microseconds are millionth of a second (6 decimal 56336d762aSopenharmony_ci/// digits) and nanoseconds are billionth of a second (9 decimal digits). 57336d762aSopenharmony_ci#[derive(Copy, Clone, Debug)] 58336d762aSopenharmony_cipub enum TimestampPrecision { 59336d762aSopenharmony_ci /// Full second precision (0 decimal digits) 60336d762aSopenharmony_ci Seconds, 61336d762aSopenharmony_ci /// Millisecond precision (3 decimal digits) 62336d762aSopenharmony_ci Millis, 63336d762aSopenharmony_ci /// Microsecond precision (6 decimal digits) 64336d762aSopenharmony_ci Micros, 65336d762aSopenharmony_ci /// Nanosecond precision (9 decimal digits) 66336d762aSopenharmony_ci Nanos, 67336d762aSopenharmony_ci} 68336d762aSopenharmony_ci 69336d762aSopenharmony_ci/// The default timestamp precision is seconds. 70336d762aSopenharmony_ciimpl Default for TimestampPrecision { 71336d762aSopenharmony_ci fn default() -> Self { 72336d762aSopenharmony_ci TimestampPrecision::Seconds 73336d762aSopenharmony_ci } 74336d762aSopenharmony_ci} 75336d762aSopenharmony_ci 76336d762aSopenharmony_ci/// A formatter to write logs into. 77336d762aSopenharmony_ci/// 78336d762aSopenharmony_ci/// `Formatter` implements the standard [`Write`] trait for writing log records. 79336d762aSopenharmony_ci/// It also supports terminal colors, through the [`style`] method. 80336d762aSopenharmony_ci/// 81336d762aSopenharmony_ci/// # Examples 82336d762aSopenharmony_ci/// 83336d762aSopenharmony_ci/// Use the [`writeln`] macro to format a log record. 84336d762aSopenharmony_ci/// An instance of a `Formatter` is passed to an `env_logger` format as `buf`: 85336d762aSopenharmony_ci/// 86336d762aSopenharmony_ci/// ``` 87336d762aSopenharmony_ci/// use std::io::Write; 88336d762aSopenharmony_ci/// 89336d762aSopenharmony_ci/// let mut builder = env_logger::Builder::new(); 90336d762aSopenharmony_ci/// 91336d762aSopenharmony_ci/// builder.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args())); 92336d762aSopenharmony_ci/// ``` 93336d762aSopenharmony_ci/// 94336d762aSopenharmony_ci/// [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html 95336d762aSopenharmony_ci/// [`writeln`]: https://doc.rust-lang.org/stable/std/macro.writeln.html 96336d762aSopenharmony_ci/// [`style`]: #method.style 97336d762aSopenharmony_cipub struct Formatter { 98336d762aSopenharmony_ci buf: Rc<RefCell<Buffer>>, 99336d762aSopenharmony_ci write_style: WriteStyle, 100336d762aSopenharmony_ci} 101336d762aSopenharmony_ci 102336d762aSopenharmony_ciimpl Formatter { 103336d762aSopenharmony_ci pub(crate) fn new(writer: &Writer) -> Self { 104336d762aSopenharmony_ci Formatter { 105336d762aSopenharmony_ci buf: Rc::new(RefCell::new(writer.buffer())), 106336d762aSopenharmony_ci write_style: writer.write_style(), 107336d762aSopenharmony_ci } 108336d762aSopenharmony_ci } 109336d762aSopenharmony_ci 110336d762aSopenharmony_ci pub(crate) fn write_style(&self) -> WriteStyle { 111336d762aSopenharmony_ci self.write_style 112336d762aSopenharmony_ci } 113336d762aSopenharmony_ci 114336d762aSopenharmony_ci pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> { 115336d762aSopenharmony_ci writer.print(&self.buf.borrow()) 116336d762aSopenharmony_ci } 117336d762aSopenharmony_ci 118336d762aSopenharmony_ci pub(crate) fn clear(&mut self) { 119336d762aSopenharmony_ci self.buf.borrow_mut().clear() 120336d762aSopenharmony_ci } 121336d762aSopenharmony_ci} 122336d762aSopenharmony_ci 123336d762aSopenharmony_ciimpl Write for Formatter { 124336d762aSopenharmony_ci fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 125336d762aSopenharmony_ci self.buf.borrow_mut().write(buf) 126336d762aSopenharmony_ci } 127336d762aSopenharmony_ci 128336d762aSopenharmony_ci fn flush(&mut self) -> io::Result<()> { 129336d762aSopenharmony_ci self.buf.borrow_mut().flush() 130336d762aSopenharmony_ci } 131336d762aSopenharmony_ci} 132336d762aSopenharmony_ci 133336d762aSopenharmony_ciimpl fmt::Debug for Formatter { 134336d762aSopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 135336d762aSopenharmony_ci f.debug_struct("Formatter").finish() 136336d762aSopenharmony_ci } 137336d762aSopenharmony_ci} 138336d762aSopenharmony_ci 139336d762aSopenharmony_cipub(crate) type FormatFn = Box<dyn Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>; 140336d762aSopenharmony_ci 141336d762aSopenharmony_cipub(crate) struct Builder { 142336d762aSopenharmony_ci pub format_timestamp: Option<TimestampPrecision>, 143336d762aSopenharmony_ci pub format_module_path: bool, 144336d762aSopenharmony_ci pub format_target: bool, 145336d762aSopenharmony_ci pub format_level: bool, 146336d762aSopenharmony_ci pub format_indent: Option<usize>, 147336d762aSopenharmony_ci pub custom_format: Option<FormatFn>, 148336d762aSopenharmony_ci pub format_suffix: &'static str, 149336d762aSopenharmony_ci built: bool, 150336d762aSopenharmony_ci} 151336d762aSopenharmony_ci 152336d762aSopenharmony_ciimpl Default for Builder { 153336d762aSopenharmony_ci fn default() -> Self { 154336d762aSopenharmony_ci Builder { 155336d762aSopenharmony_ci format_timestamp: Some(Default::default()), 156336d762aSopenharmony_ci format_module_path: false, 157336d762aSopenharmony_ci format_target: true, 158336d762aSopenharmony_ci format_level: true, 159336d762aSopenharmony_ci format_indent: Some(4), 160336d762aSopenharmony_ci custom_format: None, 161336d762aSopenharmony_ci format_suffix: "\n", 162336d762aSopenharmony_ci built: false, 163336d762aSopenharmony_ci } 164336d762aSopenharmony_ci } 165336d762aSopenharmony_ci} 166336d762aSopenharmony_ci 167336d762aSopenharmony_ciimpl Builder { 168336d762aSopenharmony_ci /// Convert the format into a callable function. 169336d762aSopenharmony_ci /// 170336d762aSopenharmony_ci /// If the `custom_format` is `Some`, then any `default_format` switches are ignored. 171336d762aSopenharmony_ci /// If the `custom_format` is `None`, then a default format is returned. 172336d762aSopenharmony_ci /// Any `default_format` switches set to `false` won't be written by the format. 173336d762aSopenharmony_ci pub fn build(&mut self) -> FormatFn { 174336d762aSopenharmony_ci assert!(!self.built, "attempt to re-use consumed builder"); 175336d762aSopenharmony_ci 176336d762aSopenharmony_ci let built = mem::replace( 177336d762aSopenharmony_ci self, 178336d762aSopenharmony_ci Builder { 179336d762aSopenharmony_ci built: true, 180336d762aSopenharmony_ci ..Default::default() 181336d762aSopenharmony_ci }, 182336d762aSopenharmony_ci ); 183336d762aSopenharmony_ci 184336d762aSopenharmony_ci if let Some(fmt) = built.custom_format { 185336d762aSopenharmony_ci fmt 186336d762aSopenharmony_ci } else { 187336d762aSopenharmony_ci Box::new(move |buf, record| { 188336d762aSopenharmony_ci let fmt = DefaultFormat { 189336d762aSopenharmony_ci timestamp: built.format_timestamp, 190336d762aSopenharmony_ci module_path: built.format_module_path, 191336d762aSopenharmony_ci target: built.format_target, 192336d762aSopenharmony_ci level: built.format_level, 193336d762aSopenharmony_ci written_header_value: false, 194336d762aSopenharmony_ci indent: built.format_indent, 195336d762aSopenharmony_ci suffix: built.format_suffix, 196336d762aSopenharmony_ci buf, 197336d762aSopenharmony_ci }; 198336d762aSopenharmony_ci 199336d762aSopenharmony_ci fmt.write(record) 200336d762aSopenharmony_ci }) 201336d762aSopenharmony_ci } 202336d762aSopenharmony_ci } 203336d762aSopenharmony_ci} 204336d762aSopenharmony_ci 205336d762aSopenharmony_ci#[cfg(feature = "termcolor")] 206336d762aSopenharmony_citype SubtleStyle = StyledValue<'static, &'static str>; 207336d762aSopenharmony_ci#[cfg(not(feature = "termcolor"))] 208336d762aSopenharmony_citype SubtleStyle = &'static str; 209336d762aSopenharmony_ci 210336d762aSopenharmony_ci/// The default format. 211336d762aSopenharmony_ci/// 212336d762aSopenharmony_ci/// This format needs to work with any combination of crate features. 213336d762aSopenharmony_cistruct DefaultFormat<'a> { 214336d762aSopenharmony_ci timestamp: Option<TimestampPrecision>, 215336d762aSopenharmony_ci module_path: bool, 216336d762aSopenharmony_ci target: bool, 217336d762aSopenharmony_ci level: bool, 218336d762aSopenharmony_ci written_header_value: bool, 219336d762aSopenharmony_ci indent: Option<usize>, 220336d762aSopenharmony_ci buf: &'a mut Formatter, 221336d762aSopenharmony_ci suffix: &'a str, 222336d762aSopenharmony_ci} 223336d762aSopenharmony_ci 224336d762aSopenharmony_ciimpl<'a> DefaultFormat<'a> { 225336d762aSopenharmony_ci fn write(mut self, record: &Record) -> io::Result<()> { 226336d762aSopenharmony_ci self.write_timestamp()?; 227336d762aSopenharmony_ci self.write_level(record)?; 228336d762aSopenharmony_ci self.write_module_path(record)?; 229336d762aSopenharmony_ci self.write_target(record)?; 230336d762aSopenharmony_ci self.finish_header()?; 231336d762aSopenharmony_ci 232336d762aSopenharmony_ci self.write_args(record) 233336d762aSopenharmony_ci } 234336d762aSopenharmony_ci 235336d762aSopenharmony_ci fn subtle_style(&self, text: &'static str) -> SubtleStyle { 236336d762aSopenharmony_ci #[cfg(feature = "termcolor")] 237336d762aSopenharmony_ci { 238336d762aSopenharmony_ci self.buf 239336d762aSopenharmony_ci .style() 240336d762aSopenharmony_ci .set_color(Color::Black) 241336d762aSopenharmony_ci .set_intense(true) 242336d762aSopenharmony_ci .clone() 243336d762aSopenharmony_ci .into_value(text) 244336d762aSopenharmony_ci } 245336d762aSopenharmony_ci #[cfg(not(feature = "termcolor"))] 246336d762aSopenharmony_ci { 247336d762aSopenharmony_ci text 248336d762aSopenharmony_ci } 249336d762aSopenharmony_ci } 250336d762aSopenharmony_ci 251336d762aSopenharmony_ci fn write_header_value<T>(&mut self, value: T) -> io::Result<()> 252336d762aSopenharmony_ci where 253336d762aSopenharmony_ci T: Display, 254336d762aSopenharmony_ci { 255336d762aSopenharmony_ci if !self.written_header_value { 256336d762aSopenharmony_ci self.written_header_value = true; 257336d762aSopenharmony_ci 258336d762aSopenharmony_ci let open_brace = self.subtle_style("["); 259336d762aSopenharmony_ci write!(self.buf, "{}{}", open_brace, value) 260336d762aSopenharmony_ci } else { 261336d762aSopenharmony_ci write!(self.buf, " {}", value) 262336d762aSopenharmony_ci } 263336d762aSopenharmony_ci } 264336d762aSopenharmony_ci 265336d762aSopenharmony_ci fn write_level(&mut self, record: &Record) -> io::Result<()> { 266336d762aSopenharmony_ci if !self.level { 267336d762aSopenharmony_ci return Ok(()); 268336d762aSopenharmony_ci } 269336d762aSopenharmony_ci 270336d762aSopenharmony_ci let level = { 271336d762aSopenharmony_ci #[cfg(feature = "termcolor")] 272336d762aSopenharmony_ci { 273336d762aSopenharmony_ci self.buf.default_styled_level(record.level()) 274336d762aSopenharmony_ci } 275336d762aSopenharmony_ci #[cfg(not(feature = "termcolor"))] 276336d762aSopenharmony_ci { 277336d762aSopenharmony_ci record.level() 278336d762aSopenharmony_ci } 279336d762aSopenharmony_ci }; 280336d762aSopenharmony_ci 281336d762aSopenharmony_ci self.write_header_value(format_args!("{:<5}", level)) 282336d762aSopenharmony_ci } 283336d762aSopenharmony_ci 284336d762aSopenharmony_ci fn write_timestamp(&mut self) -> io::Result<()> { 285336d762aSopenharmony_ci #[cfg(feature = "humantime")] 286336d762aSopenharmony_ci { 287336d762aSopenharmony_ci use self::TimestampPrecision::*; 288336d762aSopenharmony_ci let ts = match self.timestamp { 289336d762aSopenharmony_ci None => return Ok(()), 290336d762aSopenharmony_ci Some(Seconds) => self.buf.timestamp_seconds(), 291336d762aSopenharmony_ci Some(Millis) => self.buf.timestamp_millis(), 292336d762aSopenharmony_ci Some(Micros) => self.buf.timestamp_micros(), 293336d762aSopenharmony_ci Some(Nanos) => self.buf.timestamp_nanos(), 294336d762aSopenharmony_ci }; 295336d762aSopenharmony_ci 296336d762aSopenharmony_ci self.write_header_value(ts) 297336d762aSopenharmony_ci } 298336d762aSopenharmony_ci #[cfg(not(feature = "humantime"))] 299336d762aSopenharmony_ci { 300336d762aSopenharmony_ci // Trick the compiler to think we have used self.timestamp 301336d762aSopenharmony_ci // Workaround for "field is never used: `timestamp`" compiler nag. 302336d762aSopenharmony_ci let _ = self.timestamp; 303336d762aSopenharmony_ci Ok(()) 304336d762aSopenharmony_ci } 305336d762aSopenharmony_ci } 306336d762aSopenharmony_ci 307336d762aSopenharmony_ci fn write_module_path(&mut self, record: &Record) -> io::Result<()> { 308336d762aSopenharmony_ci if !self.module_path { 309336d762aSopenharmony_ci return Ok(()); 310336d762aSopenharmony_ci } 311336d762aSopenharmony_ci 312336d762aSopenharmony_ci if let Some(module_path) = record.module_path() { 313336d762aSopenharmony_ci self.write_header_value(module_path) 314336d762aSopenharmony_ci } else { 315336d762aSopenharmony_ci Ok(()) 316336d762aSopenharmony_ci } 317336d762aSopenharmony_ci } 318336d762aSopenharmony_ci 319336d762aSopenharmony_ci fn write_target(&mut self, record: &Record) -> io::Result<()> { 320336d762aSopenharmony_ci if !self.target { 321336d762aSopenharmony_ci return Ok(()); 322336d762aSopenharmony_ci } 323336d762aSopenharmony_ci 324336d762aSopenharmony_ci match record.target() { 325336d762aSopenharmony_ci "" => Ok(()), 326336d762aSopenharmony_ci target => self.write_header_value(target), 327336d762aSopenharmony_ci } 328336d762aSopenharmony_ci } 329336d762aSopenharmony_ci 330336d762aSopenharmony_ci fn finish_header(&mut self) -> io::Result<()> { 331336d762aSopenharmony_ci if self.written_header_value { 332336d762aSopenharmony_ci let close_brace = self.subtle_style("]"); 333336d762aSopenharmony_ci write!(self.buf, "{} ", close_brace) 334336d762aSopenharmony_ci } else { 335336d762aSopenharmony_ci Ok(()) 336336d762aSopenharmony_ci } 337336d762aSopenharmony_ci } 338336d762aSopenharmony_ci 339336d762aSopenharmony_ci fn write_args(&mut self, record: &Record) -> io::Result<()> { 340336d762aSopenharmony_ci match self.indent { 341336d762aSopenharmony_ci // Fast path for no indentation 342336d762aSopenharmony_ci None => write!(self.buf, "{}{}", record.args(), self.suffix), 343336d762aSopenharmony_ci 344336d762aSopenharmony_ci Some(indent_count) => { 345336d762aSopenharmony_ci // Create a wrapper around the buffer only if we have to actually indent the message 346336d762aSopenharmony_ci 347336d762aSopenharmony_ci struct IndentWrapper<'a, 'b: 'a> { 348336d762aSopenharmony_ci fmt: &'a mut DefaultFormat<'b>, 349336d762aSopenharmony_ci indent_count: usize, 350336d762aSopenharmony_ci } 351336d762aSopenharmony_ci 352336d762aSopenharmony_ci impl<'a, 'b> Write for IndentWrapper<'a, 'b> { 353336d762aSopenharmony_ci fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 354336d762aSopenharmony_ci let mut first = true; 355336d762aSopenharmony_ci for chunk in buf.split(|&x| x == b'\n') { 356336d762aSopenharmony_ci if !first { 357336d762aSopenharmony_ci write!( 358336d762aSopenharmony_ci self.fmt.buf, 359336d762aSopenharmony_ci "{}{:width$}", 360336d762aSopenharmony_ci self.fmt.suffix, 361336d762aSopenharmony_ci "", 362336d762aSopenharmony_ci width = self.indent_count 363336d762aSopenharmony_ci )?; 364336d762aSopenharmony_ci } 365336d762aSopenharmony_ci self.fmt.buf.write_all(chunk)?; 366336d762aSopenharmony_ci first = false; 367336d762aSopenharmony_ci } 368336d762aSopenharmony_ci 369336d762aSopenharmony_ci Ok(buf.len()) 370336d762aSopenharmony_ci } 371336d762aSopenharmony_ci 372336d762aSopenharmony_ci fn flush(&mut self) -> io::Result<()> { 373336d762aSopenharmony_ci self.fmt.buf.flush() 374336d762aSopenharmony_ci } 375336d762aSopenharmony_ci } 376336d762aSopenharmony_ci 377336d762aSopenharmony_ci // The explicit scope here is just to make older versions of Rust happy 378336d762aSopenharmony_ci { 379336d762aSopenharmony_ci let mut wrapper = IndentWrapper { 380336d762aSopenharmony_ci fmt: self, 381336d762aSopenharmony_ci indent_count, 382336d762aSopenharmony_ci }; 383336d762aSopenharmony_ci write!(wrapper, "{}", record.args())?; 384336d762aSopenharmony_ci } 385336d762aSopenharmony_ci 386336d762aSopenharmony_ci write!(self.buf, "{}", self.suffix)?; 387336d762aSopenharmony_ci 388336d762aSopenharmony_ci Ok(()) 389336d762aSopenharmony_ci } 390336d762aSopenharmony_ci } 391336d762aSopenharmony_ci } 392336d762aSopenharmony_ci} 393336d762aSopenharmony_ci 394336d762aSopenharmony_ci#[cfg(test)] 395336d762aSopenharmony_cimod tests { 396336d762aSopenharmony_ci use super::*; 397336d762aSopenharmony_ci 398336d762aSopenharmony_ci use log::{Level, Record}; 399336d762aSopenharmony_ci 400336d762aSopenharmony_ci fn write_record(record: Record, fmt: DefaultFormat) -> String { 401336d762aSopenharmony_ci let buf = fmt.buf.buf.clone(); 402336d762aSopenharmony_ci 403336d762aSopenharmony_ci fmt.write(&record).expect("failed to write record"); 404336d762aSopenharmony_ci 405336d762aSopenharmony_ci let buf = buf.borrow(); 406336d762aSopenharmony_ci String::from_utf8(buf.bytes().to_vec()).expect("failed to read record") 407336d762aSopenharmony_ci } 408336d762aSopenharmony_ci 409336d762aSopenharmony_ci fn write_target(target: &str, fmt: DefaultFormat) -> String { 410336d762aSopenharmony_ci write_record( 411336d762aSopenharmony_ci Record::builder() 412336d762aSopenharmony_ci .args(format_args!("log\nmessage")) 413336d762aSopenharmony_ci .level(Level::Info) 414336d762aSopenharmony_ci .file(Some("test.rs")) 415336d762aSopenharmony_ci .line(Some(144)) 416336d762aSopenharmony_ci .module_path(Some("test::path")) 417336d762aSopenharmony_ci .target(target) 418336d762aSopenharmony_ci .build(), 419336d762aSopenharmony_ci fmt, 420336d762aSopenharmony_ci ) 421336d762aSopenharmony_ci } 422336d762aSopenharmony_ci 423336d762aSopenharmony_ci fn write(fmt: DefaultFormat) -> String { 424336d762aSopenharmony_ci write_target("", fmt) 425336d762aSopenharmony_ci } 426336d762aSopenharmony_ci 427336d762aSopenharmony_ci #[test] 428336d762aSopenharmony_ci fn format_with_header() { 429336d762aSopenharmony_ci let writer = writer::Builder::new() 430336d762aSopenharmony_ci .write_style(WriteStyle::Never) 431336d762aSopenharmony_ci .build(); 432336d762aSopenharmony_ci 433336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 434336d762aSopenharmony_ci 435336d762aSopenharmony_ci let written = write(DefaultFormat { 436336d762aSopenharmony_ci timestamp: None, 437336d762aSopenharmony_ci module_path: true, 438336d762aSopenharmony_ci target: false, 439336d762aSopenharmony_ci level: true, 440336d762aSopenharmony_ci written_header_value: false, 441336d762aSopenharmony_ci indent: None, 442336d762aSopenharmony_ci suffix: "\n", 443336d762aSopenharmony_ci buf: &mut f, 444336d762aSopenharmony_ci }); 445336d762aSopenharmony_ci 446336d762aSopenharmony_ci assert_eq!("[INFO test::path] log\nmessage\n", written); 447336d762aSopenharmony_ci } 448336d762aSopenharmony_ci 449336d762aSopenharmony_ci #[test] 450336d762aSopenharmony_ci fn format_no_header() { 451336d762aSopenharmony_ci let writer = writer::Builder::new() 452336d762aSopenharmony_ci .write_style(WriteStyle::Never) 453336d762aSopenharmony_ci .build(); 454336d762aSopenharmony_ci 455336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 456336d762aSopenharmony_ci 457336d762aSopenharmony_ci let written = write(DefaultFormat { 458336d762aSopenharmony_ci timestamp: None, 459336d762aSopenharmony_ci module_path: false, 460336d762aSopenharmony_ci target: false, 461336d762aSopenharmony_ci level: false, 462336d762aSopenharmony_ci written_header_value: false, 463336d762aSopenharmony_ci indent: None, 464336d762aSopenharmony_ci suffix: "\n", 465336d762aSopenharmony_ci buf: &mut f, 466336d762aSopenharmony_ci }); 467336d762aSopenharmony_ci 468336d762aSopenharmony_ci assert_eq!("log\nmessage\n", written); 469336d762aSopenharmony_ci } 470336d762aSopenharmony_ci 471336d762aSopenharmony_ci #[test] 472336d762aSopenharmony_ci fn format_indent_spaces() { 473336d762aSopenharmony_ci let writer = writer::Builder::new() 474336d762aSopenharmony_ci .write_style(WriteStyle::Never) 475336d762aSopenharmony_ci .build(); 476336d762aSopenharmony_ci 477336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 478336d762aSopenharmony_ci 479336d762aSopenharmony_ci let written = write(DefaultFormat { 480336d762aSopenharmony_ci timestamp: None, 481336d762aSopenharmony_ci module_path: true, 482336d762aSopenharmony_ci target: false, 483336d762aSopenharmony_ci level: true, 484336d762aSopenharmony_ci written_header_value: false, 485336d762aSopenharmony_ci indent: Some(4), 486336d762aSopenharmony_ci suffix: "\n", 487336d762aSopenharmony_ci buf: &mut f, 488336d762aSopenharmony_ci }); 489336d762aSopenharmony_ci 490336d762aSopenharmony_ci assert_eq!("[INFO test::path] log\n message\n", written); 491336d762aSopenharmony_ci } 492336d762aSopenharmony_ci 493336d762aSopenharmony_ci #[test] 494336d762aSopenharmony_ci fn format_indent_zero_spaces() { 495336d762aSopenharmony_ci let writer = writer::Builder::new() 496336d762aSopenharmony_ci .write_style(WriteStyle::Never) 497336d762aSopenharmony_ci .build(); 498336d762aSopenharmony_ci 499336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 500336d762aSopenharmony_ci 501336d762aSopenharmony_ci let written = write(DefaultFormat { 502336d762aSopenharmony_ci timestamp: None, 503336d762aSopenharmony_ci module_path: true, 504336d762aSopenharmony_ci target: false, 505336d762aSopenharmony_ci level: true, 506336d762aSopenharmony_ci written_header_value: false, 507336d762aSopenharmony_ci indent: Some(0), 508336d762aSopenharmony_ci suffix: "\n", 509336d762aSopenharmony_ci buf: &mut f, 510336d762aSopenharmony_ci }); 511336d762aSopenharmony_ci 512336d762aSopenharmony_ci assert_eq!("[INFO test::path] log\nmessage\n", written); 513336d762aSopenharmony_ci } 514336d762aSopenharmony_ci 515336d762aSopenharmony_ci #[test] 516336d762aSopenharmony_ci fn format_indent_spaces_no_header() { 517336d762aSopenharmony_ci let writer = writer::Builder::new() 518336d762aSopenharmony_ci .write_style(WriteStyle::Never) 519336d762aSopenharmony_ci .build(); 520336d762aSopenharmony_ci 521336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 522336d762aSopenharmony_ci 523336d762aSopenharmony_ci let written = write(DefaultFormat { 524336d762aSopenharmony_ci timestamp: None, 525336d762aSopenharmony_ci module_path: false, 526336d762aSopenharmony_ci target: false, 527336d762aSopenharmony_ci level: false, 528336d762aSopenharmony_ci written_header_value: false, 529336d762aSopenharmony_ci indent: Some(4), 530336d762aSopenharmony_ci suffix: "\n", 531336d762aSopenharmony_ci buf: &mut f, 532336d762aSopenharmony_ci }); 533336d762aSopenharmony_ci 534336d762aSopenharmony_ci assert_eq!("log\n message\n", written); 535336d762aSopenharmony_ci } 536336d762aSopenharmony_ci 537336d762aSopenharmony_ci #[test] 538336d762aSopenharmony_ci fn format_suffix() { 539336d762aSopenharmony_ci let writer = writer::Builder::new() 540336d762aSopenharmony_ci .write_style(WriteStyle::Never) 541336d762aSopenharmony_ci .build(); 542336d762aSopenharmony_ci 543336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 544336d762aSopenharmony_ci 545336d762aSopenharmony_ci let written = write(DefaultFormat { 546336d762aSopenharmony_ci timestamp: None, 547336d762aSopenharmony_ci module_path: false, 548336d762aSopenharmony_ci target: false, 549336d762aSopenharmony_ci level: false, 550336d762aSopenharmony_ci written_header_value: false, 551336d762aSopenharmony_ci indent: None, 552336d762aSopenharmony_ci suffix: "\n\n", 553336d762aSopenharmony_ci buf: &mut f, 554336d762aSopenharmony_ci }); 555336d762aSopenharmony_ci 556336d762aSopenharmony_ci assert_eq!("log\nmessage\n\n", written); 557336d762aSopenharmony_ci } 558336d762aSopenharmony_ci 559336d762aSopenharmony_ci #[test] 560336d762aSopenharmony_ci fn format_suffix_with_indent() { 561336d762aSopenharmony_ci let writer = writer::Builder::new() 562336d762aSopenharmony_ci .write_style(WriteStyle::Never) 563336d762aSopenharmony_ci .build(); 564336d762aSopenharmony_ci 565336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 566336d762aSopenharmony_ci 567336d762aSopenharmony_ci let written = write(DefaultFormat { 568336d762aSopenharmony_ci timestamp: None, 569336d762aSopenharmony_ci module_path: false, 570336d762aSopenharmony_ci target: false, 571336d762aSopenharmony_ci level: false, 572336d762aSopenharmony_ci written_header_value: false, 573336d762aSopenharmony_ci indent: Some(4), 574336d762aSopenharmony_ci suffix: "\n\n", 575336d762aSopenharmony_ci buf: &mut f, 576336d762aSopenharmony_ci }); 577336d762aSopenharmony_ci 578336d762aSopenharmony_ci assert_eq!("log\n\n message\n\n", written); 579336d762aSopenharmony_ci } 580336d762aSopenharmony_ci 581336d762aSopenharmony_ci #[test] 582336d762aSopenharmony_ci fn format_target() { 583336d762aSopenharmony_ci let writer = writer::Builder::new() 584336d762aSopenharmony_ci .write_style(WriteStyle::Never) 585336d762aSopenharmony_ci .build(); 586336d762aSopenharmony_ci 587336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 588336d762aSopenharmony_ci 589336d762aSopenharmony_ci let written = write_target( 590336d762aSopenharmony_ci "target", 591336d762aSopenharmony_ci DefaultFormat { 592336d762aSopenharmony_ci timestamp: None, 593336d762aSopenharmony_ci module_path: true, 594336d762aSopenharmony_ci target: true, 595336d762aSopenharmony_ci level: true, 596336d762aSopenharmony_ci written_header_value: false, 597336d762aSopenharmony_ci indent: None, 598336d762aSopenharmony_ci suffix: "\n", 599336d762aSopenharmony_ci buf: &mut f, 600336d762aSopenharmony_ci }, 601336d762aSopenharmony_ci ); 602336d762aSopenharmony_ci 603336d762aSopenharmony_ci assert_eq!("[INFO test::path target] log\nmessage\n", written); 604336d762aSopenharmony_ci } 605336d762aSopenharmony_ci 606336d762aSopenharmony_ci #[test] 607336d762aSopenharmony_ci fn format_empty_target() { 608336d762aSopenharmony_ci let writer = writer::Builder::new() 609336d762aSopenharmony_ci .write_style(WriteStyle::Never) 610336d762aSopenharmony_ci .build(); 611336d762aSopenharmony_ci 612336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 613336d762aSopenharmony_ci 614336d762aSopenharmony_ci let written = write(DefaultFormat { 615336d762aSopenharmony_ci timestamp: None, 616336d762aSopenharmony_ci module_path: true, 617336d762aSopenharmony_ci target: true, 618336d762aSopenharmony_ci level: true, 619336d762aSopenharmony_ci written_header_value: false, 620336d762aSopenharmony_ci indent: None, 621336d762aSopenharmony_ci suffix: "\n", 622336d762aSopenharmony_ci buf: &mut f, 623336d762aSopenharmony_ci }); 624336d762aSopenharmony_ci 625336d762aSopenharmony_ci assert_eq!("[INFO test::path] log\nmessage\n", written); 626336d762aSopenharmony_ci } 627336d762aSopenharmony_ci 628336d762aSopenharmony_ci #[test] 629336d762aSopenharmony_ci fn format_no_target() { 630336d762aSopenharmony_ci let writer = writer::Builder::new() 631336d762aSopenharmony_ci .write_style(WriteStyle::Never) 632336d762aSopenharmony_ci .build(); 633336d762aSopenharmony_ci 634336d762aSopenharmony_ci let mut f = Formatter::new(&writer); 635336d762aSopenharmony_ci 636336d762aSopenharmony_ci let written = write_target( 637336d762aSopenharmony_ci "target", 638336d762aSopenharmony_ci DefaultFormat { 639336d762aSopenharmony_ci timestamp: None, 640336d762aSopenharmony_ci module_path: true, 641336d762aSopenharmony_ci target: false, 642336d762aSopenharmony_ci level: true, 643336d762aSopenharmony_ci written_header_value: false, 644336d762aSopenharmony_ci indent: None, 645336d762aSopenharmony_ci suffix: "\n", 646336d762aSopenharmony_ci buf: &mut f, 647336d762aSopenharmony_ci }, 648336d762aSopenharmony_ci ); 649336d762aSopenharmony_ci 650336d762aSopenharmony_ci assert_eq!("[INFO test::path] log\nmessage\n", written); 651336d762aSopenharmony_ci } 652336d762aSopenharmony_ci} 653