in src/flowgger/encoder/gelf_encoder.rs [59:115]
fn encode(&self, record: Record) -> Result<Vec<u8>, &'static str> {
let mut map = ObjectBuilder::new()
.insert("version".to_owned(), Value::String("1.1".to_owned()))
.insert(
"host".to_owned(),
Value::String(if record.hostname.is_empty() {
"unknown".to_owned()
} else {
record.hostname
}),
)
.insert(
"short_message".to_owned(),
Value::String(record.msg.unwrap_or_else(|| "-".to_owned())),
)
.insert("timestamp".to_owned(), Value::F64(record.ts));
if let Some(severity) = record.severity {
map = map.insert("level".to_owned(), Value::U64(u64::from(severity)));
}
if let Some(full_msg) = record.full_msg {
map = map.insert("full_message".to_owned(), Value::String(full_msg));
}
if let Some(appname) = record.appname {
map = map.insert("application_name".to_owned(), Value::String(appname));
}
if let Some(procid) = record.procid {
map = map.insert("process_id".to_owned(), Value::String(procid));
}
if let Some(sd_vec) = record.sd {
for &ref sd in &sd_vec {
// Warning: Gelf doesn't have a concept of structued data. In case there are
// several, all their attributes will be aded as fields. So if several structured
// data have the same key, only the last value will show as it will overwrite the
// others. We could use the sd_id to prefix the field to sove this but this is a
// breaking change.
if let Some(sd_id) = &sd.sd_id {
map = map.insert("sd_id".to_owned(), Value::String(sd_id.to_string()));
}
for (name, value) in &sd.pairs {
let value = match value {
SDValue::String(value) => Value::String(value.to_string()),
SDValue::Bool(value) => Value::Bool(*value),
SDValue::F64(value) => Value::F64(*value),
SDValue::I64(value) => Value::I64(*value),
SDValue::U64(value) => Value::U64(*value),
SDValue::Null => Value::Null,
};
map = map.insert(name, value);
}
}
}
for (name, value) in self.extra.iter().cloned() {
map = map.insert(name, Value::String(value));
}
let json = serde_json::to_vec(&map.build()).or(Err("Unable to serialize to JSON"))?;
Ok(json)
}