use crate::color::HexColor;
use crate::config::Config;
use crate::level::Level;
use chrono::Local;
use serde::Serialize;
pub struct RenderContext<'a> {
pub level: Level,
pub tag: &'a str,
pub pid: Option<u32>,
pub message: &'a str,
pub fields: &'a [(String, String)],
pub use_color: bool,
pub use_emoji: bool,
pub color_override: Option<HexColor>,
pub emoji_override: Option<&'a str>,
}
#[derive(Serialize)]
struct JsonLine<'a> {
timestamp: String,
level: &'a str,
severity: u8,
tag: &'a str,
pid: Option<u32>,
message: &'a str,
fields: std::collections::BTreeMap<&'a str, &'a str>,
}
pub fn render_console(ctx: &RenderContext, config: &Config) -> String {
let now = Local::now();
let timestamp = now.format(&config.general.timestamp_format).to_string();
let emoji = if ctx.use_emoji {
ctx.emoji_override
.unwrap_or_else(|| config.emoji.for_level(ctx.level))
} else {
""
};
let level_label = ctx.level.label();
let pid_str = ctx.pid.map(|p| format!("[{p}]")).unwrap_or_default();
let tag_with_pid = format!("{}{}", ctx.tag, pid_str);
let mut fields_str = String::new();
if !ctx.fields.is_empty() {
fields_str.push(' ');
fields_str.push_str(
&ctx.fields
.iter()
.map(|(k, v)| format!("{k}={v}"))
.collect::<Vec<_>>()
.join(" "),
);
}
let rendered_message = format!("{}{}", ctx.message, fields_str);
let body = config
.output
.template
.replace("{timestamp}", ×tamp)
.replace("{emoji}", emoji)
.replace("{level}", level_label)
.replace("{tag}", &tag_with_pid)
.replace("{message}", &rendered_message);
let body = body.replace(" ", " ").trim_start().to_string();
if !ctx.use_color {
return body;
}
let color = ctx
.color_override
.unwrap_or_else(|| config.colors.for_level(ctx.level));
color.paint(&body)
}
pub fn render_json(ctx: &RenderContext) -> serde_json::Result<String> {
let now = Local::now();
let line = JsonLine {
timestamp: now.to_rfc3339_opts(chrono::SecondsFormat::Millis, false),
level: ctx.level.as_str(),
severity: ctx.level.severity(),
tag: ctx.tag,
pid: ctx.pid,
message: ctx.message,
fields: ctx
.fields
.iter()
.map(|(k, v)| (k.as_str(), v.as_str()))
.collect(),
};
serde_json::to_string(&line)
}