1use crate::config::Config;
4use crate::util;
5use fern::colors::{Color, ColoredLevelConfig};
6use std::fs;
7use std::io;
8use std::sync::atomic::{AtomicUsize, Ordering};
9use thiserror::Error;
10
11static STDOUT_LINE_COUNTER: AtomicUsize = AtomicUsize::new(0);
12
13fn get_num_stdout_lines_logged() -> usize {
14 STDOUT_LINE_COUNTER.load(Ordering::Acquire)
15}
16
17pub(crate) fn add_lines_printed_to_stdout(num_lines: usize) {
19 STDOUT_LINE_COUNTER.fetch_add(num_lines, Ordering::AcqRel);
20}
21
22pub(crate) fn clear_stdout() -> io::Result<()> {
25 use std::io::Write;
26
27 let stdout = io::stdout();
28 let mut f = stdout.lock();
29 let num_lines_to_clear = get_num_stdout_lines_logged();
30 for _ in 0..num_lines_to_clear {
31 write!(f, "\x1B[1A\x1B[2K")?;
35 }
36 f.flush()?;
37 Ok(())
38}
39
40pub fn set_up_logging(count_lines: bool) -> anyhow::Result<()> {
42 let colors_line = ColoredLevelConfig::new()
43 .error(Color::Red)
44 .warn(Color::Yellow)
45 .trace(Color::BrightBlack);
46 let should_color = util::wapm_should_print_color();
47
48 let colors_level = colors_line.info(Color::Green);
49 let dispatch = fern::Dispatch::new()
50 .chain({
52 let base = if should_color {
53 fern::Dispatch::new()
54 .level(log::LevelFilter::Info)
55 .filter(|metadata| metadata.target().starts_with("wapm_cli"))
56 .format(move |out, message, record| {
57 if count_lines && record.level() == log::Level::Info {
58 let num_lines = message.to_string().lines().count();
59 add_lines_printed_to_stdout(num_lines);
60 }
61 out.finish(format_args!(
62 "{color_line}[{level}{color_line}]{ansi_close} {message}",
63 color_line = format_args!(
64 "\x1B[{}m",
65 colors_line.get_color(&record.level()).to_fg_str()
66 ),
67 level = colors_level.color(record.level()),
68 ansi_close = "\x1B[0m",
69 message = message,
70 ));
71 })
72 } else {
73 fern::Dispatch::new()
75 .level(log::LevelFilter::Info)
76 .filter(|metadata| metadata.target().starts_with("wapm_cli"))
77 .format(move |out, message, record| {
78 if count_lines && record.level() == log::Level::Info {
79 let num_lines = message.to_string().lines().count();
80 add_lines_printed_to_stdout(num_lines);
81 }
82 out.finish(format_args!(
83 "[{level}] {message}",
84 level = record.level(),
85 message = message,
86 ));
87 })
88 };
89 base
90 .chain(
92 fern::Dispatch::new()
93 .filter(|metadata| metadata.level() == log::LevelFilter::Info)
94 .chain(std::io::stdout()),
95 )
96 .chain(
98 fern::Dispatch::new()
99 .filter(|metadata| {
100 metadata.level() <= log::LevelFilter::Warn
102 && metadata.target().starts_with("wapm_cli")
103 })
104 .chain(std::io::stderr()),
105 )
106 });
107
108 let dispatch = if let Ok(wasmer_dir) = Config::get_folder() {
110 let log_out = wasmer_dir.join("wapm.log");
111 dispatch.chain(
112 fern::Dispatch::new()
113 .level(log::LevelFilter::Debug)
114 .level_for("hyper", log::LevelFilter::Info)
115 .level_for("tokio_reactor", log::LevelFilter::Info)
116 .format(move |out, message, record| {
117 out.finish(format_args!(
118 "[{date}][{level}][{target}][{file}:{line}] {message}",
119 date = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
120 target = record.target(),
121 level = record.level(),
122 message = message,
123 file = record.file().unwrap_or(""),
124 line = record
125 .line()
126 .map(|line| format!("{}", line))
127 .unwrap_or_else(|| "".to_string()),
128 ));
129 })
130 .chain(
131 fs::OpenOptions::new()
132 .write(true)
133 .create(true)
134 .truncate(true)
135 .open(log_out.clone())
136 .map_err(|e| {
137 LoggingError::FailedToOpenLoggingFile(format!(
138 "log_out: {:?}, error type: {:?}",
139 log_out,
140 e.kind()
141 ))
142 })?,
143 ),
144 )
145 } else {
146 dispatch
147 };
148
149 dispatch
150 .apply()
151 .map_err(|e| LoggingError::FailedToInstantiateLogger(format!("{}", e)))?;
152
153 trace!("Logging set up");
154 Ok(())
155}
156
157#[derive(Debug, Error)]
158pub enum LoggingError {
159 #[error("Failed to open logging file in WASMER_DIR: {0}")]
160 FailedToOpenLoggingFile(String),
161 #[error("Something went wrong setting up logging: {0}")]
162 FailedToInstantiateLogger(String),
163}