use std::str::FromStr;
use failure_ext::SlogKVErrorKey;
use slog::Key;
use slog::Level;
#[derive(Debug, PartialEq, Eq)]
pub enum KVCategory {
Ignore,
Inline,
LevelLog(Level),
}
pub trait KVCategorizer {
fn categorize(&self, key: Key) -> KVCategory;
fn name(&self, key: Key) -> &'static str;
fn ignore(&self, key: Key) -> bool {
self.categorize(key) == KVCategory::Ignore
}
}
pub struct InlineCategorizer;
impl KVCategorizer for InlineCategorizer {
fn categorize(&self, _key: Key) -> KVCategory {
KVCategory::Inline
}
fn name(&self, key: Key) -> &'static str {
key
}
}
pub struct ErrorCategorizer;
impl KVCategorizer for ErrorCategorizer {
fn categorize(&self, key: Key) -> KVCategory {
match SlogKVErrorKey::from_str(key) {
Ok(SlogKVErrorKey::Error) => KVCategory::LevelLog(Level::Error),
Ok(SlogKVErrorKey::Cause) => KVCategory::LevelLog(Level::Debug),
Ok(SlogKVErrorKey::Backtrace) => KVCategory::LevelLog(Level::Trace),
Ok(SlogKVErrorKey::RootCause) | Err(()) => InlineCategorizer.categorize(key),
Ok(SlogKVErrorKey::ErrorDebug) => KVCategory::LevelLog(Level::Debug),
}
}
fn name(&self, key: Key) -> &'static str {
match SlogKVErrorKey::from_str(key) {
Ok(SlogKVErrorKey::Error) => "Error",
Ok(SlogKVErrorKey::Cause) => "Caused by",
Ok(SlogKVErrorKey::Backtrace) => "Originated in",
Ok(SlogKVErrorKey::RootCause) => "Root cause",
Ok(SlogKVErrorKey::ErrorDebug) => "Debug context",
Err(()) => InlineCategorizer.name(key),
}
}
}
pub struct FacebookCategorizer;
impl KVCategorizer for FacebookCategorizer {
fn categorize(&self, key: Key) -> KVCategory {
match key {
"hostname" => KVCategory::Ignore,
_ => ErrorCategorizer.categorize(key),
}
}
fn name(&self, key: Key) -> &'static str {
ErrorCategorizer.name(key)
}
}
#[cfg(test)]
mod tests {
use anyhow::Error;
use failure_ext::SlogKVError;
use itertools::assert_equal;
use slog::b;
use slog::record;
use slog::KV;
use thiserror::Error;
use super::*;
use crate::collector_serializer::CollectorSerializer;
#[derive(Error, Debug)]
enum TestError {
#[error("my error #{0} displayed")]
MyError(usize),
}
#[test]
fn test_inline() {
let categorizer = InlineCategorizer;
let values = vec!["test", "test2"];
for v in values {
assert_eq!(categorizer.categorize(v), KVCategory::Inline);
assert_eq!(categorizer.name(v), v);
}
}
#[test]
fn test_error() {
let err = Error::from(TestError::MyError(0))
.context(TestError::MyError(1))
.context(TestError::MyError(2));
let debug = format!("{err:#?}");
let categorizer = ErrorCategorizer;
let mut serializer = CollectorSerializer::new(&categorizer);
SlogKVError(err)
.serialize(
&record!(Level::Info, "test", &format_args!(""), b!()),
&mut serializer,
)
.expect("failed to serialize");
assert_equal(
serializer.into_inner(),
vec![
("error", "my error #2 displayed".to_owned()),
("error_debug", debug),
("cause", "my error #1 displayed".to_owned()),
("cause", "my error #0 displayed".to_owned()),
("root_cause", "my error #0 displayed".to_owned()),
],
);
}
}