Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use mail_parser::DateTime;
|
||||
use tokio::io::{AsyncWrite, AsyncWriteExt};
|
||||
|
||||
use crate::{Error, Event, EventDetails, Key, Level, Value};
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
|
||||
pub struct FmtWriter<T: AsyncWrite + Unpin> {
|
||||
writer: T,
|
||||
ansi: bool,
|
||||
multiline: bool,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum Color {
|
||||
Black,
|
||||
Red,
|
||||
Green,
|
||||
Yellow,
|
||||
Blue,
|
||||
Magenta,
|
||||
Cyan,
|
||||
White,
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Unpin> FmtWriter<T> {
|
||||
pub fn new(writer: T) -> Self {
|
||||
Self {
|
||||
writer,
|
||||
ansi: false,
|
||||
multiline: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_ansi(self, ansi: bool) -> Self {
|
||||
Self { ansi, ..self }
|
||||
}
|
||||
|
||||
pub fn with_multiline(self, multiline: bool) -> Self {
|
||||
Self { multiline, ..self }
|
||||
}
|
||||
|
||||
pub async fn write(&mut self, event: &Event<EventDetails>) -> std::io::Result<()> {
|
||||
// Write timestamp
|
||||
if self.ansi {
|
||||
self.writer
|
||||
.write_all(Color::White.as_code().as_bytes())
|
||||
.await?;
|
||||
}
|
||||
self.writer
|
||||
.write_all(
|
||||
DateTime::from_timestamp(event.inner.timestamp as i64)
|
||||
.to_rfc3339()
|
||||
.as_bytes(),
|
||||
)
|
||||
.await?;
|
||||
if self.ansi {
|
||||
self.writer.write_all(Color::reset().as_bytes()).await?;
|
||||
}
|
||||
self.writer.write_all(" ".as_bytes()).await?;
|
||||
|
||||
// Write level
|
||||
if self.ansi {
|
||||
self.writer
|
||||
.write_all(
|
||||
match event.inner.level {
|
||||
Level::Error => Color::Red,
|
||||
Level::Warn => Color::Yellow,
|
||||
Level::Info => Color::Green,
|
||||
Level::Debug => Color::Blue,
|
||||
Level::Trace => Color::Magenta,
|
||||
Level::Disable => return Ok(()),
|
||||
}
|
||||
.as_code_bold()
|
||||
.as_bytes(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
self.writer
|
||||
.write_all(event.inner.level.as_str().as_bytes())
|
||||
.await?;
|
||||
if self.ansi {
|
||||
self.writer.write_all(Color::reset().as_bytes()).await?;
|
||||
}
|
||||
self.writer.write_all(" ".as_bytes()).await?;
|
||||
|
||||
// Write message
|
||||
if self.ansi {
|
||||
self.writer
|
||||
.write_all(Color::White.as_code_bold().as_bytes())
|
||||
.await?;
|
||||
}
|
||||
self.writer
|
||||
.write_all(event.inner.typ.description().as_bytes())
|
||||
.await?;
|
||||
if self.ansi {
|
||||
self.writer.write_all(Color::reset().as_bytes()).await?;
|
||||
}
|
||||
self.writer.write_all(" (".as_bytes()).await?;
|
||||
self.writer
|
||||
.write_all(event.inner.typ.as_str().as_bytes())
|
||||
.await?;
|
||||
|
||||
self.writer
|
||||
.write_all(if self.multiline { ")\n" } else { ") " }.as_bytes())
|
||||
.await?;
|
||||
|
||||
// Write keys
|
||||
if let Some(parent_event) = &event.inner.span {
|
||||
self.write_keys(&parent_event.keys, &event.keys, 1).await?;
|
||||
} else {
|
||||
self.write_keys(&[], &event.keys, 1).await?;
|
||||
}
|
||||
|
||||
if !self.multiline {
|
||||
self.writer.write_all("\n".as_bytes()).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn write_keys(
|
||||
&mut self,
|
||||
span_keys: &[(Key, Value)],
|
||||
keys: &[(Key, Value)],
|
||||
indent: usize,
|
||||
) -> std::io::Result<()> {
|
||||
Box::pin(async move {
|
||||
let mut is_first = true;
|
||||
for (key, value) in span_keys.iter().chain(keys.iter()) {
|
||||
if matches!(key, Key::SpanId) {
|
||||
continue;
|
||||
} else if is_first {
|
||||
is_first = false;
|
||||
} else if !self.multiline {
|
||||
self.writer.write_all(", ".as_bytes()).await?;
|
||||
}
|
||||
|
||||
// Write key
|
||||
if self.multiline {
|
||||
for _ in 0..indent {
|
||||
self.writer.write_all("\t".as_bytes()).await?;
|
||||
}
|
||||
}
|
||||
if self.ansi {
|
||||
self.writer
|
||||
.write_all(Color::Cyan.as_code().as_bytes())
|
||||
.await?;
|
||||
}
|
||||
self.writer.write_all(key.as_str().as_bytes()).await?;
|
||||
if self.ansi {
|
||||
self.writer.write_all(Color::reset().as_bytes()).await?;
|
||||
}
|
||||
|
||||
// Write value
|
||||
self.writer.write_all(" = ".as_bytes()).await?;
|
||||
self.write_value(value, indent).await?;
|
||||
|
||||
if self.multiline && !matches!(value, Value::Event(_)) {
|
||||
self.writer.write_all("\n".as_bytes()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn write_value(&mut self, value: &Value, indent: usize) -> std::io::Result<()> {
|
||||
Box::pin(async move {
|
||||
match value {
|
||||
Value::String(v) => {
|
||||
self.writer.write_all("\"".as_bytes()).await?;
|
||||
for ch in v.as_bytes() {
|
||||
match ch {
|
||||
b'\r' => {
|
||||
self.writer.write_all("\\r".as_bytes()).await?;
|
||||
}
|
||||
b'\n' => {
|
||||
self.writer.write_all("\\n".as_bytes()).await?;
|
||||
}
|
||||
b'\t' => {
|
||||
self.writer.write_all("\\t".as_bytes()).await?;
|
||||
}
|
||||
b'\\' => {
|
||||
self.writer.write_all("\\\\".as_bytes()).await?;
|
||||
}
|
||||
_ => {
|
||||
self.writer.write_all(&[*ch]).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.writer.write_all("\"".as_bytes()).await?;
|
||||
}
|
||||
Value::UInt(v) => {
|
||||
self.writer.write_all(v.to_string().as_bytes()).await?;
|
||||
}
|
||||
Value::Int(v) => {
|
||||
self.writer.write_all(v.to_string().as_bytes()).await?;
|
||||
}
|
||||
Value::Float(v) => {
|
||||
self.writer.write_all(v.to_string().as_bytes()).await?;
|
||||
}
|
||||
Value::Timestamp(v) => {
|
||||
self.writer
|
||||
.write_all(DateTime::from_timestamp(*v as i64).to_rfc3339().as_bytes())
|
||||
.await?;
|
||||
}
|
||||
Value::Duration(v) => {
|
||||
self.writer.write_all(v.to_string().as_bytes()).await?;
|
||||
self.writer.write_all("ms".as_bytes()).await?;
|
||||
}
|
||||
Value::Bytes(bytes) => {
|
||||
self.writer.write_all("base64:".as_bytes()).await?;
|
||||
self.writer
|
||||
.write_all(STANDARD.encode(bytes).as_bytes())
|
||||
.await?;
|
||||
}
|
||||
Value::Bool(true) => {
|
||||
self.writer.write_all("true".as_bytes()).await?;
|
||||
}
|
||||
Value::Bool(false) => {
|
||||
self.writer.write_all("false".as_bytes()).await?;
|
||||
}
|
||||
Value::Ipv4(v) => {
|
||||
self.writer.write_all(v.to_string().as_bytes()).await?;
|
||||
}
|
||||
Value::Ipv6(v) => {
|
||||
self.writer.write_all(v.to_string().as_bytes()).await?;
|
||||
}
|
||||
Value::Event(e) => {
|
||||
self.writer
|
||||
.write_all(e.0.inner.description().as_bytes())
|
||||
.await?;
|
||||
self.writer.write_all(" (".as_bytes()).await?;
|
||||
self.writer.write_all(e.0.inner.as_str().as_bytes()).await?;
|
||||
self.writer.write_all(")".as_bytes()).await?;
|
||||
if !e.0.keys.is_empty() {
|
||||
self.writer
|
||||
.write_all(if self.multiline { "\n" } else { " { " }.as_bytes())
|
||||
.await?;
|
||||
|
||||
self.write_keys(&e.0.keys, &[], indent + 1).await?;
|
||||
|
||||
if !self.multiline {
|
||||
self.writer.write_all(" }".as_bytes()).await?;
|
||||
}
|
||||
} else if self.multiline {
|
||||
self.writer.write_all("\n".as_bytes()).await?;
|
||||
}
|
||||
}
|
||||
Value::Array(arr) => {
|
||||
self.writer.write_all("[".as_bytes()).await?;
|
||||
for (pos, value) in arr.iter().enumerate() {
|
||||
if pos > 0 {
|
||||
self.writer.write_all(", ".as_bytes()).await?;
|
||||
}
|
||||
self.write_value(value, indent).await?;
|
||||
}
|
||||
self.writer.write_all("]".as_bytes()).await?;
|
||||
}
|
||||
Value::None => {
|
||||
self.writer.write_all("(null)".as_bytes()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.writer.flush().await
|
||||
}
|
||||
|
||||
pub fn update_writer(&mut self, writer: T) {
|
||||
self.writer = writer;
|
||||
}
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn as_code(&self) -> &'static str {
|
||||
match self {
|
||||
Color::Black => "\x1b[30m",
|
||||
Color::Red => "\x1b[31m",
|
||||
Color::Green => "\x1b[32m",
|
||||
Color::Yellow => "\x1b[33m",
|
||||
Color::Blue => "\x1b[34m",
|
||||
Color::Magenta => "\x1b[35m",
|
||||
Color::Cyan => "\x1b[36m",
|
||||
Color::White => "\x1b[37m",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_code_bold(&self) -> &'static str {
|
||||
match self {
|
||||
Color::Black => "\x1b[30;1m",
|
||||
Color::Red => "\x1b[31;1m",
|
||||
Color::Green => "\x1b[32;1m",
|
||||
Color::Yellow => "\x1b[33;1m",
|
||||
Color::Blue => "\x1b[34;1m",
|
||||
Color::Magenta => "\x1b[35;1m",
|
||||
Color::Cyan => "\x1b[36;1m",
|
||||
Color::White => "\x1b[37;1m",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset() -> &'static str {
|
||||
"\x1b[0m"
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Value {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Value::String(value) => value.fmt(f),
|
||||
Value::UInt(value) => value.fmt(f),
|
||||
Value::Int(value) => value.fmt(f),
|
||||
Value::Float(value) => value.fmt(f),
|
||||
Value::Timestamp(value) => value.fmt(f),
|
||||
Value::Duration(value) => value.fmt(f),
|
||||
Value::Bytes(value) => STANDARD.encode(value).fmt(f),
|
||||
Value::Bool(value) => value.fmt(f),
|
||||
Value::Ipv4(value) => value.fmt(f),
|
||||
Value::Ipv6(value) => value.fmt(f),
|
||||
Value::Event(value) => {
|
||||
"{".fmt(f)?;
|
||||
value.fmt(f)?;
|
||||
"}".fmt(f)
|
||||
}
|
||||
Value::Array(value) => {
|
||||
f.write_str("[")?;
|
||||
for (i, value) in value.iter().enumerate() {
|
||||
if i > 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
value.fmt(f)?;
|
||||
}
|
||||
f.write_str("]")
|
||||
}
|
||||
Value::None => "(null)".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.inner.description().fmt(f)?;
|
||||
" (".fmt(f)?;
|
||||
self.0.inner.as_str().fmt(f)?;
|
||||
")".fmt(f)?;
|
||||
|
||||
if !self.0.keys.is_empty() {
|
||||
f.write_str(": ")?;
|
||||
for (i, (key, value)) in self.0.keys.iter().enumerate() {
|
||||
if i > 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
key.as_str().fmt(f)?;
|
||||
f.write_str(" = ")?;
|
||||
value.fmt(f)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user