diff --git a/src/sinks/console.rs b/src/sinks/console.rs index 75fb4aba203f9..8475a05f588c2 100644 --- a/src/sinks/console.rs +++ b/src/sinks/console.rs @@ -25,13 +25,13 @@ pub struct ConsoleSinkConfig { #[serde(default)] pub target: Target, #[serde(default = "default_string_encoder")] - pub encoder: Box, + pub encoding: Box, } #[typetag::serde(name = "console")] impl crate::topology::config::SinkConfig for ConsoleSinkConfig { fn build(&self, acker: Acker) -> Result<(super::RouterSink, super::Healthcheck), String> { - let encoder = self.encoder.build(); + let encoder = self.encoding.build(); let output: Box = match self.target { Target::Stdout => Box::new(io::stdout()), diff --git a/src/sinks/encoders.rs b/src/sinks/encoders.rs index 8a002e4696e17..494f216ee9017 100644 --- a/src/sinks/encoders.rs +++ b/src/sinks/encoders.rs @@ -1,6 +1,8 @@ +mod dynamic; mod json; mod string; +pub use dynamic::DynamicEncoderConfig; pub use json::JsonEncoderConfig; pub use string::StringEncoderConfig; diff --git a/src/sinks/encoders/dynamic.rs b/src/sinks/encoders/dynamic.rs new file mode 100644 index 0000000000000..6a77d09d02a58 --- /dev/null +++ b/src/sinks/encoders/dynamic.rs @@ -0,0 +1,66 @@ +use super::{json::JsonEncoder, string::StringEncoder, Encoder, EncoderConfig}; +use crate::event::Event; +use bytes::Bytes; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct DynamicEncoderConfig {} + +#[typetag::serde(name = "dynamic")] +impl EncoderConfig for DynamicEncoderConfig { + fn build(&self) -> Box { + Box::new(DynamicEncoder { + json: JsonEncoder {}, + string: StringEncoder {}, + }) + } +} + +struct DynamicEncoder { + string: StringEncoder, + json: JsonEncoder, +} + +impl Encoder for DynamicEncoder { + fn encode(&self, event: Event) -> Bytes { + if event.as_log().is_structured() { + self.json.encode(event) + } else { + self.string.encode(event) + } + } +} + +#[cfg(test)] +mod tests { + use super::DynamicEncoderConfig; + use crate::event::Event; + use crate::sinks::encoders::EncoderConfig; + use std::collections::HashMap; + + #[test] + fn dynamic_encoder_uses_string() { + let encoder = DynamicEncoderConfig::default().build(); + let event = Event::from("hello world"); + let bytes = encoder.encode(event); + let msg = String::from_utf8(bytes.to_vec()).unwrap(); + + assert_eq!(msg, "hello world".to_string()); + } + + #[test] + fn dynamic_encoder_uses_json() { + let encoder = DynamicEncoderConfig::default().build(); + let mut event = Event::from("hello world"); + + event + .as_mut_log() + .insert_explicit("key".into(), "value".into()); + + let bytes = encoder.encode(event); + let map = serde_json::from_slice::>(&bytes[..]).unwrap(); + + assert_eq!(map["message"], "hello world".to_string()); + assert_eq!(map["key"], "value".to_string()); + } +} diff --git a/src/sinks/encoders/string.rs b/src/sinks/encoders/string.rs index d9687f66dbc7c..f97313fa6017e 100644 --- a/src/sinks/encoders/string.rs +++ b/src/sinks/encoders/string.rs @@ -13,7 +13,7 @@ impl EncoderConfig for StringEncoderConfig { } } -struct StringEncoder {} +pub struct StringEncoder {} impl Encoder for StringEncoder { fn encode(&self, event: Event) -> Bytes {