use std::fmt;
use std::io;
use std::io::Write;
use tracing::field::Visit;
use tracing_subscriber::field::RecordFields;
use tracing_subscriber::fmt::format::Writer;
use tracing_subscriber::fmt::FormatFields;
struct FieldFormatterVisitor<'a> {
writer: Writer<'a>,
is_empty: bool,
result: fmt::Result,
}
impl<'a> FieldFormatterVisitor<'a> {
fn maybe_pad(&mut self) {
if self.is_empty {
self.is_empty = false;
} else {
self.result = write!(self.writer, " ");
}
}
fn record_display(&mut self, field: &tracing::field::Field, value: &dyn fmt::Display) {
if self.result.is_err() {
return;
}
self.maybe_pad();
self.result = match field.name() {
"message" => write!(self.writer, "{}", value),
name if name.starts_with("log.") => Ok(()),
name if name.starts_with("r#") => write!(self.writer, "{}={}", &name[2..], value),
name => write!(self.writer, "{}={}", name, value),
};
}
}
impl<'a> Visit for FieldFormatterVisitor<'a> {
fn record_f64(&mut self, field: &tracing::field::Field, value: f64) {
self.record_display(field, &value)
}
fn record_i64(&mut self, field: &tracing::field::Field, value: i64) {
self.record_display(field, &value)
}
fn record_u64(&mut self, field: &tracing::field::Field, value: u64) {
self.record_display(field, &format_args!("{:#x}", value))
}
fn record_bool(&mut self, field: &tracing::field::Field, value: bool) {
self.record_display(field, &value)
}
fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
self.record_display(field, &format_args!("{:?}", value))
}
fn record_error(
&mut self,
field: &tracing::field::Field,
mut value: &(dyn std::error::Error + 'static),
) {
self.record_debug(field, &format_args!("{}", value));
while let Some(s) = value.source() {
value = s;
if self.result.is_err() {
return;
}
self.result = write!(self.writer, ": {}", value);
}
}
fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn fmt::Debug) {
self.record_display(field, &format_args!("{:x?}", value))
}
}
pub struct FieldFormatter;
impl<'a> FormatFields<'a> for FieldFormatter {
fn format_fields<R: RecordFields>(&self, writer: Writer<'_>, fields: R) -> fmt::Result {
let mut visitor = FieldFormatterVisitor {
writer,
is_empty: false,
result: Ok(()),
};
fields.record(&mut visitor);
visitor.result
}
}
pub struct CrlfWriter<T> {
inner: T,
write_lf: bool,
}
impl<T: Write> CrlfWriter<T> {
pub fn new(t: T) -> Self {
CrlfWriter {
inner: t,
write_lf: false,
}
}
fn flush_lf(&mut self) -> io::Result<()> {
if self.write_lf {
if self.inner.write(b"\n")? == 0 {
return Err(io::ErrorKind::WriteZero.into());
}
self.write_lf = false;
}
Ok(())
}
}
impl<T: Write> Write for CrlfWriter<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.flush_lf()?;
if buf.first() == Some(&b'\n') {
return Ok(match self.inner.write(b"\r\n")? {
0 => 0,
1 => {
self.write_lf = true;
1
}
_ => 1,
});
}
let len = buf.iter().position(|x| *x == b'\n').unwrap_or(buf.len());
self.inner.write(&buf[..len])
}
fn flush(&mut self) -> io::Result<()> {
self.flush_lf()?;
self.inner.flush()
}
}