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 /// This feature is in beta and behavior may change.
34 ///
35 /// When set to `false` (legacy mode), metadata fields like `host`, `timestamp`, and `source_type`
36 /// are stored as top-level fields alongside your log data.
37 ///
38 /// When set to `true` (Vector namespace mode), metadata is stored in a separate metadata namespace,
39 /// keeping it distinct from your actual log data.
40 ///
41 /// See the [Log Namespacing guide](/guides/level-up/log_namespace/) for detailed information
42 /// about when to use Vector namespace mode and how to migrate from legacy mode.
43 #[configurable(metadata(
44 status = "beta",
45 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."
46 ))]
47 pub log_namespace: Option<bool>,
48}
49
50impl Options {
51 /// Gets the value of the globally configured log namespace, or the default if it wasn't set.
52 pub fn log_namespace(self) -> LogNamespace {
53 self.log_namespace
54 .map_or(LogNamespace::Legacy, |use_vector_namespace| {
55 use_vector_namespace.into()
56 })
57 }
58
59 /// Merges two schema options together.
60 pub fn append(&mut self, with: Self, errors: &mut Vec<String>) {
61 if self.log_namespace.is_some()
62 && with.log_namespace.is_some()
63 && self.log_namespace != with.log_namespace
64 {
65 errors.push(
66 format!("conflicting values for 'log_namespace' found. Both {:?} and {:?} used in the same component",
67 self.log_namespace(), with.log_namespace())
68 );
69 }
70 if let Some(log_namespace) = with.log_namespace {
71 self.log_namespace = Some(log_namespace);
72 }
73
74 // If either config enables these flags, it is enabled.
75 self.enabled |= with.enabled;
76 self.validation |= with.validation;
77 }
78}
79
80impl Default for Options {
81 fn default() -> Self {
82 Self {
83 enabled: default_enabled(),
84 validation: default_validation(),
85 log_namespace: None,
86 }
87 }
88}
89
90const fn default_enabled() -> bool {
91 false
92}
93
94const fn default_validation() -> bool {
95 false
96}
97
98#[cfg(test)]
99mod test {
100 use super::*;
101
102 #[test]
103 fn test_append() {
104 for (test, mut a, b, expected) in [
105 (
106 "enable log namespacing",
107 Options {
108 enabled: false,
109 validation: false,
110 log_namespace: None,
111 },
112 Options {
113 enabled: false,
114 validation: false,
115 log_namespace: Some(true),
116 },
117 Some(Options {
118 enabled: false,
119 validation: false,
120 log_namespace: Some(true),
121 }),
122 ),
123 (
124 "log namespace conflict",
125 Options {
126 enabled: false,
127 validation: false,
128 log_namespace: Some(false),
129 },
130 Options {
131 enabled: false,
132 validation: false,
133 log_namespace: Some(true),
134 },
135 None,
136 ),
137 (
138 "enable schemas",
139 Options {
140 enabled: false,
141 validation: false,
142 log_namespace: None,
143 },
144 Options {
145 enabled: true,
146 validation: false,
147 log_namespace: None,
148 },
149 Some(Options {
150 enabled: true,
151 validation: false,
152 log_namespace: None,
153 }),
154 ),
155 (
156 "enable sink requirements",
157 Options {
158 enabled: false,
159 validation: false,
160 log_namespace: None,
161 },
162 Options {
163 enabled: false,
164 validation: true,
165 log_namespace: None,
166 },
167 Some(Options {
168 enabled: false,
169 validation: true,
170 log_namespace: None,
171 }),
172 ),
173 ] {
174 let mut errors = vec![];
175 a.append(b, &mut errors);
176 if errors.is_empty() {
177 assert_eq!(Some(a), expected, "result mismatch: {test}");
178 } else {
179 assert_eq!(
180 errors.is_empty(),
181 expected.is_some(),
182 "error mismatch: {test}"
183 );
184 }
185 }
186 }
187}