vrl/datadog/search/field.rs
1use super::grammar;
2
3/// Default fields that represent the search path when a Datadog tag/facet is not provided.
4static DEFAULT_FIELDS: &[&str] = &[
5 "message",
6 "custom.error.message",
7 "custom.error.stack",
8 "custom.title",
9 "_default_",
10];
11
12/// Attributes that represent special fields in Datadog.
13static RESERVED_ATTRIBUTES: &[&str] = &[
14 "host",
15 "source",
16 "status",
17 "service",
18 "trace_id",
19 "message",
20 "timestamp",
21 "tags",
22];
23
24/// Describes a field to search on.
25#[derive(Clone, Hash, PartialEq, Eq, Debug)]
26pub enum Field {
27 /// Default field (when tag/facet isn't provided)
28 Default(String),
29
30 // TODO investigate making this be an enum which may make more sense
31 // when dealing with a fixed set of field names
32 /// Reserved field that receives special treatment in Datadog.
33 Reserved(String),
34
35 /// An Attribute-- i.e. started with `@`.
36 // In Datadog Log Search the `@` prefix is used to define a Facet for
37 // attribute searching, and the event structure is assumed to have a
38 // root level field "custom". In VRL we do not guarantee this event
39 // structure so we are diverging a little from the DD Log Search
40 // definition and implementation a bit here, by calling this "Attribute".
41 //
42 // Internally when we handle this enum variant, we attempt to parse the
43 // string as a log path to obtain the value.
44 Attribute(String),
45
46 /// Tag type - i.e. search in the `tags` field.
47 Tag(String),
48}
49
50impl Field {
51 pub fn as_str(&self) -> &str {
52 match self {
53 Self::Default(s) => s,
54 Self::Reserved(s) => s,
55 Self::Attribute(s) => s,
56 Self::Tag(s) => s,
57 }
58 }
59}
60
61/// Converts a field/facet name to the VRL equivalent. Datadog payloads have a `message` field
62/// (which is used whenever the default field is encountered.
63pub fn normalize_fields<T: AsRef<str>>(value: T) -> Vec<Field> {
64 let value = value.as_ref();
65 if value.eq(grammar::DEFAULT_FIELD) {
66 return DEFAULT_FIELDS
67 .iter()
68 .map(|s| Field::Default((*s).to_owned()))
69 .collect();
70 }
71
72 let field = match value.replace('@', ".") {
73 v if value.starts_with('@') => Field::Attribute(v),
74 v if DEFAULT_FIELDS.contains(&v.as_ref()) => Field::Default(v),
75 v if RESERVED_ATTRIBUTES.contains(&v.as_ref()) => Field::Reserved(v),
76 v => Field::Tag(v),
77 };
78
79 vec![field]
80}