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 pub fn check(&self, e: Event) -> (bool, Event) {
57 match self {
58 Condition::IsLog => check_is_log(e),
59 Condition::IsMetric => check_is_metric(e),
60 Condition::IsTrace => check_is_trace(e),
61 Condition::Vrl(x) => x.check(e),
62 Condition::DatadogSearch(x) => x.check(e),
63 Condition::AlwaysPass => (true, e),
64 Condition::AlwaysFail => (false, e),
65 }
66 }
67
68 pub(crate) fn check_with_context(&self, e: Event) -> (Result<(), String>, Event) {
73 match self {
74 Condition::IsLog => check_is_log_with_context(e),
75 Condition::IsMetric => check_is_metric_with_context(e),
76 Condition::IsTrace => check_is_trace_with_context(e),
77 Condition::Vrl(x) => x.check_with_context(e),
78 Condition::DatadogSearch(x) => x.check_with_context(e),
79 Condition::AlwaysPass => (Ok(()), e),
80 Condition::AlwaysFail => (Ok(()), e),
81 }
82 }
83}
84
85#[configurable_component]
97#[derive(Clone, Debug)]
98#[serde(tag = "type", rename_all = "snake_case")]
99pub enum ConditionConfig {
100 #[configurable(metadata(docs::hidden))]
102 IsLog,
103
104 #[configurable(metadata(docs::hidden))]
106 IsMetric,
107
108 #[configurable(metadata(docs::hidden))]
110 IsTrace,
111
112 Vrl(VrlConfig),
114
115 DatadogSearch(DatadogSearchConfig),
117}
118
119impl ConditionConfig {
120 pub fn build(
121 &self,
122 enrichment_tables: &vector_lib::enrichment::TableRegistry,
123 ) -> crate::Result<Condition> {
124 match self {
125 ConditionConfig::IsLog => Ok(Condition::IsLog),
126 ConditionConfig::IsMetric => Ok(Condition::IsMetric),
127 ConditionConfig::IsTrace => Ok(Condition::IsTrace),
128 ConditionConfig::Vrl(x) => x.build(enrichment_tables),
129 ConditionConfig::DatadogSearch(x) => x.build(enrichment_tables),
130 }
131 }
132}
133
134pub trait Conditional: std::fmt::Debug {
135 fn check(&self, event: Event) -> (bool, Event);
139
140 fn check_with_context(&self, e: Event) -> (Result<(), String>, Event) {
145 let (result, event) = self.check(e);
146 if result {
147 (Ok(()), event)
148 } else {
149 (Err("condition failed".into()), event)
150 }
151 }
152}
153
154pub trait ConditionalConfig: std::fmt::Debug + Send + Sync + dyn_clone::DynClone {
155 fn build(
156 &self,
157 enrichment_tables: &vector_lib::enrichment::TableRegistry,
158 ) -> crate::Result<Condition>;
159}
160
161dyn_clone::clone_trait_object!(ConditionalConfig);
162
163#[configurable_component]
182#[derive(Clone, Debug)]
183#[configurable(metadata(docs::type_override = "condition"))]
184#[serde(untagged)]
185pub enum AnyCondition {
186 String(String),
188
189 Map(ConditionConfig),
191}
192
193impl AnyCondition {
194 pub fn build(
195 &self,
196 enrichment_tables: &vector_lib::enrichment::TableRegistry,
197 ) -> crate::Result<Condition> {
198 match self {
199 AnyCondition::String(s) => {
200 let vrl_config = VrlConfig {
201 source: s.clone(),
202 runtime: Default::default(),
203 };
204 vrl_config.build(enrichment_tables)
205 }
206 AnyCondition::Map(m) => m.build(enrichment_tables),
207 }
208 }
209}
210
211impl From<ConditionConfig> for AnyCondition {
212 fn from(config: ConditionConfig) -> Self {
213 Self::Map(config)
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use indoc::indoc;
220 use serde::Deserialize;
221
222 use super::*;
223
224 #[derive(Deserialize, Debug)]
225 struct Test {
226 condition: AnyCondition,
227 }
228
229 #[test]
230 fn deserialize_anycondition_default() {
231 let conf: Test = toml::from_str(r#"condition = ".nork == false""#).unwrap();
232 assert_eq!(
233 r#"String(".nork == false")"#,
234 format!("{:?}", conf.condition)
235 )
236 }
237
238 #[test]
239 fn deserialize_anycondition_vrl() {
240 let conf: Test = toml::from_str(indoc! {r#"
241 condition.type = "vrl"
242 condition.source = '.nork == true'
243 "#})
244 .unwrap();
245
246 assert_eq!(
247 r#"Map(Vrl(VrlConfig { source: ".nork == true", runtime: Ast }))"#,
248 format!("{:?}", conf.condition)
249 )
250 }
251}