vector/config/
schema.rs

1use vector_lib::{config::LogNamespace, configurable::configurable_component};
2
3pub(crate) use crate::schema::Definition;
4
5/// Schema options.
6///
7/// **Note:** The `enabled` and `validation` options are experimental and should only be enabled if you
8/// understand the limitations. While the infrastructure exists for schema tracking and validation, the
9/// full vision of automatic semantic field mapping and comprehensive schema enforcement was never fully
10/// realized.
11///
12/// If you encounter issues with these features, please [report them here](https://github.com/vectordotdev/vector/issues/new?template=bug.yml).
13#[configurable_component]
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15#[serde(default, deny_unknown_fields)]
16pub struct Options {
17    /// When enabled, Vector tracks the schema (field types and structure) of events as they flow
18    /// from sources through transforms to sinks. This allows Vector to understand what data each
19    /// component receives and produces.
20    #[serde(default = "default_enabled")]
21    pub enabled: bool,
22
23    /// When enabled, Vector validates that events flowing into each sink match the schema
24    /// requirements of that sink. If a sink requires certain fields or types that are missing
25    /// from the incoming events, Vector will report an error during configuration validation.
26    ///
27    /// This helps catch pipeline configuration errors early, before runtime.
28    #[serde(default = "default_validation")]
29    pub validation: bool,
30
31    /// Controls how metadata is stored in log events.
32    ///
33    /// When set to `false` (legacy mode), metadata fields like `host`, `timestamp`, and `source_type`
34    /// are stored as top-level fields alongside your log data.
35    ///
36    /// When set to `true` (Vector namespace mode), metadata is stored in a separate metadata namespace,
37    /// keeping it distinct from your actual log data.
38    ///
39    /// See the [Log Namespacing guide](/guides/level-up/log_namespace/) for detailed information
40    /// about when to use Vector namespace mode and how to migrate from legacy mode.
41    #[configurable(metadata(
42        docs::warnings = "Enabling log namespacing currently does not work when disk buffers are used. Avoid combining `schema.log_namespace = true` with disk buffers until [#18574](https://github.com/vectordotdev/vector/issues/18574) is resolved."
43    ))]
44    pub log_namespace: Option<bool>,
45}
46
47impl Options {
48    /// Gets the value of the globally configured log namespace, or the default if it wasn't set.
49    pub fn log_namespace(self) -> LogNamespace {
50        self.log_namespace
51            .map_or(LogNamespace::Legacy, |use_vector_namespace| {
52                use_vector_namespace.into()
53            })
54    }
55
56    /// Merges two schema options together.
57    pub fn append(&mut self, with: Self, errors: &mut Vec<String>) {
58        if self.log_namespace.is_some()
59            && with.log_namespace.is_some()
60            && self.log_namespace != with.log_namespace
61        {
62            errors.push(
63                format!("conflicting values for 'log_namespace' found. Both {:?} and {:?} used in the same component",
64                        self.log_namespace(), with.log_namespace())
65            );
66        }
67        if let Some(log_namespace) = with.log_namespace {
68            self.log_namespace = Some(log_namespace);
69        }
70
71        // If either config enables these flags, it is enabled.
72        self.enabled |= with.enabled;
73        self.validation |= with.validation;
74    }
75}
76
77impl Default for Options {
78    fn default() -> Self {
79        Self {
80            enabled: default_enabled(),
81            validation: default_validation(),
82            log_namespace: None,
83        }
84    }
85}
86
87const fn default_enabled() -> bool {
88    false
89}
90
91const fn default_validation() -> bool {
92    false
93}
94
95#[cfg(test)]
96mod test {
97    use super::*;
98
99    #[test]
100    fn test_append() {
101        for (test, mut a, b, expected) in [
102            (
103                "enable log namespacing",
104                Options {
105                    enabled: false,
106                    validation: false,
107                    log_namespace: None,
108                },
109                Options {
110                    enabled: false,
111                    validation: false,
112                    log_namespace: Some(true),
113                },
114                Some(Options {
115                    enabled: false,
116                    validation: false,
117                    log_namespace: Some(true),
118                }),
119            ),
120            (
121                "log namespace conflict",
122                Options {
123                    enabled: false,
124                    validation: false,
125                    log_namespace: Some(false),
126                },
127                Options {
128                    enabled: false,
129                    validation: false,
130                    log_namespace: Some(true),
131                },
132                None,
133            ),
134            (
135                "enable schemas",
136                Options {
137                    enabled: false,
138                    validation: false,
139                    log_namespace: None,
140                },
141                Options {
142                    enabled: true,
143                    validation: false,
144                    log_namespace: None,
145                },
146                Some(Options {
147                    enabled: true,
148                    validation: false,
149                    log_namespace: None,
150                }),
151            ),
152            (
153                "enable sink requirements",
154                Options {
155                    enabled: false,
156                    validation: false,
157                    log_namespace: None,
158                },
159                Options {
160                    enabled: false,
161                    validation: true,
162                    log_namespace: None,
163                },
164                Some(Options {
165                    enabled: false,
166                    validation: true,
167                    log_namespace: None,
168                }),
169            ),
170        ] {
171            let mut errors = vec![];
172            a.append(b, &mut errors);
173            if errors.is_empty() {
174                assert_eq!(Some(a), expected, "result mismatch: {test}");
175            } else {
176                assert_eq!(
177                    errors.is_empty(),
178                    expected.is_some(),
179                    "error mismatch: {test}"
180                );
181            }
182        }
183    }
184}