1#![allow(missing_docs)]
2use vector_lib::configurable::configurable_component;
3
4use crate::event::Event;
5
6mod datadog_search;
7pub(crate) mod is_log;
8pub(crate) mod is_metric;
9pub(crate) mod is_trace;
10mod vrl;
11
12pub use self::{
13 datadog_search::{DatadogSearchConfig, DatadogSearchRunner},
14 vrl::VrlConfig,
15};
16use self::{
17 is_log::{check_is_log, check_is_log_with_context},
18 is_metric::{check_is_metric, check_is_metric_with_context},
19 is_trace::{check_is_trace, check_is_trace_with_context},
20 vrl::Vrl,
21};
22
23#[derive(Debug, Clone)]
24#[allow(clippy::large_enum_variant)]
25pub enum Condition {
26 IsLog,
28
29 IsMetric,
31
32 IsTrace,
34
35 Vrl(Vrl),
37
38 DatadogSearch(DatadogSearchRunner),
40
41 AlwaysPass,
45
46 AlwaysFail,
50}
51
52impl Condition {
53 #[allow(dead_code)]
57 pub fn check(&self, e: Event) -> (bool, Event) {
58 match self {
59 Condition::IsLog => check_is_log(e),
60 Condition::IsMetric => check_is_metric(e),
61 Condition::IsTrace => check_is_trace(e),
62 Condition::Vrl(x) => x.check(e),
63 Condition::DatadogSearch(x) => x.check(e),
64 Condition::AlwaysPass => (true, e),
65 Condition::AlwaysFail => (false, e),
66 }
67 }
68
69 pub(crate) fn check_with_context(&self, e: Event) -> (Result<(), String>, Event) {
74 match self {
75 Condition::IsLog => check_is_log_with_context(e),
76 Condition::IsMetric => check_is_metric_with_context(e),
77 Condition::IsTrace => check_is_trace_with_context(e),
78 Condition::Vrl(x) => x.check_with_context(e),
79 Condition::DatadogSearch(x) => x.check_with_context(e),
80 Condition::AlwaysPass => (Ok(()), e),
81 Condition::AlwaysFail => (Ok(()), e),
82 }
83 }
84}
85
86#[configurable_component]
98#[derive(Clone, Debug)]
99#[serde(tag = "type", rename_all = "snake_case")]
100pub enum ConditionConfig {
101 #[configurable(metadata(docs::hidden))]
103 IsLog,
104
105 #[configurable(metadata(docs::hidden))]
107 IsMetric,
108
109 #[configurable(metadata(docs::hidden))]
111 IsTrace,
112
113 Vrl(VrlConfig),
115
116 DatadogSearch(DatadogSearchConfig),
118}
119
120impl ConditionConfig {
121 pub fn build(
122 &self,
123 enrichment_tables: &vector_lib::enrichment::TableRegistry,
124 ) -> crate::Result<Condition> {
125 match self {
126 ConditionConfig::IsLog => Ok(Condition::IsLog),
127 ConditionConfig::IsMetric => Ok(Condition::IsMetric),
128 ConditionConfig::IsTrace => Ok(Condition::IsTrace),
129 ConditionConfig::Vrl(x) => x.build(enrichment_tables),
130 ConditionConfig::DatadogSearch(x) => x.build(enrichment_tables),
131 }
132 }
133}
134
135pub trait Conditional: std::fmt::Debug {
136 fn check(&self, event: Event) -> (bool, Event);
140
141 fn check_with_context(&self, e: Event) -> (Result<(), String>, Event) {
146 let (result, event) = self.check(e);
147 if result {
148 (Ok(()), event)
149 } else {
150 (Err("condition failed".into()), event)
151 }
152 }
153}
154
155pub trait ConditionalConfig: std::fmt::Debug + Send + Sync + dyn_clone::DynClone {
156 fn build(
157 &self,
158 enrichment_tables: &vector_lib::enrichment::TableRegistry,
159 ) -> crate::Result<Condition>;
160}
161
162dyn_clone::clone_trait_object!(ConditionalConfig);
163
164#[configurable_component]
183#[derive(Clone, Debug)]
184#[configurable(metadata(docs::type_override = "condition"))]
185#[serde(untagged)]
186pub enum AnyCondition {
187 String(String),
189
190 Map(ConditionConfig),
192}
193
194impl AnyCondition {
195 pub fn build(
196 &self,
197 enrichment_tables: &vector_lib::enrichment::TableRegistry,
198 ) -> crate::Result<Condition> {
199 match self {
200 AnyCondition::String(s) => {
201 let vrl_config = VrlConfig {
202 source: s.clone(),
203 runtime: Default::default(),
204 };
205 vrl_config.build(enrichment_tables)
206 }
207 AnyCondition::Map(m) => m.build(enrichment_tables),
208 }
209 }
210}
211
212impl From<ConditionConfig> for AnyCondition {
213 fn from(config: ConditionConfig) -> Self {
214 Self::Map(config)
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use indoc::indoc;
221 use serde::Deserialize;
222
223 use super::*;
224
225 #[derive(Deserialize, Debug)]
226 struct Test {
227 condition: AnyCondition,
228 }
229
230 #[test]
231 fn deserialize_anycondition_default() {
232 let conf: Test = toml::from_str(r#"condition = ".nork == false""#).unwrap();
233 assert_eq!(
234 r#"String(".nork == false")"#,
235 format!("{:?}", conf.condition)
236 )
237 }
238
239 #[test]
240 fn deserialize_anycondition_vrl() {
241 let conf: Test = toml::from_str(indoc! {r#"
242 condition.type = "vrl"
243 condition.source = '.nork == true'
244 "#})
245 .unwrap();
246
247 assert_eq!(
248 r#"Map(Vrl(VrlConfig { source: ".nork == true", runtime: Ast }))"#,
249 format!("{:?}", conf.condition)
250 )
251 }
252}