1#[cfg(test)]
7#[path = "logger_test.rs"]
8mod logger_test;
9
10use crate::recursion_level;
11use crate::types::FlowInfo;
12use colored::{ColoredString, Colorize};
13use log::{Level, LevelFilter};
14use std::io::stdout;
15use std::process::exit;
16
17#[derive(Debug, PartialEq)]
18pub(crate) enum LogLevel {
20 VERBOSE,
21 INFO,
22 ERROR,
23 OFF,
24}
25
26pub struct LoggerOptions {
28 pub name: String,
30 pub level: String,
32 pub color: bool,
34}
35
36pub(crate) fn get_level(level_name: &str) -> LogLevel {
37 match level_name {
38 "verbose" => LogLevel::VERBOSE,
39 "error" => LogLevel::ERROR,
40 "off" => LogLevel::OFF,
41 _ => LogLevel::INFO,
42 }
43}
44
45pub(crate) fn get_log_level() -> String {
47 if envmnt::is_equal("CARGO_MAKE_LOG_LEVEL", "off") {
48 "off"
49 } else if log_enabled!(Level::Debug) {
50 "verbose"
51 } else if log_enabled!(Level::Info) {
52 "info"
53 } else {
54 "error"
55 }
56 .to_string()
57}
58
59fn get_name_for_filter(filter: &LevelFilter) -> String {
60 let level = match filter {
61 LevelFilter::Off => return "off".to_string(),
62 LevelFilter::Debug => Level::Debug,
63 LevelFilter::Warn => Level::Warn,
64 LevelFilter::Error => Level::Error,
65 _ => Level::Info,
66 };
67
68 get_name_for_level(&level)
69}
70
71fn get_name_for_level(level: &Level) -> String {
72 match level {
73 Level::Debug => "verbose".to_string(),
74 Level::Warn => "warn".to_string(),
75 Level::Error => "error".to_string(),
76 _ => "info".to_string(),
77 }
78}
79
80fn get_formatted_name(name: &str, use_color: bool) -> ColoredString {
81 if use_color {
82 name.bold()
83 } else {
84 name.normal()
85 }
86}
87
88fn get_formatted_log_level(level: &Level, use_color: bool) -> ColoredString {
89 let mut level_name = get_name_for_level(&level);
90 level_name = level_name.to_uppercase();
91
92 if use_color {
93 let fmt_value = match level {
94 Level::Debug => level_name.cyan(),
95 Level::Info => level_name.green(),
96 Level::Warn => level_name.yellow(),
97 Level::Error => level_name.red(),
98 _ => level_name.normal(),
99 };
100
101 fmt_value.bold()
102 } else {
103 level_name.normal()
104 }
105}
106
107pub(crate) fn should_reduce_output(flow_info: &FlowInfo) -> bool {
108 match flow_info.config.config.reduce_output {
109 Some(value) => value,
110 None => !envmnt::is("CARGO_MAKE_CI"),
111 }
112}
113
114pub(crate) fn init(options: &LoggerOptions) {
120 let level_name = &options.level;
121 let color = options.color;
122
123 let level = get_level(level_name);
124
125 let log_level = match level {
126 LogLevel::VERBOSE => LevelFilter::Debug,
127 LogLevel::INFO => LevelFilter::Info,
128 LogLevel::ERROR => LevelFilter::Error,
129 LogLevel::OFF => LevelFilter::Off,
130 };
131 let level_name_value = get_name_for_filter(&log_level);
132
133 envmnt::set("CARGO_MAKE_LOG_LEVEL", &level_name_value);
134 envmnt::set_bool("CARGO_MAKE_DISABLE_COLOR", !color);
135
136 let recursion_lvl = recursion_level::get();
137 let recursion_level_log = if recursion_lvl == 0 {
138 "".to_string()
139 } else {
140 format!("[{}]", recursion_lvl)
141 };
142
143 let name_fmt = get_formatted_name(&options.name, color);
144
145 let result = fern::Dispatch::new()
146 .format(move |out, message, record| {
147 let record_level = record.level();
148
149 if cfg!(test) {
150 if record_level == LevelFilter::Error {
151 panic!("test error flow: {}", message);
152 }
153 }
154
155 let record_level_fmt = get_formatted_log_level(&record_level, color);
156
157 out.finish(format_args!(
158 "[{}]{} {} - {}",
159 &name_fmt, &recursion_level_log, &record_level_fmt, &message
160 ));
161
162 if record_level == Level::Error {
163 warn!("Build Failed.");
164
165 exit(1);
166 }
167 })
168 .level(log_level)
169 .chain(stdout())
170 .apply();
171
172 if result.is_err() {
173 println!("Unable to setup logger.");
174 }
175}