1#![allow(missing_docs)]
2use vector_lib::configurable::configurable_component;
3use vector_vrl_metrics::MetricsStorage;
4
5use crate::event::Event;
6
7mod datadog_search;
8pub(crate) mod is_log;
9pub(crate) mod is_metric;
10pub(crate) mod is_trace;
11mod vrl;
12
13pub use self::{
14 datadog_search::{DatadogSearchConfig, DatadogSearchRunner},
15 vrl::VrlConfig,
16};
17use self::{
18 is_log::{check_is_log, check_is_log_with_context},
19 is_metric::{check_is_metric, check_is_metric_with_context},
20 is_trace::{check_is_trace, check_is_trace_with_context},
21 vrl::Vrl,
22};
23
24#[derive(Debug, Clone)]
25#[allow(clippy::large_enum_variant)]
26pub enum Condition {
27 IsLog,
29
30 IsMetric,
32
33 IsTrace,
35
36 Vrl(Vrl),
38
39 DatadogSearch(DatadogSearchRunner),
41
42 AlwaysPass,
46
47 AlwaysFail,
51}
52
53impl Condition {
54 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 metrics_storage: &MetricsStorage,
125 ) -> crate::Result<Condition> {
126 match self {
127 ConditionConfig::IsLog => Ok(Condition::IsLog),
128 ConditionConfig::IsMetric => Ok(Condition::IsMetric),
129 ConditionConfig::IsTrace => Ok(Condition::IsTrace),
130 ConditionConfig::Vrl(x) => x.build(enrichment_tables, metrics_storage),
131 ConditionConfig::DatadogSearch(x) => x.build(enrichment_tables, metrics_storage),
132 }
133 }
134}
135
136pub trait Conditional: std::fmt::Debug {
137 fn check(&self, event: Event) -> (bool, Event);
141
142 fn check_with_context(&self, e: Event) -> (Result<(), String>, Event) {
147 let (result, event) = self.check(e);
148 if result {
149 (Ok(()), event)
150 } else {
151 (Err("condition failed".into()), event)
152 }
153 }
154}
155
156pub trait ConditionalConfig: std::fmt::Debug + Send + Sync + dyn_clone::DynClone {
157 fn build(
158 &self,
159 enrichment_tables: &vector_lib::enrichment::TableRegistry,
160 metrics_storage: &MetricsStorage,
161 ) -> crate::Result<Condition>;
162}
163
164dyn_clone::clone_trait_object!(ConditionalConfig);
165
166#[configurable_component]
185#[derive(Clone, Debug)]
186#[configurable(metadata(docs::type_override = "condition"))]
187#[serde(untagged)]
188pub enum AnyCondition {
189 String(String),
191
192 Map(ConditionConfig),
194}
195
196impl AnyCondition {
197 pub fn build(
198 &self,
199 enrichment_tables: &vector_lib::enrichment::TableRegistry,
200 metrics_storage: &MetricsStorage,
201 ) -> crate::Result<Condition> {
202 match self {
203 AnyCondition::String(s) => {
204 let vrl_config = VrlConfig {
205 source: s.clone(),
206 runtime: Default::default(),
207 };
208 vrl_config.build(enrichment_tables, metrics_storage)
209 }
210 AnyCondition::Map(m) => m.build(enrichment_tables, metrics_storage),
211 }
212 }
213}
214
215impl From<ConditionConfig> for AnyCondition {
216 fn from(config: ConditionConfig) -> Self {
217 Self::Map(config)
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use indoc::indoc;
224 use serde::Deserialize;
225
226 use super::*;
227
228 #[derive(Deserialize, Debug)]
229 struct Test {
230 condition: AnyCondition,
231 }
232
233 #[test]
234 fn deserialize_anycondition_default() {
235 let conf: Test = toml::from_str(r#"condition = ".nork == false""#).unwrap();
236 assert_eq!(
237 r#"String(".nork == false")"#,
238 format!("{:?}", conf.condition)
239 )
240 }
241
242 #[test]
243 fn deserialize_anycondition_vrl() {
244 let conf: Test = toml::from_str(indoc! {r#"
245 condition.type = "vrl"
246 condition.source = '.nork == true'
247 "#})
248 .unwrap();
249
250 assert_eq!(
251 r#"Map(Vrl(VrlConfig { source: ".nork == true", runtime: Ast }))"#,
252 format!("{:?}", conf.condition)
253 )
254 }
255}