|
3 | 3 | #[cfg(feature = "rust-llvm")]
|
4 | 4 | extern crate aya_rustc_llvm_proxy;
|
5 | 5 |
|
6 |
| -use std::{ |
7 |
| - env, |
8 |
| - fs::{self, OpenOptions}, |
9 |
| - os::fd::AsRawFd, |
10 |
| - path::PathBuf, |
11 |
| - str::FromStr, |
12 |
| -}; |
| 6 | +use std::{env, fs, io, path::PathBuf, str::FromStr}; |
13 | 7 |
|
14 | 8 | use bpf_linker::{Cpu, Linker, LinkerOptions, OptLevel, OutputType};
|
15 | 9 | use clap::Parser;
|
16 |
| -use libc::dup2; |
17 |
| -use log::info; |
18 |
| -use simplelog::{ |
19 |
| - ColorChoice, Config, LevelFilter, SimpleLogger, TermLogger, TerminalMode, WriteLogger, |
20 |
| -}; |
21 | 10 | use thiserror::Error;
|
| 11 | +use tracing::{info, Level, Subscriber}; |
| 12 | +use tracing_appender::non_blocking::WorkerGuard; |
| 13 | +use tracing_subscriber::{fmt::MakeWriter, prelude::*, EnvFilter}; |
| 14 | +use tracing_tree::HierarchicalLayer; |
22 | 15 |
|
23 | 16 | #[derive(Debug, Error)]
|
24 | 17 | enum CliError {
|
@@ -65,6 +58,7 @@ impl FromStr for CliOutputType {
|
65 | 58 | }))
|
66 | 59 | }
|
67 | 60 | }
|
| 61 | + |
68 | 62 | #[derive(Debug, Parser)]
|
69 | 63 | struct CommandLine {
|
70 | 64 | /// LLVM target triple. When not provided, the target is inferred from the inputs
|
@@ -109,9 +103,10 @@ struct CommandLine {
|
109 | 103 | #[clap(long, value_name = "path")]
|
110 | 104 | log_file: Option<PathBuf>,
|
111 | 105 |
|
112 |
| - /// Set the log level. Can be one of `off`, `info`, `warn`, `debug`, `trace`. |
| 106 | + /// Set the log level. If not specified, no logging is used. Can be one of |
| 107 | + /// `error`, `warn`, `info`, `debug`, `trace`. |
113 | 108 | #[clap(long, value_name = "level")]
|
114 |
| - log_level: Option<LevelFilter>, |
| 109 | + log_level: Option<Level>, |
115 | 110 |
|
116 | 111 | /// Try hard to unroll loops. Useful when targeting kernels that don't support loops
|
117 | 112 | #[clap(long)]
|
@@ -155,6 +150,18 @@ struct CommandLine {
|
155 | 150 | _debug: bool,
|
156 | 151 | }
|
157 | 152 |
|
| 153 | +/// Returns a [`HierarchicalLayer`](tracing_tree::HierarchicalLayer) for the |
| 154 | +/// given `writer`. |
| 155 | +fn tracing_layer<W>(writer: W) -> HierarchicalLayer<W> |
| 156 | +where |
| 157 | + W: for<'writer> MakeWriter<'writer> + 'static, |
| 158 | +{ |
| 159 | + const TRACING_IDENT: usize = 2; |
| 160 | + HierarchicalLayer::new(TRACING_IDENT) |
| 161 | + .with_indent_lines(true) |
| 162 | + .with_writer(writer) |
| 163 | +} |
| 164 | + |
158 | 165 | fn main() {
|
159 | 166 | let args = env::args().map(|arg| {
|
160 | 167 | if arg == "-flavor" {
|
@@ -191,51 +198,38 @@ fn main() {
|
191 | 198 | error("no input files", clap::error::ErrorKind::TooFewValues);
|
192 | 199 | }
|
193 | 200 |
|
194 |
| - let env_log_level = match env::var("RUST_LOG") { |
195 |
| - Ok(s) if !s.is_empty() => match s.parse::<LevelFilter>() { |
196 |
| - Ok(l) => Some(l), |
197 |
| - Err(e) => error( |
198 |
| - &format!("invalid RUST_LOG value: {e}"), |
199 |
| - clap::error::ErrorKind::InvalidValue, |
200 |
| - ), |
201 |
| - }, |
202 |
| - _ => None, |
203 |
| - }; |
204 |
| - let log_level = log_level.or(env_log_level).unwrap_or(LevelFilter::Warn); |
205 |
| - if let Some(log_file) = log_file { |
206 |
| - let log_file = match OpenOptions::new().create(true).append(true).open(log_file) { |
207 |
| - Ok(f) => { |
208 |
| - // Use dup2 to duplicate stderr fd to the log file fd |
209 |
| - let result = unsafe { dup2(f.as_raw_fd(), std::io::stderr().as_raw_fd()) }; |
210 |
| - |
211 |
| - if result == -1 { |
212 |
| - error( |
213 |
| - &format!( |
214 |
| - "failed to duplicate stderr: {}", |
215 |
| - std::io::Error::last_os_error() |
216 |
| - ), |
217 |
| - clap::error::ErrorKind::Io, |
218 |
| - ) |
219 |
| - } |
220 |
| - f |
221 |
| - } |
222 |
| - Err(e) => { |
223 |
| - error( |
224 |
| - &format!("failed to open log file: {e:?}"), |
225 |
| - clap::error::ErrorKind::Io, |
| 201 | + // Configure tracing. |
| 202 | + if let Some(log_level) = log_level { |
| 203 | + let subscriber_registry = tracing_subscriber::registry() |
| 204 | + .with(EnvFilter::from_default_env().add_directive(log_level.into())); |
| 205 | + let (subscriber, _guard): ( |
| 206 | + Box<dyn Subscriber + Send + Sync + 'static>, |
| 207 | + Option<WorkerGuard>, |
| 208 | + ) = match log_file { |
| 209 | + Some(log_file) => { |
| 210 | + let file_appender = tracing_appender::rolling::never( |
| 211 | + log_file.parent().unwrap_or_else(|| { |
| 212 | + error("invalid log_file", clap::error::ErrorKind::InvalidValue) |
| 213 | + }), |
| 214 | + log_file.file_name().unwrap_or_else(|| { |
| 215 | + error("invalid log_file", clap::error::ErrorKind::InvalidValue) |
| 216 | + }), |
226 | 217 | );
|
| 218 | + let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender); |
| 219 | + let subscriber = subscriber_registry |
| 220 | + .with(tracing_layer(io::stdout)) |
| 221 | + .with(tracing_layer(non_blocking)); |
| 222 | + |
| 223 | + (Box::new(subscriber), Some(_guard)) |
| 224 | + } |
| 225 | + None => { |
| 226 | + let subscriber = subscriber_registry.with(tracing_layer(io::stderr)); |
| 227 | + (Box::new(subscriber), None) |
227 | 228 | }
|
228 | 229 | };
|
229 |
| - WriteLogger::init(log_level, Config::default(), log_file).unwrap(); |
230 |
| - } else if TermLogger::init( |
231 |
| - log_level, |
232 |
| - Config::default(), |
233 |
| - TerminalMode::Mixed, |
234 |
| - ColorChoice::Auto, |
235 |
| - ) |
236 |
| - .is_err() |
237 |
| - { |
238 |
| - SimpleLogger::init(log_level, Config::default()).unwrap(); |
| 230 | + if let Err(e) = tracing::subscriber::set_global_default(subscriber) { |
| 231 | + error(&e.to_string(), clap::error::ErrorKind::Format); |
| 232 | + } |
239 | 233 | }
|
240 | 234 |
|
241 | 235 | info!(
|
|
0 commit comments