| // Licensed to the Software Freedom Conservancy (SFC) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The SFC licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| use crate::metadata::now_unix_timestamp; |
| use env_logger::fmt::Color; |
| use env_logger::Target::Stdout; |
| use env_logger::DEFAULT_FILTER_ENV; |
| use log::Level; |
| use log::LevelFilter::{Debug, Info, Trace}; |
| use serde::{Deserialize, Serialize}; |
| use std::cell::RefCell; |
| use std::env; |
| use std::fmt::Display; |
| use std::io::Write; |
| use std::ops::Deref; |
| use Color::{Blue, Cyan, Green, Red, Yellow}; |
| |
| enum OutputType { |
| Logger, |
| Json, |
| Shell, |
| } |
| |
| pub struct Logger { |
| debug: bool, |
| trace: bool, |
| output: OutputType, |
| json: RefCell<JsonOutput>, |
| } |
| |
| #[derive(Serialize, Deserialize)] |
| pub struct Logs { |
| pub level: String, |
| pub timestamp: u64, |
| pub message: String, |
| } |
| |
| #[derive(Serialize, Deserialize)] |
| pub struct Result { |
| pub code: i32, |
| pub message: String, |
| } |
| |
| #[derive(Serialize, Deserialize)] |
| pub struct JsonOutput { |
| pub logs: Vec<Logs>, |
| pub result: Result, |
| } |
| |
| impl Logger { |
| pub fn default() -> Self { |
| Logger::create("", false, false) |
| } |
| |
| pub fn create(output: &str, debug: bool, trace: bool) -> Self { |
| let output_type; |
| if output.eq_ignore_ascii_case("json") { |
| output_type = OutputType::Json; |
| } else if output.eq_ignore_ascii_case("shell") { |
| output_type = OutputType::Shell; |
| } else { |
| output_type = OutputType::Logger; |
| } |
| match output_type { |
| OutputType::Logger => { |
| if env::var(DEFAULT_FILTER_ENV).unwrap_or_default().is_empty() { |
| let mut filter = match debug { |
| true => Debug, |
| false => Info, |
| }; |
| if trace { |
| filter = Trace |
| } |
| env_logger::Builder::new() |
| .filter_module(env!("CARGO_CRATE_NAME"), filter) |
| .target(Stdout) |
| .format(|buf, record| { |
| let mut level_style = buf.style(); |
| match record.level() { |
| Level::Trace => level_style.set_color(Cyan), |
| Level::Debug => level_style.set_color(Blue), |
| Level::Info => level_style.set_color(Green), |
| Level::Warn => level_style.set_color(Yellow), |
| Level::Error => level_style.set_color(Red).set_bold(true), |
| }; |
| writeln!( |
| buf, |
| "{}\t{}", |
| level_style.value(record.level()), |
| record.args() |
| ) |
| }) |
| .try_init() |
| .unwrap_or_default(); |
| } else { |
| env_logger::try_init().unwrap_or_default(); |
| } |
| } |
| _ => { |
| env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) |
| .try_init() |
| .unwrap_or_default(); |
| } |
| } |
| |
| Logger { |
| debug, |
| trace, |
| output: output_type, |
| json: RefCell::new(JsonOutput { |
| logs: Vec::new(), |
| result: Result { |
| code: 0, |
| message: "".to_string(), |
| }, |
| }), |
| } |
| } |
| |
| pub fn error<T: Display>(&self, message: T) { |
| self.logger(message.to_string(), Level::Error); |
| } |
| |
| pub fn warn<T: Display>(&self, message: T) { |
| self.logger(message.to_string(), Level::Warn); |
| } |
| |
| pub fn info<T: Display>(&self, message: T) { |
| self.logger(message.to_string(), Level::Info); |
| } |
| |
| pub fn debug<T: Display>(&self, message: T) { |
| self.logger(message.to_string(), Level::Debug); |
| } |
| |
| pub fn trace<T: Display>(&self, message: T) { |
| self.logger(message.to_string(), Level::Trace); |
| } |
| |
| fn logger(&self, message: String, level: Level) { |
| match self.output { |
| OutputType::Json => { |
| let trace = level <= Level::Trace && self.trace; |
| let debug = level <= Level::Debug && self.debug; |
| let other = level <= Level::Info; |
| if trace || debug || other { |
| self.json |
| .borrow_mut() |
| .logs |
| .push(self.create_json_log(message.to_string(), level)); |
| } |
| if level == Level::Info || level <= Level::Error { |
| self.json.borrow_mut().result.message = message; |
| } |
| } |
| OutputType::Shell => { |
| if level == Level::Info { |
| print!("{}", message); |
| } else if level == Level::Error { |
| eprint!("{}", message); |
| } |
| } |
| _ => { |
| log::log!(level, "{}", message); |
| } |
| } |
| } |
| |
| fn create_json_log(&self, message: String, level: Level) -> Logs { |
| Logs { |
| level: level.to_string().to_uppercase(), |
| timestamp: now_unix_timestamp(), |
| message, |
| } |
| } |
| |
| pub fn set_code(&self, code: i32) { |
| self.json.borrow_mut().result.code = code; |
| } |
| |
| pub fn flush(&self) { |
| let json_output = &self.json.borrow(); |
| let json = json_output.deref(); |
| if !json.logs.is_empty() { |
| print!("{}", serde_json::to_string_pretty(json.deref()).unwrap()); |
| } |
| } |
| } |