mod color_compact;
mod compact;
mod json;
use ntime;
use std::io;
use crate::attributes;
use crate::constant::{ATTRIBUTE_KEY_TIME, ATTRIBUTE_KEY_TIMESTAMP};
use crate::sink::LogUpdate;
#[derive(Clone, Debug)]
pub enum OutputFormat {
Compact,
ColorCompact,
Json,
}
#[derive(Clone, Debug)]
pub enum FormatterError {
DelimiterNotAString,
}
impl OutputFormat {
pub fn name(&self) -> String {
match self {
Self::Compact => "compact",
Self::ColorCompact => "compact (w/console color)",
Self::Json => "JSON",
}
.into()
}
}
#[derive(Clone, Debug)]
pub struct FormatterConfig {
pub format: OutputFormat,
pub time_format: ntime::Format,
pub delimiter: Vec<u8>,
}
impl FormatterConfig {
pub fn default() -> Self {
compact::default_format_config()
}
pub fn default_compact() -> Self {
compact::default_format_config()
}
pub fn default_color() -> Self {
color_compact::default_format_config()
}
pub fn default_json() -> Self {
json::default_format_config()
}
}
#[derive(Clone, Debug)]
pub struct Formatter {
format: OutputFormat,
time_key: String,
time_format: ntime::Format,
delimiter: Vec<u8>,
}
impl Formatter {
pub fn new(conf: FormatterConfig) -> Self {
Self {
format: conf.format,
time_key: match &conf.time_format {
ntime::Format::TimestampSeconds | ntime::Format::TimestampMilliseconds => String::from(ATTRIBUTE_KEY_TIMESTAMP),
_ => String::from(ATTRIBUTE_KEY_TIME),
},
time_format: conf.time_format,
delimiter: conf.delimiter,
}
}
pub fn write<T: io::Write>(&self, out: &mut T, update: &LogUpdate, attrs: &attributes::Map) -> io::Result<()> {
match self.format {
OutputFormat::Compact => compact::write(out, &self.time_format, update, attrs),
OutputFormat::ColorCompact => color_compact::write(out, &self.time_format, update, attrs),
OutputFormat::Json => json::write(out, &self.time_format, &self.time_key, &update, attrs),
}
}
pub fn write_delimiter<T: io::Write>(&self, out: &mut T) -> io::Result<()> {
match out.write(self.delimiter.as_slice()) {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}
pub fn as_string(&self, update: &LogUpdate, attrs: &attributes::Map) -> String {
let mut out = Vec::new();
match self.write(&mut out, update, attrs) {
Ok(_) => (),
Err(e) => panic!("failed to convert log update {update:?} to string buffer: {e}"),
};
match String::from_utf8(out) {
Ok(s) => s,
Err(e) => panic!("failed to convert log update {update:?} to UTF8: {e}"),
}
}
pub fn delimiter_as_string(&self) -> Result<String, FormatterError> {
match String::from_utf8(self.delimiter.clone()) {
Ok(s) => Ok(s),
Err(_) => Err(FormatterError::DelimiterNotAString),
}
}
}
pub fn as_panic_string(update: &LogUpdate, attrs: &attributes::Map) -> String {
let formatter = Formatter::new(FormatterConfig {
format: OutputFormat::Compact,
..FormatterConfig::default_compact()
});
formatter.as_string(update, attrs)
}