relay_filter/
generic.rs

1//! Implements generic filtering based on the [`RuleCondition`] DSL.
2//!
3//! Multiple generic filters can be defined and they are going to be checked in FIFO order. The
4//! first one that matches, will result in the event being discarded with a [`FilterStatKey`]
5//! identifying the matching filter.
6
7use std::iter::FusedIterator;
8
9use crate::{FilterStatKey, GenericFilterConfig, GenericFiltersConfig, GenericFiltersMap};
10
11use relay_protocol::{Getter, RuleCondition};
12
13/// Maximum supported version of the generic filters schema.
14///
15/// If the version in the project config is higher, no generic filters are applied.
16const MAX_SUPPORTED_VERSION: u16 = 1;
17
18/// Returns whether the given generic config versions are supported.
19pub fn are_generic_filters_supported(
20    global_filters_version: Option<u16>,
21    project_filters_version: u16,
22) -> bool {
23    global_filters_version.is_none_or(|v| v <= MAX_SUPPORTED_VERSION)
24        && project_filters_version <= MAX_SUPPORTED_VERSION
25}
26
27/// Checks events by patterns in their error messages.
28fn matches<F: Getter>(item: &F, condition: Option<&RuleCondition>) -> bool {
29    // TODO: the condition DSL needs to be extended to support more complex semantics, such as
30    //  collections operations.
31    condition.is_some_and(|condition| condition.matches(item))
32}
33
34/// Filters events by any generic condition.
35///
36/// Note that conditions may have type-specific getter strings, e.g. `"event.some_field"`. In order
37/// to make such a generic filter apply to non-Event types, make sure that the [`Getter`] implementation
38/// for that type maps `"event.some_field"` to the corresponding field on that type.
39pub(crate) fn should_filter<F: Getter>(
40    item: &F,
41    project_filters: &GenericFiltersConfig,
42    global_filters: Option<&GenericFiltersConfig>,
43) -> Result<(), FilterStatKey> {
44    let filters = merge_generic_filters(
45        project_filters,
46        global_filters,
47        #[cfg(test)]
48        MAX_SUPPORTED_VERSION,
49    );
50
51    for filter_config in filters {
52        if filter_config.is_enabled && matches(item, filter_config.condition) {
53            return Err(FilterStatKey::GenericFilter(filter_config.id.to_owned()));
54        }
55    }
56
57    Ok(())
58}
59
60/// Returns an iterator that yields merged generic configs.
61///
62/// Since filters of project and global configs are complementary and don't
63/// provide much value in isolation, both versions must match
64/// [`MAX_SUPPORTED_VERSION`] to be compatible.  If filters aren't compatible,
65/// an empty iterator is returned.
66///
67/// If filters are compatible, an iterator over all filters is returned. This
68/// iterator yields filters according to the principles below:
69/// - Filters from project configs are evaluated before filters from global
70///   configs.
71/// - No duplicates: once a filter is evaluated (yielded or skipped), no filter
72///   with the same id is evaluated again.
73/// - If a filter with the same id exists in projects and global configs, both
74///   are merged and the filter is yielded. Values from the filter in the project
75///   config are prioritized.
76fn merge_generic_filters<'a>(
77    project: &'a GenericFiltersConfig,
78    global: Option<&'a GenericFiltersConfig>,
79    #[cfg(test)] max_supported_version: u16,
80) -> impl Iterator<Item = GenericFilterConfigRef<'a>> {
81    #[cfg(not(test))]
82    let max_supported_version = MAX_SUPPORTED_VERSION;
83
84    let is_supported = project.version <= max_supported_version
85        && global.is_none_or(|gf| gf.version <= max_supported_version);
86
87    is_supported
88        .then(|| {
89            DynamicGenericFiltersConfigIter::new(&project.filters, global.map(|gc| &gc.filters))
90        })
91        .into_iter()
92        .flatten()
93}
94
95/// Iterator over the generic filters of the project and global configs.
96struct DynamicGenericFiltersConfigIter<'a> {
97    /// Generic project filters.
98    project: &'a GenericFiltersMap,
99    /// Index of the next filter in project configs to evaluate.
100    project_index: usize,
101    /// Generic global filters.
102    global: Option<&'a GenericFiltersMap>,
103    /// Index of the next filter in global configs to evaluate.
104    global_index: usize,
105}
106
107impl<'a> DynamicGenericFiltersConfigIter<'a> {
108    pub fn new(project: &'a GenericFiltersMap, global: Option<&'a GenericFiltersMap>) -> Self {
109        DynamicGenericFiltersConfigIter {
110            project,
111            project_index: 0,
112            global,
113            global_index: 0,
114        }
115    }
116}
117
118impl<'a> Iterator for DynamicGenericFiltersConfigIter<'a> {
119    type Item = GenericFilterConfigRef<'a>;
120
121    fn next(&mut self) -> Option<Self::Item> {
122        if let Some((id, filter)) = self.project.get_index(self.project_index) {
123            self.project_index += 1;
124            let merged = merge_filters(filter, self.global.and_then(|gf| gf.get(id)));
125            return Some(merged);
126        }
127
128        loop {
129            let (id, filter) = self.global?.get_index(self.global_index)?;
130            self.global_index += 1;
131            if !self.project.contains_key(id) {
132                return Some(filter.into());
133            }
134        }
135    }
136}
137
138impl FusedIterator for DynamicGenericFiltersConfigIter<'_> {}
139
140/// Merges the two filters with the same id, prioritizing values from the primary.
141///
142/// It's assumed both filters share the same id. The returned filter will have
143/// the primary filter's ID.
144fn merge_filters<'a>(
145    primary: &'a GenericFilterConfig,
146    secondary: Option<&'a GenericFilterConfig>,
147) -> GenericFilterConfigRef<'a> {
148    GenericFilterConfigRef {
149        id: primary.id.as_str(),
150        is_enabled: primary.is_enabled,
151        condition: primary
152            .condition
153            .as_ref()
154            .or(secondary.and_then(|filter| filter.condition.as_ref())),
155    }
156}
157
158#[derive(Debug, Default, PartialEq)]
159struct GenericFilterConfigRef<'a> {
160    id: &'a str,
161    is_enabled: bool,
162    condition: Option<&'a RuleCondition>,
163}
164
165impl<'a> From<&'a GenericFilterConfig> for GenericFilterConfigRef<'a> {
166    fn from(value: &'a GenericFilterConfig) -> Self {
167        GenericFilterConfigRef {
168            id: value.id.as_str(),
169            is_enabled: value.is_enabled,
170            condition: value.condition.as_ref(),
171        }
172    }
173}
174
175#[cfg(test)]
176mod tests {
177
178    use super::*;
179
180    use relay_event_schema::protocol::{Event, LenientString};
181    use relay_protocol::{Annotated, FromValue as _};
182
183    fn mock_filters() -> GenericFiltersMap {
184        vec![
185            GenericFilterConfig {
186                id: "firstReleases".to_owned(),
187                is_enabled: true,
188                condition: Some(RuleCondition::eq("event.release", "1.0")),
189            },
190            GenericFilterConfig {
191                id: "helloTransactions".to_owned(),
192                is_enabled: true,
193                condition: Some(RuleCondition::eq("event.transaction", "/hello")),
194            },
195        ]
196        .into()
197    }
198
199    #[test]
200    fn test_should_filter_match_rules() {
201        let config = GenericFiltersConfig {
202            version: 1,
203            filters: mock_filters(),
204        };
205
206        // Matching first rule.
207        let event = Event {
208            release: Annotated::new(LenientString("1.0".to_owned())),
209            ..Default::default()
210        };
211        assert_eq!(
212            should_filter(&event, &config, None),
213            Err(FilterStatKey::GenericFilter("firstReleases".to_owned()))
214        );
215
216        // Matching second rule.
217        let event = Event {
218            transaction: Annotated::new("/hello".to_owned()),
219            ..Default::default()
220        };
221        assert_eq!(
222            should_filter(&event, &config, None),
223            Err(FilterStatKey::GenericFilter("helloTransactions".to_owned()))
224        );
225    }
226
227    #[test]
228    fn test_should_filter_fifo_match_rules() {
229        let config = GenericFiltersConfig {
230            version: 1,
231            filters: mock_filters(),
232        };
233
234        // Matching both rules (first is taken).
235        let event = Event {
236            release: Annotated::new(LenientString("1.0".to_owned())),
237            transaction: Annotated::new("/hello".to_owned()),
238            ..Default::default()
239        };
240        assert_eq!(
241            should_filter(&event, &config, None),
242            Err(FilterStatKey::GenericFilter("firstReleases".to_owned()))
243        );
244    }
245
246    #[test]
247    fn test_should_filter_match_no_rules() {
248        let config = GenericFiltersConfig {
249            version: 1,
250            filters: mock_filters(),
251        };
252
253        // Matching no rule.
254        let event = Event {
255            transaction: Annotated::new("/world".to_owned()),
256            ..Default::default()
257        };
258        assert_eq!(should_filter(&event, &config, None), Ok(()));
259    }
260
261    #[test]
262    fn test_should_filter_with_higher_config_version() {
263        let config = GenericFiltersConfig {
264            // We simulate receiving a higher configuration version, which we don't support.
265            version: MAX_SUPPORTED_VERSION + 1,
266            filters: mock_filters(),
267        };
268
269        let event = Event {
270            release: Annotated::new(LenientString("1.0".to_owned())),
271            transaction: Annotated::new("/hello".to_owned()),
272            ..Default::default()
273        };
274        assert_eq!(should_filter(&event, &config, None), Ok(()));
275    }
276
277    #[test]
278    fn test_should_filter_from_global_filters() {
279        let project = GenericFiltersConfig {
280            version: 1,
281            filters: vec![GenericFilterConfig {
282                id: "firstReleases".to_owned(),
283                is_enabled: true,
284                condition: Some(RuleCondition::eq("event.release", "1.0")),
285            }]
286            .into(),
287        };
288
289        let global = GenericFiltersConfig {
290            version: 1,
291            filters: vec![GenericFilterConfig {
292                id: "helloTransactions".to_owned(),
293                is_enabled: true,
294                condition: Some(RuleCondition::eq("event.transaction", "/hello")),
295            }]
296            .into(),
297        };
298
299        let event = Event {
300            transaction: Annotated::new("/hello".to_owned()),
301            ..Default::default()
302        };
303
304        assert_eq!(
305            should_filter(&event, &project, Some(&global)),
306            Err(FilterStatKey::GenericFilter("helloTransactions".to_owned()))
307        );
308    }
309
310    fn empty_filter() -> GenericFiltersConfig {
311        GenericFiltersConfig {
312            version: 1,
313            filters: GenericFiltersMap::new(),
314        }
315    }
316
317    /// Returns a complete and enabled [`GenericFiltersConfig`].
318    fn enabled_filter(id: &str) -> GenericFiltersConfig {
319        GenericFiltersConfig {
320            version: 1,
321            filters: vec![GenericFilterConfig {
322                id: id.to_owned(),
323                is_enabled: true,
324                condition: Some(RuleCondition::eq("event.exceptions", "myError")),
325            }]
326            .into(),
327        }
328    }
329
330    /// Returns an enabled flag of a [`GenericFiltersConfig`].
331    fn enabled_flag_filter(id: &str) -> GenericFiltersConfig {
332        GenericFiltersConfig {
333            version: 1,
334            filters: vec![GenericFilterConfig {
335                id: id.to_owned(),
336                is_enabled: true,
337                condition: None,
338            }]
339            .into(),
340        }
341    }
342
343    /// Returns a complete but disabled [`GenericFiltersConfig`].
344    fn disabled_filter(id: &str) -> GenericFiltersConfig {
345        GenericFiltersConfig {
346            version: 1,
347            filters: vec![GenericFilterConfig {
348                id: id.to_owned(),
349                is_enabled: false,
350                condition: Some(RuleCondition::eq("event.exceptions", "myError")),
351            }]
352            .into(),
353        }
354    }
355
356    /// Returns a disabled flag of a [`GenericFiltersConfig`].
357    fn disabled_flag_filter(id: &str) -> GenericFiltersConfig {
358        GenericFiltersConfig {
359            version: 1,
360            filters: vec![GenericFilterConfig {
361                id: id.to_owned(),
362                is_enabled: false,
363                condition: None,
364            }]
365            .into(),
366        }
367    }
368
369    #[test]
370    fn test_no_combined_when_unsupported_project_version() {
371        let mut project = enabled_filter("unsupported-project");
372        project.version = 2;
373        let global = enabled_filter("supported-global");
374        assert!(merge_generic_filters(&project, Some(&global), 1).eq(None.into_iter()));
375    }
376
377    #[test]
378    fn test_no_combined_when_unsupported_project_version_no_global() {
379        let mut project = enabled_filter("unsupported-project");
380        project.version = 2;
381        assert!(merge_generic_filters(&project, None, 1).eq(None.into_iter()));
382    }
383
384    #[test]
385    fn test_no_combined_when_unsupported_global_version() {
386        let project = enabled_filter("supported-project");
387        let mut global = enabled_filter("unsupported-global");
388        global.version = 2;
389        assert!(merge_generic_filters(&project, Some(&global), 1).eq(None.into_iter()));
390    }
391
392    #[test]
393    fn test_no_combined_when_unsupported_project_and_global_version() {
394        let mut project = enabled_filter("unsupported-project");
395        project.version = 2;
396        let mut global = enabled_filter("unsupported-global");
397        global.version = 2;
398        assert!(merge_generic_filters(&project, Some(&global), 1).eq(None.into_iter()));
399    }
400
401    #[test]
402    fn test_both_combined_when_supported_project_and_global_version() {
403        let project = enabled_filter("supported-project");
404        let global = enabled_filter("supported-global");
405        assert!(
406            merge_generic_filters(&project, Some(&global), 1).eq([
407                project.filters.first().unwrap().1.into(),
408                global.filters.first().unwrap().1.into()
409            ]
410            .into_iter())
411        );
412    }
413
414    #[test]
415    fn test_project_combined_when_duplicated_filter_project_and_global() {
416        let project = enabled_filter("filter");
417        let global = enabled_filter("filter");
418        assert!(
419            merge_generic_filters(&project, Some(&global), 1).eq([project
420                .filters
421                .first()
422                .unwrap()
423                .1
424                .into()]
425            .into_iter())
426        );
427    }
428
429    #[test]
430    fn test_no_combined_when_empty_project_and_global() {
431        let project = empty_filter();
432        let global = empty_filter();
433        assert!(merge_generic_filters(&project, Some(&global), 1).eq(None.into_iter()));
434    }
435
436    #[test]
437    fn test_global_combined_when_empty_project_disabled_global_filter() {
438        let project = empty_filter();
439        let global = disabled_filter("disabled-global");
440        assert!(
441            merge_generic_filters(&project, Some(&global), 1).eq([global
442                .filters
443                .first()
444                .unwrap()
445                .1
446                .into()]
447            .into_iter())
448        );
449    }
450
451    #[test]
452    fn test_global_combined_when_empty_project_enabled_global_filters() {
453        let project = empty_filter();
454        let global = enabled_filter("enabled-global");
455        assert!(
456            merge_generic_filters(&project, Some(&global), 1).eq([global
457                .filters
458                .first()
459                .unwrap()
460                .1
461                .into()]
462            .into_iter())
463        );
464    }
465
466    #[test]
467    fn test_global_combined_when_empty_project_enabled_flag_global() {
468        let project = empty_filter();
469        let global = enabled_flag_filter("skip");
470        assert!(
471            merge_generic_filters(&project, Some(&global), 1).eq([global
472                .filters
473                .first()
474                .unwrap()
475                .1
476                .into()])
477        );
478    }
479
480    #[test]
481    fn test_project_combined_when_disabled_project_empty_global() {
482        let project = disabled_filter("disabled-project");
483        let global = empty_filter();
484        assert!(
485            merge_generic_filters(&project, Some(&global), 1).eq([project
486                .filters
487                .first()
488                .unwrap()
489                .1
490                .into()]
491            .into_iter())
492        );
493    }
494
495    #[test]
496    fn test_project_combined_when_disabled_project_missing_global() {
497        let project = disabled_filter("disabled-project");
498        assert!(
499            merge_generic_filters(&project, None, 1).eq([project
500                .filters
501                .first()
502                .unwrap()
503                .1
504                .into(),]
505            .into_iter())
506        );
507    }
508
509    #[test]
510    fn test_both_combined_when_different_disabled_project_and_global() {
511        let project = disabled_filter("disabled-project");
512        let global = disabled_filter("disabled-global");
513        assert!(merge_generic_filters(&project, Some(&global), 1).eq([
514            project.filters.first().unwrap().1.into(),
515            global.filters.first().unwrap().1.into()
516        ]));
517    }
518
519    #[test]
520    fn test_project_combined_duplicated_disabled_project_and_global() {
521        let project = disabled_filter("filter");
522        let global = disabled_filter("filter");
523        assert!(
524            merge_generic_filters(&project, Some(&global), 1).eq([project
525                .filters
526                .first()
527                .unwrap()
528                .1
529                .into()])
530        );
531    }
532
533    #[test]
534    fn test_merged_combined_when_disabled_project_enabled_global() {
535        let project = disabled_filter("filter");
536        let global = enabled_filter("filter");
537        let expected = &GenericFilterConfig {
538            id: "filter".to_owned(),
539            is_enabled: false,
540            condition: global.filters.first().unwrap().1.condition.clone(),
541        };
542        assert!(
543            merge_generic_filters(&project, Some(&global), 1).eq([expected.into()].into_iter())
544        );
545    }
546
547    #[test]
548    fn test_no_combined_when_enabled_flag_project_empty_global() {
549        let project = enabled_flag_filter("filter");
550        let global = empty_filter();
551        assert!(
552            merge_generic_filters(&project, Some(&global), 1).eq([project
553                .filters
554                .first()
555                .unwrap()
556                .1
557                .into()]
558            .into_iter())
559        );
560    }
561
562    #[test]
563    fn test_project_combined_when_enabled_flag_project_missing_global() {
564        let project = enabled_flag_filter("filter");
565        assert!(
566            merge_generic_filters(&project, None, 1).eq([project
567                .filters
568                .first()
569                .unwrap()
570                .1
571                .into()]
572            .into_iter())
573        );
574    }
575
576    #[test]
577    fn test_project_combined_when_disabled_flag_project_empty_global() {
578        let project = disabled_flag_filter("filter");
579        let global = empty_filter();
580        assert!(
581            merge_generic_filters(&project, Some(&global), 1).eq([project
582                .filters
583                .first()
584                .unwrap()
585                .1
586                .into()])
587        );
588    }
589
590    #[test]
591    fn test_project_combined_when_disabled_flag_project_missing_global() {
592        let project = disabled_flag_filter("filter");
593        assert!(
594            merge_generic_filters(&project, None, 1).eq([project
595                .filters
596                .first()
597                .unwrap()
598                .1
599                .into()])
600        );
601    }
602
603    #[test]
604    fn test_project_combined_when_enabled_project_empty_global() {
605        let project = enabled_filter("enabled-project");
606        let global = empty_filter();
607        assert!(
608            merge_generic_filters(&project, Some(&global), 1).eq([project
609                .filters
610                .first()
611                .unwrap()
612                .1
613                .into()]
614            .into_iter())
615        );
616    }
617
618    #[test]
619    fn test_project_combined_when_enabled_project_missing_global() {
620        let project = enabled_filter("enabled-project");
621        assert!(
622            merge_generic_filters(&project, None, 1).eq([project
623                .filters
624                .first()
625                .unwrap()
626                .1
627                .into()]
628            .into_iter())
629        );
630    }
631
632    #[test]
633    fn test_merged_combined_when_enabled_flag_project_disabled_global() {
634        let project = enabled_flag_filter("filter");
635        let global = disabled_filter("filter");
636        let expected = &GenericFilterConfig {
637            id: "filter".to_owned(),
638            is_enabled: true,
639            condition: global.filters.first().unwrap().1.condition.clone(),
640        };
641        assert!(
642            merge_generic_filters(&project, Some(&global), 1).eq([expected.into()].into_iter())
643        );
644    }
645
646    #[test]
647    fn test_global_combined_when_disabled_flag_project_disabled_global() {
648        let project = disabled_flag_filter("filter");
649        let global = disabled_filter("filter");
650        assert!(
651            merge_generic_filters(&project, Some(&global), 1).eq([global
652                .filters
653                .first()
654                .unwrap()
655                .1
656                .into()])
657        );
658    }
659
660    #[test]
661    fn test_project_combined_when_enabled_project_disabled_global() {
662        let project = enabled_filter("filter");
663        let global = disabled_filter("filter");
664        assert!(
665            merge_generic_filters(&project, Some(&global), 1).eq([project
666                .filters
667                .first()
668                .unwrap()
669                .1
670                .into()]
671            .into_iter())
672        );
673    }
674
675    #[test]
676    fn test_global_combined_when_enabled_flag_project_enabled_global() {
677        let project = enabled_flag_filter("filter");
678        let global = enabled_filter("filter");
679        assert!(
680            merge_generic_filters(&project, Some(&global), 1).eq([global
681                .filters
682                .first()
683                .unwrap()
684                .1
685                .into()]
686            .into_iter())
687        );
688    }
689
690    #[test]
691    fn test_merged_combined_when_disabled_flag_project_enabled_global() {
692        let project = disabled_flag_filter("filter");
693        let global = enabled_filter("filter");
694        let expected = &GenericFilterConfig {
695            id: "filter".to_owned(),
696            is_enabled: false,
697            condition: global.filters.first().unwrap().1.condition.clone(),
698        };
699        assert!(
700            merge_generic_filters(&project, Some(&global), 1).eq([expected.into()].into_iter())
701        );
702    }
703
704    #[test]
705    fn test_project_combined_when_enabled_project_enabled_flag_global() {
706        let project = enabled_filter("filter");
707        let global = enabled_flag_filter("filter");
708        assert!(
709            merge_generic_filters(&project, Some(&global), 1).eq([project
710                .filters
711                .first()
712                .unwrap()
713                .1
714                .into()]
715            .into_iter())
716        );
717    }
718
719    #[test]
720    fn test_project_combined_when_enabled_flags_project_and_global() {
721        let project = enabled_flag_filter("filter");
722        let global = enabled_flag_filter("filter");
723        assert!(
724            merge_generic_filters(&project, Some(&global), 1).eq([project
725                .filters
726                .first()
727                .unwrap()
728                .1
729                .into()]
730            .into_iter())
731        );
732    }
733
734    #[test]
735    fn test_multiple_combined_filters() {
736        let project = GenericFiltersConfig {
737            version: 1,
738            filters: vec![
739                GenericFilterConfig {
740                    id: "0".to_owned(),
741                    is_enabled: true,
742                    condition: Some(RuleCondition::eq("event.exceptions", "myError")),
743                },
744                GenericFilterConfig {
745                    id: "1".to_owned(),
746                    is_enabled: true,
747                    condition: None,
748                },
749                GenericFilterConfig {
750                    id: "2".to_owned(),
751                    is_enabled: true,
752                    condition: Some(RuleCondition::eq("event.exceptions", "myError")),
753                },
754            ]
755            .into(),
756        };
757        let global = GenericFiltersConfig {
758            version: 1,
759            filters: vec![
760                GenericFilterConfig {
761                    id: "1".to_owned(),
762                    is_enabled: false,
763                    condition: Some(RuleCondition::eq("event.exceptions", "myOtherError")),
764                },
765                GenericFilterConfig {
766                    id: "3".to_owned(),
767                    is_enabled: false,
768                    condition: Some(RuleCondition::eq("event.exceptions", "myLastError")),
769                },
770            ]
771            .into(),
772        };
773
774        let expected0 = &project.filters[0];
775        let expected1 = &GenericFilterConfig {
776            id: "1".to_owned(),
777            is_enabled: true,
778            condition: Some(RuleCondition::eq("event.exceptions", "myOtherError")),
779        };
780        let expected2 = &project.filters[2];
781        let expected3 = &global.filters[1];
782
783        assert!(
784            merge_generic_filters(&project, Some(&global), 1).eq([
785                expected0.into(),
786                expected1.into(),
787                expected2.into(),
788                expected3.into()
789            ]
790            .into_iter())
791        );
792    }
793
794    #[test]
795    fn test_os_name_not_filter() {
796        let config = GenericFiltersConfig {
797            version: 1,
798            filters: vec![GenericFilterConfig {
799                id: "os_name".to_owned(),
800                is_enabled: true,
801                condition: Some(RuleCondition::eq("event.contexts.os.name", "fooBar").negate()),
802            }]
803            .into(),
804        };
805
806        let cases = [("fooBar", false), ("foobar", true), ("other", true)];
807        for (name, filters) in cases {
808            let event = Event::from_value(
809                serde_json::json!({
810                    "contexts": {
811                        "os": {
812                            "name": name,
813                        },
814                    },
815                })
816                .into(),
817            );
818
819            let expected = if filters {
820                Err(FilterStatKey::GenericFilter("os_name".to_owned()))
821            } else {
822                Ok(())
823            };
824
825            assert_eq!(
826                should_filter(event.value().unwrap(), &config, None),
827                expected
828            );
829        }
830    }
831}