1*0d6140beSAndroid Build Coastguard Worker //
2*0d6140beSAndroid Build Coastguard Worker // Copyright 2019, Google Inc.
3*0d6140beSAndroid Build Coastguard Worker // All rights reserved.
4*0d6140beSAndroid Build Coastguard Worker //
5*0d6140beSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
6*0d6140beSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are
7*0d6140beSAndroid Build Coastguard Worker // met:
8*0d6140beSAndroid Build Coastguard Worker //
9*0d6140beSAndroid Build Coastguard Worker // * Redistributions of source code must retain the above copyright
10*0d6140beSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
11*0d6140beSAndroid Build Coastguard Worker // * Redistributions in binary form must reproduce the above
12*0d6140beSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer
13*0d6140beSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the
14*0d6140beSAndroid Build Coastguard Worker // distribution.
15*0d6140beSAndroid Build Coastguard Worker // * Neither the name of Google Inc. nor the names of its
16*0d6140beSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from
17*0d6140beSAndroid Build Coastguard Worker // this software without specific prior written permission.
18*0d6140beSAndroid Build Coastguard Worker //
19*0d6140beSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*0d6140beSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*0d6140beSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*0d6140beSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*0d6140beSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*0d6140beSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*0d6140beSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*0d6140beSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*0d6140beSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*0d6140beSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*0d6140beSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*0d6140beSAndroid Build Coastguard Worker //
31*0d6140beSAndroid Build Coastguard Worker // Alternatively, this software may be distributed under the terms of the
32*0d6140beSAndroid Build Coastguard Worker // GNU General Public License ("GPL") version 2 as published by the Free
33*0d6140beSAndroid Build Coastguard Worker // Software Foundation.
34*0d6140beSAndroid Build Coastguard Worker //
35*0d6140beSAndroid Build Coastguard Worker
36*0d6140beSAndroid Build Coastguard Worker use flashrom_tester::types;
37*0d6140beSAndroid Build Coastguard Worker use std::io::Write;
38*0d6140beSAndroid Build Coastguard Worker
39*0d6140beSAndroid Build Coastguard Worker struct Logger {
40*0d6140beSAndroid Build Coastguard Worker level: log::LevelFilter,
41*0d6140beSAndroid Build Coastguard Worker color: types::Color,
42*0d6140beSAndroid Build Coastguard Worker }
43*0d6140beSAndroid Build Coastguard Worker
44*0d6140beSAndroid Build Coastguard Worker impl log::Log for Logger {
enabled(&self, metadata: &log::Metadata) -> bool45*0d6140beSAndroid Build Coastguard Worker fn enabled(&self, metadata: &log::Metadata) -> bool {
46*0d6140beSAndroid Build Coastguard Worker metadata.level() <= self.level
47*0d6140beSAndroid Build Coastguard Worker }
48*0d6140beSAndroid Build Coastguard Worker
log(&self, record: &log::Record)49*0d6140beSAndroid Build Coastguard Worker fn log(&self, record: &log::Record) {
50*0d6140beSAndroid Build Coastguard Worker // Write errors deliberately ignored
51*0d6140beSAndroid Build Coastguard Worker let stdout = std::io::stdout();
52*0d6140beSAndroid Build Coastguard Worker let mut lock = stdout.lock();
53*0d6140beSAndroid Build Coastguard Worker let now = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Micros, true);
54*0d6140beSAndroid Build Coastguard Worker let _ = write!(lock, "{}{} ", self.color.magenta, now);
55*0d6140beSAndroid Build Coastguard Worker let _ = write!(
56*0d6140beSAndroid Build Coastguard Worker lock,
57*0d6140beSAndroid Build Coastguard Worker "{}[ {} ]{} ",
58*0d6140beSAndroid Build Coastguard Worker self.color.yellow,
59*0d6140beSAndroid Build Coastguard Worker record.level(),
60*0d6140beSAndroid Build Coastguard Worker self.color.reset
61*0d6140beSAndroid Build Coastguard Worker );
62*0d6140beSAndroid Build Coastguard Worker let _ = writeln!(lock, "{}", record.args());
63*0d6140beSAndroid Build Coastguard Worker }
64*0d6140beSAndroid Build Coastguard Worker
flush(&self)65*0d6140beSAndroid Build Coastguard Worker fn flush(&self) {
66*0d6140beSAndroid Build Coastguard Worker // Flush errors deliberately ignored
67*0d6140beSAndroid Build Coastguard Worker let _ = std::io::stdout().flush();
68*0d6140beSAndroid Build Coastguard Worker }
69*0d6140beSAndroid Build Coastguard Worker }
70*0d6140beSAndroid Build Coastguard Worker
init(debug: bool)71*0d6140beSAndroid Build Coastguard Worker pub fn init(debug: bool) {
72*0d6140beSAndroid Build Coastguard Worker let mut logger = Logger {
73*0d6140beSAndroid Build Coastguard Worker level: log::LevelFilter::Info,
74*0d6140beSAndroid Build Coastguard Worker color: if atty::is(atty::Stream::Stdout) {
75*0d6140beSAndroid Build Coastguard Worker types::COLOR
76*0d6140beSAndroid Build Coastguard Worker } else {
77*0d6140beSAndroid Build Coastguard Worker types::NOCOLOR
78*0d6140beSAndroid Build Coastguard Worker },
79*0d6140beSAndroid Build Coastguard Worker };
80*0d6140beSAndroid Build Coastguard Worker
81*0d6140beSAndroid Build Coastguard Worker if debug {
82*0d6140beSAndroid Build Coastguard Worker logger.level = log::LevelFilter::Debug;
83*0d6140beSAndroid Build Coastguard Worker }
84*0d6140beSAndroid Build Coastguard Worker log::set_max_level(logger.level);
85*0d6140beSAndroid Build Coastguard Worker log::set_boxed_logger(Box::new(logger)).unwrap();
86*0d6140beSAndroid Build Coastguard Worker }
87*0d6140beSAndroid Build Coastguard Worker
88*0d6140beSAndroid Build Coastguard Worker #[cfg(test)]
89*0d6140beSAndroid Build Coastguard Worker mod tests {
90*0d6140beSAndroid Build Coastguard Worker use std::io::Read;
91*0d6140beSAndroid Build Coastguard Worker
92*0d6140beSAndroid Build Coastguard Worker use super::Logger;
93*0d6140beSAndroid Build Coastguard Worker use flashrom_tester::types;
94*0d6140beSAndroid Build Coastguard Worker use log::{Level, LevelFilter, Log, Record};
95*0d6140beSAndroid Build Coastguard Worker
run_records(records: &[Record]) -> String96*0d6140beSAndroid Build Coastguard Worker fn run_records(records: &[Record]) -> String {
97*0d6140beSAndroid Build Coastguard Worker let buf = gag::BufferRedirect::stdout().unwrap();
98*0d6140beSAndroid Build Coastguard Worker {
99*0d6140beSAndroid Build Coastguard Worker let logger = Logger {
100*0d6140beSAndroid Build Coastguard Worker level: LevelFilter::Info,
101*0d6140beSAndroid Build Coastguard Worker color: types::COLOR,
102*0d6140beSAndroid Build Coastguard Worker };
103*0d6140beSAndroid Build Coastguard Worker
104*0d6140beSAndroid Build Coastguard Worker for record in records {
105*0d6140beSAndroid Build Coastguard Worker if logger.enabled(record.metadata()) {
106*0d6140beSAndroid Build Coastguard Worker logger.log(record);
107*0d6140beSAndroid Build Coastguard Worker }
108*0d6140beSAndroid Build Coastguard Worker }
109*0d6140beSAndroid Build Coastguard Worker }
110*0d6140beSAndroid Build Coastguard Worker let mut ret = String::new();
111*0d6140beSAndroid Build Coastguard Worker buf.into_inner().read_to_string(&mut ret).unwrap();
112*0d6140beSAndroid Build Coastguard Worker ret
113*0d6140beSAndroid Build Coastguard Worker }
114*0d6140beSAndroid Build Coastguard Worker
115*0d6140beSAndroid Build Coastguard Worker /// Log messages have the expected format
116*0d6140beSAndroid Build Coastguard Worker #[test]
format()117*0d6140beSAndroid Build Coastguard Worker fn format() {
118*0d6140beSAndroid Build Coastguard Worker let buf = run_records(&[Record::builder()
119*0d6140beSAndroid Build Coastguard Worker .args(format_args!("Test message at INFO"))
120*0d6140beSAndroid Build Coastguard Worker .level(Level::Info)
121*0d6140beSAndroid Build Coastguard Worker .build()]);
122*0d6140beSAndroid Build Coastguard Worker
123*0d6140beSAndroid Build Coastguard Worker assert_eq!(&buf[..5], "\x1b[35m");
124*0d6140beSAndroid Build Coastguard Worker // Time is difficult to test, assume it's formatted okay
125*0d6140beSAndroid Build Coastguard Worker // Split on the UTC timezone char
126*0d6140beSAndroid Build Coastguard Worker assert_eq!(
127*0d6140beSAndroid Build Coastguard Worker buf.split_once("Z ").unwrap().1,
128*0d6140beSAndroid Build Coastguard Worker "\x1b[33m[ INFO ]\x1b[0m Test message at INFO\n"
129*0d6140beSAndroid Build Coastguard Worker );
130*0d6140beSAndroid Build Coastguard Worker }
131*0d6140beSAndroid Build Coastguard Worker
132*0d6140beSAndroid Build Coastguard Worker #[test]
level_filter()133*0d6140beSAndroid Build Coastguard Worker fn level_filter() {
134*0d6140beSAndroid Build Coastguard Worker let buf = run_records(&[
135*0d6140beSAndroid Build Coastguard Worker Record::builder()
136*0d6140beSAndroid Build Coastguard Worker .args(format_args!("Test message at DEBUG"))
137*0d6140beSAndroid Build Coastguard Worker .level(Level::Debug)
138*0d6140beSAndroid Build Coastguard Worker .build(),
139*0d6140beSAndroid Build Coastguard Worker Record::builder()
140*0d6140beSAndroid Build Coastguard Worker .args(format_args!("Hello, world!"))
141*0d6140beSAndroid Build Coastguard Worker .level(Level::Error)
142*0d6140beSAndroid Build Coastguard Worker .build(),
143*0d6140beSAndroid Build Coastguard Worker ]);
144*0d6140beSAndroid Build Coastguard Worker
145*0d6140beSAndroid Build Coastguard Worker // There is one line because the Debug record wasn't written.
146*0d6140beSAndroid Build Coastguard Worker println!("{}", buf);
147*0d6140beSAndroid Build Coastguard Worker assert_eq!(buf.lines().count(), 1);
148*0d6140beSAndroid Build Coastguard Worker }
149*0d6140beSAndroid Build Coastguard Worker }
150