An easy way to get file name and line numbers is to use the built-in pretty formatter:
fn main() {
tracing_subscriber::fmt().pretty().init();
tracing::error!("hello, world");
}
However, the output uses multiple lines for each log record. Also note that there's a minor formatting bug that's fixed, but not in the current release.
I also wanted a format like you're asking for and ended up implementing a custom FormatEvent like this:
use std::fmt::{Error, Write};
use crossterm::style::Stylize;
use tracing::{subscriber::Subscriber, Event};
use tracing_log::NormalizeEvent;
use tracing_subscriber::{
fmt::{
time::{ChronoLocal, FormatTime},
FmtContext, FormatEvent, FormatFields,
},
registry::LookupSpan,
};
fn main() {
tracing_subscriber::fmt().event_format(SimpleFmt).init();
tracing::error!("hello, world");
}
struct SimpleFmt;
impl<S, N> FormatEvent<S, N> for SimpleFmt
where
S: Subscriber + for<'a> LookupSpan<'a>,
N: for<'a> FormatFields<'a> + 'static,
{
fn format_event(
&self,
ctx: &FmtContext<'_, S, N>,
writer: &mut dyn Write,
event: &Event<'_>,
) -> Result<(), Error> {
// Create timestamp
let time_format = "%b %d %I:%M:%S%.6f %p";
let mut time_now = String::new();
ChronoLocal::with_format(time_format.into()).format_time(&mut time_now)?;
// Get line numbers from log crate events
let normalized_meta = event.normalized_metadata();
let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
// Write formatted log record
let message = format!(
"{} {} {}{}{} ",
time_now.grey(),
meta.level().to_string().blue(),
meta.file().unwrap_or("").to_string().yellow(),
String::from(":").yellow(),
meta.line().unwrap_or(0).to_string().yellow(),
);
write!(writer, "{}", message).unwrap();
ctx.format_fields(writer, event)?;
writeln!(writer)
}
}