use serde::{Deserialize, Serialize};
use slog::{OwnedKVList, Record, KV};
use std::cell::Cell;
use std::fmt::{self, Debug, Display};
use std::sync::Arc;
pub trait MsgFormat: Sync + Send + Debug {
fn fmt(&self, f: &mut fmt::Formatter, record: &Record, values: &OwnedKVList) -> slog::Result;
fn to_string(&self, record: &Record, values: &OwnedKVList) -> slog::Result<String> {
struct ClosureAsDisplay<F: Fn(&mut fmt::Formatter) -> fmt::Result>(F);
impl<F: Fn(&mut fmt::Formatter) -> fmt::Result> Display for ClosureAsDisplay<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0(f)
}
}
let result: Cell<Option<slog::Error>> = Cell::new(None);
let s = ClosureAsDisplay(|f| {
if let Err(e) = MsgFormat::fmt(self, f, record, values) {
result.set(Some(e));
}
Ok(())
})
.to_string();
if let Some(e) = result.take() {
Err(e)
} else {
Ok(s)
}
}
}
impl<T: MsgFormat + ?Sized> MsgFormat for &T {
fn fmt(&self, f: &mut fmt::Formatter, record: &Record, values: &OwnedKVList) -> slog::Result {
MsgFormat::fmt(&**self, f, record, values)
}
}
impl<T: MsgFormat + ?Sized> MsgFormat for Box<T> {
fn fmt(&self, f: &mut fmt::Formatter, record: &Record, values: &OwnedKVList) -> slog::Result {
MsgFormat::fmt(&**self, f, record, values)
}
}
impl<T: MsgFormat + ?Sized> MsgFormat for Arc<T> {
fn fmt(&self, f: &mut fmt::Formatter, record: &Record, values: &OwnedKVList) -> slog::Result {
MsgFormat::fmt(&**self, f, record, values)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct BasicMsgFormat;
impl MsgFormat for BasicMsgFormat {
fn fmt(&self, f: &mut fmt::Formatter, record: &Record, _: &OwnedKVList) -> slog::Result {
write!(f, "{}", record.msg())?;
Ok(())
}
}
pub struct CustomMsgFormat<
T: Fn(&mut fmt::Formatter, &Record, &OwnedKVList) -> slog::Result + Send + Sync,
>(pub T);
impl<T: Fn(&mut fmt::Formatter, &Record, &OwnedKVList) -> slog::Result + Send + Sync> MsgFormat
for CustomMsgFormat<T>
{
fn fmt(&self, f: &mut fmt::Formatter, record: &Record, values: &OwnedKVList) -> slog::Result {
self.0(f, record, values)
}
}
impl<T: Fn(&mut fmt::Formatter, &Record, &OwnedKVList) -> slog::Result + Send + Sync> Debug
for CustomMsgFormat<T>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CustomMsgFormat").finish()
}
}
struct Rfc5424LikeValueEscaper<W: fmt::Write>(W);
impl<W: fmt::Write> fmt::Write for Rfc5424LikeValueEscaper<W> {
fn write_str(&mut self, mut s: &str) -> fmt::Result {
while let Some(index) = s.find(|c| c == '\\' || c == '"' || c == ']') {
if index != 0 {
self.0.write_str(&s[..index])?;
}
self.write_char(s.as_bytes()[index] as char)?;
if s.len() >= index {
s = &s[(index + 1)..];
} else {
s = "";
break;
}
}
if !s.is_empty() {
self.0.write_str(s)?;
}
Ok(())
}
fn write_char(&mut self, c: char) -> fmt::Result {
match c {
'\\' => self.0.write_str(r"\\"),
'"' => self.0.write_str("\\\""),
']' => self.0.write_str("\\]"),
_ => write!(self.0, "{}", c),
}
}
}
#[test]
fn test_rfc_5424_like_value_escaper() {
use std::iter;
fn case(input: &str, expected_output: &str) {
let mut e = Rfc5424LikeValueEscaper(String::new());
fmt::Write::write_str(&mut e, input).unwrap();
assert_eq!(e.0, expected_output);
}
for c in &['\\', '"', ']'] {
let ec = format!("\\{}", c);
{
let input = format!("{}", c);
case(&*input, &*ec);
}
for at_start_count in 0..=2 {
for at_mid_count in 0..=2 {
for at_end_count in 0..=2 {
let mut input = String::new();
let mut expected_output = String::new();
input.extend(iter::repeat(c).take(at_start_count));
expected_output.extend(iter::repeat(&*ec).take(at_start_count));
input.push_str("foo");
expected_output.push_str("foo");
input.extend(iter::repeat(c).take(at_mid_count));
expected_output.extend(iter::repeat(&*ec).take(at_mid_count));
input.push_str("bar");
expected_output.push_str("bar");
input.extend(iter::repeat(c).take(at_end_count));
expected_output.extend(iter::repeat(&*ec).take(at_end_count));
case(&*input, &*expected_output);
}
}
}
}
case("", "");
case("foo", "foo");
case("[foo]", "[foo\\]");
case("\\\"]", "\\\\\\\"\\]"); }
#[derive(Clone, Copy, Debug, Default)]
pub struct DefaultMsgFormat;
impl MsgFormat for DefaultMsgFormat {
fn fmt(&self, f: &mut fmt::Formatter, record: &Record, values: &OwnedKVList) -> slog::Result {
struct SerializerImpl<'a, 'b> {
f: &'a mut fmt::Formatter<'b>,
is_first_kv: bool,
}
impl<'a, 'b> SerializerImpl<'a, 'b> {
fn new(f: &'a mut fmt::Formatter<'b>) -> Self {
Self {
f,
is_first_kv: true,
}
}
fn finish(&mut self) -> slog::Result {
if !self.is_first_kv {
write!(self.f, "]")?;
}
Ok(())
}
}
impl<'a, 'b> slog::Serializer for SerializerImpl<'a, 'b> {
fn emit_arguments(&mut self, key: slog::Key, val: &fmt::Arguments) -> slog::Result {
use fmt::Write;
self.f
.write_str(if self.is_first_kv { " [" } else { " " })?;
self.is_first_kv = false;
write!(self.f, "{}=\"", key)?;
write!(Rfc5424LikeValueEscaper(&mut self.f), "{}", val)?;
self.f.write_char('"')?;
Ok(())
}
}
write!(f, "{}", record.msg())?;
{
let mut serializer = SerializerImpl::new(f);
values.serialize(record, &mut serializer)?;
record.kv().serialize(record, &mut serializer)?;
serializer.finish()?;
}
Ok(())
}
}
#[test]
fn test_default_msg_format() {
use slog::Level;
let result = DefaultMsgFormat
.to_string(
&record!(
Level::Info,
"",
&format_args!("Hello, world!"),
b!("key1" => "value1")
),
&o!("key2" => "value2").into(),
)
.expect("formatting failed");
assert!(
result == "Hello, world! [key1=\"value1\" key2=\"value2\"]"
|| result == "Hello, world! [key2=\"value2\" key1=\"value1\"]"
);
}
#[derive(Default, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[non_exhaustive]
#[serde(rename_all = "snake_case")]
pub enum MsgFormatConfig {
#[default]
Default,
Basic,
}
impl From<MsgFormatConfig> for Arc<dyn MsgFormat> {
fn from(conf: MsgFormatConfig) -> Self {
Self::from(&conf)
}
}
impl From<&MsgFormatConfig> for Arc<dyn MsgFormat> {
fn from(conf: &MsgFormatConfig) -> Self {
match *conf {
MsgFormatConfig::Default => Arc::new(DefaultMsgFormat),
MsgFormatConfig::Basic => Arc::new(BasicMsgFormat),
}
}
}