mirror of
https://github.com/eyre-rs/eyre.git
synced 2025-10-02 15:26:08 +00:00
Initial commit of color-spantrace
This commit is contained in:
commit
c2ac4508ae
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "color-spantrace"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Jane Lusby <jlusby@yaah.dev>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
console = "0.10.0"
|
||||||
|
tracing-error = "0.1.2"
|
||||||
|
tracing-core = "0.1.10"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tracing-subscriber = "0.2.5"
|
||||||
|
tracing = "0.1.13"
|
21
examples/usage.rs
Normal file
21
examples/usage.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use tracing::instrument;
|
||||||
|
use tracing_error::{prelude::*, ErrorLayer, SpanTrace};
|
||||||
|
use tracing_subscriber::{prelude::*, registry::Registry};
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
|
fn main() {
|
||||||
|
Registry::default().with(ErrorLayer::default()).init();
|
||||||
|
|
||||||
|
let span_trace = one(42);
|
||||||
|
println!("{}", color_spantrace::colorize(&span_trace));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
|
fn one(i: u32) -> SpanTrace {
|
||||||
|
two()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
|
fn two() -> SpanTrace {
|
||||||
|
SpanTrace::capture()
|
||||||
|
}
|
161
src/lib.rs
Normal file
161
src/lib.rs
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
use console::style;
|
||||||
|
use std::fmt;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, ErrorKind};
|
||||||
|
use tracing_error::SpanTrace;
|
||||||
|
|
||||||
|
pub fn colorize(span_trace: &SpanTrace) -> impl fmt::Display + '_ {
|
||||||
|
ColorSpanTrace { span_trace }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColorSpanTrace<'a> {
|
||||||
|
span_trace: &'a SpanTrace,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! try_bool {
|
||||||
|
($e:expr, $dest:ident) => {{
|
||||||
|
let ret = $e.unwrap_or_else(|e| $dest = Err(e));
|
||||||
|
|
||||||
|
if $dest.is_err() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Frame<'a> {
|
||||||
|
metadata: &'a tracing_core::Metadata<'static>,
|
||||||
|
fields: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines how verbose the backtrace is supposed to be.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum Verbosity {
|
||||||
|
/// Print a small message including the panic payload and the panic location.
|
||||||
|
Minimal,
|
||||||
|
/// Everything in `Minimal` and additionally print a backtrace.
|
||||||
|
Medium,
|
||||||
|
/// Everything in `Medium` plus source snippets for all backtrace locations.
|
||||||
|
Full,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Verbosity {
|
||||||
|
/// Get the verbosity level from the `RUST_LIB_BACKTRACE` env variable.
|
||||||
|
fn from_env() -> Self {
|
||||||
|
match std::env::var("RUST_LIB_BACKTRACE") {
|
||||||
|
Ok(ref x) if x == "full" => Verbosity::Full,
|
||||||
|
Ok(_) => Verbosity::Medium,
|
||||||
|
Err(_) => Verbosity::Minimal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame<'_> {
|
||||||
|
fn print(&self, i: u32, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.print_header(i, f)?;
|
||||||
|
self.print_fields(f)?;
|
||||||
|
self.print_source_location(f)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_header(&self, i: u32, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{:>4}: {}",
|
||||||
|
i,
|
||||||
|
style(format_args!(
|
||||||
|
"{}::{}",
|
||||||
|
self.metadata.target(),
|
||||||
|
self.metadata.name()
|
||||||
|
))
|
||||||
|
.red()
|
||||||
|
.dim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_fields(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if !self.fields.is_empty() {
|
||||||
|
write!(f, " with {}", style(self.fields).bold())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_source_location(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if let Some(file) = self.metadata.file() {
|
||||||
|
let lineno = self
|
||||||
|
.metadata
|
||||||
|
.line()
|
||||||
|
.map_or("<unknown line>".to_owned(), |x| x.to_string());
|
||||||
|
write!(f, "\n at {}:{}", file, lineno)?;
|
||||||
|
} else {
|
||||||
|
write!(f, "\n at <unknown source file>")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_source_if_avail(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let (lineno, filename) = match (self.metadata.line(), self.metadata.file()) {
|
||||||
|
(Some(a), Some(b)) => (a, b),
|
||||||
|
// Without a line number and file name, we can't sensibly proceed.
|
||||||
|
_ => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let file = match File::open(filename) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(ref e) if e.kind() == ErrorKind::NotFound => return Ok(()),
|
||||||
|
e @ Err(_) => e.unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extract relevant lines.
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let start_line = lineno - 2.min(lineno - 1);
|
||||||
|
let surrounding_src = reader.lines().skip(start_line as usize - 1).take(5);
|
||||||
|
for (line, cur_line_no) in surrounding_src.zip(start_line..) {
|
||||||
|
if cur_line_no == lineno {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"\n{}",
|
||||||
|
style(format_args!("{:>10} > {}", cur_line_no, line.unwrap())).bold()
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
write!(f, "\n{:>10} │ {}", cur_line_no, line.unwrap())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ColorSpanTrace<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut err = Ok(());
|
||||||
|
let mut span = 0;
|
||||||
|
|
||||||
|
let verbosity = Verbosity::from_env();
|
||||||
|
|
||||||
|
writeln!(f, "{:━^80}", " SPANTRACE ")?;
|
||||||
|
self.span_trace.with_spans(|metadata, fields| {
|
||||||
|
let frame = Frame { metadata, fields };
|
||||||
|
|
||||||
|
if span > 0 {
|
||||||
|
try_bool!(write!(f, "\n",), err);
|
||||||
|
}
|
||||||
|
|
||||||
|
try_bool!(frame.print(span, f), err);
|
||||||
|
|
||||||
|
match verbosity {
|
||||||
|
Verbosity::Full => try_bool!(frame.print_source_if_avail(f), err),
|
||||||
|
Verbosity::Medium => {}
|
||||||
|
Verbosity::Minimal => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
span += 1;
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
|
err
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user