diff --git a/.meta/_partials/_conditions.toml b/.meta/_partials/_conditions.toml index 7fbdbafc9c8a3..70d6acda14913 100644 --- a/.meta/_partials/_conditions.toml +++ b/.meta/_partials/_conditions.toml @@ -1,11 +1,10 @@ [<%= namespace %>.type] type = "string" required = true -examples = ["check_fields"] +examples = ["check_fields", "is_log", "is_metric"] common = true description = """\ -The type of the condition to execute. Currently only the `check_fields` type is \ -available.\ +The type of the condition to execute.\ """ [<%= namespace %>."``.eq"] @@ -14,6 +13,7 @@ examples = [ { "message.eq" = "this is the content to match against" } ] common = true +relevant_when = {type = "check_fields"} description = """\ Check whether a fields contents exactly matches the value specified.\ """ @@ -24,6 +24,7 @@ examples = [ { "method.neq" = "POST" } ] common = true +relevant_when = {type = "check_fields"} description = """\ Check whether a fields contents does not match the value specified.\ """ @@ -34,6 +35,7 @@ examples = [ { "host.exists" = true } ] common = true +relevant_when = {type = "check_fields"} description = """\ Check whether a field exists or does not exist, depending on the provided value\ being `true` or `false` respectively.\ diff --git a/config/vector.spec.toml b/config/vector.spec.toml index 2768bed35dfb6..bd8ede651a58d 100644 --- a/config/vector.spec.toml +++ b/config/vector.spec.toml @@ -1823,18 +1823,20 @@ end [transforms.swimlanes.lanes] [transforms.swimlanes.lanes.``] - # The type of the condition to execute. Currently only the `check_fields` type - # is available. + # The type of the condition to execute. # # * required # * type: string type = "check_fields" + type = "is_log" + type = "is_metric" # Check whether a fields contents exactly matches the value specified. # # * optional # * no default # * type: string + # * relevant when type = "check_fields" "message.eq" = "this is the content to match against" # Check whether a field exists or does not exist, depending on the provided @@ -1843,6 +1845,7 @@ end # * optional # * no default # * type: bool + # * relevant when type = "check_fields" "host.exists" = true # Check whether a fields contents does not match the value specified. @@ -1850,6 +1853,7 @@ end # * optional # * no default # * type: string + # * relevant when type = "check_fields" "method.neq" = "POST" # Accepts and outputs `log` events allowing you to tokenize a field's value by splitting on white space, ignoring special wrapping characters, and zip the tokens into ordered field names. diff --git a/src/conditions/is_log.rs b/src/conditions/is_log.rs new file mode 100644 index 0000000000000..0d874398342ac --- /dev/null +++ b/src/conditions/is_log.rs @@ -0,0 +1,71 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + conditions::{Condition, ConditionConfig, ConditionDescription}, + Event, +}; + +//------------------------------------------------------------------------------ + +#[derive(Deserialize, Serialize, Debug, Default, Clone)] +pub struct IsLogConfig {} + +inventory::submit! { + ConditionDescription::new::("is_log") +} + +#[typetag::serde(name = "is_log")] +impl ConditionConfig for IsLogConfig { + fn build(&self) -> crate::Result> { + Ok(Box::new(IsLog {})) + } +} + +//------------------------------------------------------------------------------ + +pub struct IsLog {} + +impl Condition for IsLog { + fn check(&self, e: &Event) -> bool { + match e { + Event::Log(_) => true, + _ => false, + } + } + + fn check_with_context(&self, e: &Event) -> Result<(), String> { + if self.check(e) { + Ok(()) + } else { + Err("event is not a log type".to_string()) + } + } +} + +//------------------------------------------------------------------------------ + +#[cfg(test)] +mod test { + use super::*; + use crate::{ + event::metric::{Metric, MetricKind, MetricValue}, + Event, + }; + + #[test] + fn is_log_basic() { + let cond = IsLogConfig {}.build().unwrap(); + + assert_eq!(cond.check(&Event::from("just a log")), true); + assert_eq!( + cond.check(&Event::from(Metric { + name: "test metric".to_string(), + timestamp: None, + tags: None, + kind: MetricKind::Incremental, + value: MetricValue::Counter { value: 1.0 }, + })), + false + ); + } +} diff --git a/src/conditions/is_metric.rs b/src/conditions/is_metric.rs new file mode 100644 index 0000000000000..67f0125b2a1e3 --- /dev/null +++ b/src/conditions/is_metric.rs @@ -0,0 +1,71 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + conditions::{Condition, ConditionConfig, ConditionDescription}, + Event, +}; + +//------------------------------------------------------------------------------ + +#[derive(Deserialize, Serialize, Debug, Default, Clone)] +pub struct IsMetricConfig {} + +inventory::submit! { + ConditionDescription::new::("is_metric") +} + +#[typetag::serde(name = "is_metric")] +impl ConditionConfig for IsMetricConfig { + fn build(&self) -> crate::Result> { + Ok(Box::new(IsMetric {})) + } +} + +//------------------------------------------------------------------------------ + +pub struct IsMetric {} + +impl Condition for IsMetric { + fn check(&self, e: &Event) -> bool { + match e { + Event::Metric(_) => true, + _ => false, + } + } + + fn check_with_context(&self, e: &Event) -> Result<(), String> { + if self.check(e) { + Ok(()) + } else { + Err("event is not a metric type".to_string()) + } + } +} + +//------------------------------------------------------------------------------ + +#[cfg(test)] +mod test { + use super::*; + use crate::{ + event::metric::{Metric, MetricKind, MetricValue}, + Event, + }; + + #[test] + fn is_metric_basic() { + let cond = IsMetricConfig {}.build().unwrap(); + + assert_eq!(cond.check(&Event::from("just a log")), false); + assert_eq!( + cond.check(&Event::from(Metric { + name: "test metric".to_string(), + timestamp: None, + tags: None, + kind: MetricKind::Incremental, + value: MetricValue::Counter { value: 1.0 }, + })), + true + ); + } +} diff --git a/src/conditions/mod.rs b/src/conditions/mod.rs index cd45059df6306..f70b0e8b010ac 100644 --- a/src/conditions/mod.rs +++ b/src/conditions/mod.rs @@ -3,6 +3,8 @@ use crate::Event; use inventory; pub mod check_fields; +pub mod is_log; +pub mod is_metric; pub use check_fields::CheckFieldsConfig; diff --git a/tests/behavior/transforms/swimlanes.toml b/tests/behavior/transforms/swimlanes.toml index 609198d2b23d2..975173fab2285 100644 --- a/tests/behavior/transforms/swimlanes.toml +++ b/tests/behavior/transforms/swimlanes.toml @@ -5,6 +5,8 @@ "message.eq" = "test swimlane 1" [transforms.foo.lanes.second] "message.eq" = "test swimlane 2" + [transforms.foo.lanes.third] + type = "is_log" [transforms.bar] inputs = ["foo.first"] @@ -31,6 +33,11 @@ "message.equals" = "test swimlane 1" "new_field.equals" = "new field added" + [[tests.outputs]] + extract_from = "foo.third" + [[tests.outputs.conditions]] + "message.equals" = "test swimlane 1" + [[tests]] name = "swimlanes test 2" no_outputs_from = [ "foo.first", "bar" ] @@ -43,3 +50,8 @@ extract_from = "foo.second" [[tests.outputs.conditions]] "message.equals" = "test swimlane 2" + + [[tests.outputs]] + extract_from = "foo.third" + [[tests.outputs.conditions]] + "message.equals" = "test swimlane 2" diff --git a/website/docs/reference/tests.md b/website/docs/reference/tests.md index 318bcdfecefac..e5ea062f77e66 100644 --- a/website/docs/reference/tests.md +++ b/website/docs/reference/tests.md @@ -637,7 +637,7 @@ A table that defines a collection of conditions to check against the output of a groups={[]} name={"``.eq"} path={"outputs.conditions"} - relevantWhen={null} + relevantWhen={{"type":"check_fields"}} required={false} templateable={false} type={"string"} @@ -660,7 +660,7 @@ Check whether a fields contents exactly matches the value specified. groups={[]} name={"``.exists"} path={"outputs.conditions"} - relevantWhen={null} + relevantWhen={{"type":"check_fields"}} required={false} templateable={false} type={"bool"} @@ -683,7 +683,7 @@ Check whether a field exists or does not exist, depending on the provided valueb groups={[]} name={"``.neq"} path={"outputs.conditions"} - relevantWhen={null} + relevantWhen={{"type":"check_fields"}} required={false} templateable={false} type={"string"} @@ -702,7 +702,7 @@ Check whether a fields contents does not match the value specified. common={true} defaultValue={null} enumValues={null} - examples={["check_fields"]} + examples={["check_fields","is_log","is_metric"]} groups={[]} name={"type"} path={"outputs.conditions"} @@ -715,7 +715,7 @@ Check whether a fields contents does not match the value specified. ##### type -The type of the condition to execute. Currently only the `check_fields` type is available. +The type of the condition to execute. diff --git a/website/docs/reference/transforms/swimlanes.md b/website/docs/reference/transforms/swimlanes.md index 0c93772d51e66..423884a791e82 100644 --- a/website/docs/reference/transforms/swimlanes.md +++ b/website/docs/reference/transforms/swimlanes.md @@ -105,7 +105,7 @@ The identifier of a swimlane. groups={[]} name={"``.eq"} path={"lanes.``"} - relevantWhen={null} + relevantWhen={{"type":"check_fields"}} required={false} templateable={false} type={"string"} @@ -128,7 +128,7 @@ Check whether a fields contents exactly matches the value specified. groups={[]} name={"``.exists"} path={"lanes.``"} - relevantWhen={null} + relevantWhen={{"type":"check_fields"}} required={false} templateable={false} type={"bool"} @@ -151,7 +151,7 @@ Check whether a field exists or does not exist, depending on the provided valueb groups={[]} name={"``.neq"} path={"lanes.``"} - relevantWhen={null} + relevantWhen={{"type":"check_fields"}} required={false} templateable={false} type={"string"} @@ -170,7 +170,7 @@ Check whether a fields contents does not match the value specified. common={true} defaultValue={null} enumValues={null} - examples={["check_fields"]} + examples={["check_fields","is_log","is_metric"]} groups={[]} name={"type"} path={"lanes.``"} @@ -183,7 +183,7 @@ Check whether a fields contents does not match the value specified. ##### type -The type of the condition to execute. Currently only the `check_fields` type is available. +The type of the condition to execute.