1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
#[cfg(feature = "transforms-dedupe")]
pub mod config;
#[cfg(feature = "transforms-impl-dedupe")]
pub mod transform;
#[cfg(feature = "transforms-impl-dedupe")]
pub mod common {
use std::num::NonZeroUsize;
use vector_lib::{configurable::configurable_component, lookup::lookup_v2::ConfigTargetPath};
use crate::config::log_schema;
/// Caching configuration for deduplication.
#[configurable_component]
#[derive(Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct CacheConfig {
/// Number of events to cache and use for comparing incoming events to previously seen events.
pub num_events: NonZeroUsize,
}
pub fn default_cache_config() -> CacheConfig {
CacheConfig {
num_events: NonZeroUsize::new(5000).expect("static non-zero number"),
}
}
/// Options to control what fields to match against.
///
/// When no field matching configuration is specified, events are matched using the `timestamp`,
/// `host`, and `message` fields from an event. The specific field names used are those set in
/// the global [`log schema`][global_log_schema] configuration.
///
/// [global_log_schema]: https://vector.dev/docs/reference/configuration/global-options/#log_schema
// TODO: This enum renders correctly in terms of providing equivalent Cue output when using the
// machine-generated stuff vs the previously-hand-written Cue... but what it _doesn't_ have in the
// machine-generated output is any sort of blurb that these "fields" (`match` and `ignore`) are
// actually mutually exclusive.
//
// We know that to be the case when we're generating the output from the configuration schema, so we
// need to emit something in that output to indicate as much, and further, actually use it on the
// Cue side to add some sort of boilerplate about them being mutually exclusive, etc.
#[configurable_component]
#[derive(Clone, Debug)]
#[serde(deny_unknown_fields)]
pub enum FieldMatchConfig {
/// Matches events using only the specified fields.
#[serde(rename = "match")]
MatchFields(
#[configurable(metadata(
docs::examples = "field1",
docs::examples = "parent.child_field"
))]
Vec<ConfigTargetPath>,
),
/// Matches events using all fields except for the ignored ones.
#[serde(rename = "ignore")]
IgnoreFields(
#[configurable(metadata(
docs::examples = "field1",
docs::examples = "parent.child_field",
docs::examples = "host",
docs::examples = "hostname"
))]
Vec<ConfigTargetPath>,
),
}
pub fn fill_default_fields_match(maybe_fields: Option<&FieldMatchConfig>) -> FieldMatchConfig {
// We provide a default value on `fields`, based on `default_match_fields`, in order to
// drive the configuration schema and documentation. Since we're getting the values from the
// configured log schema, though, the default field values shown in the configuration
// schema/documentation may not be the same as an actual user's Vector configuration.
match maybe_fields {
Some(FieldMatchConfig::MatchFields(x)) => FieldMatchConfig::MatchFields(x.clone()),
Some(FieldMatchConfig::IgnoreFields(y)) => FieldMatchConfig::IgnoreFields(y.clone()),
None => FieldMatchConfig::MatchFields(default_match_fields()),
}
}
// TODO: Add support to the `configurable(metadata(..))` helper attribute for passing an expression
// that will provide the value for the metadata attribute's value, as well as letting all metadata
// attributes have whatever value they want, so long as it can be serialized by `serde_json`.
//
// Once we have that, we could curry these default values (and others) via a metadata attribute
// instead of via `serde(default = "...")` to allow for displaying default values in the
// configuration schema _without_ actually changing how a field is populated during deserialization.
//
// See the comment in `fill_default_fields_match` for more information on why this is required.
//
// TODO: These values are used even for events with the new "Vector" log namespace.
// These aren't great defaults in that case, but hard-coding isn't much better since the
// structure can vary significantly. This should probably either become a required field
// in the future, or maybe the "semantic meaning" can be utilized here.
fn default_match_fields() -> Vec<ConfigTargetPath> {
let mut fields = Vec::new();
if let Some(message_key) = log_schema().message_key_target_path() {
fields.push(ConfigTargetPath(message_key.clone()));
}
if let Some(host_key) = log_schema().host_key_target_path() {
fields.push(ConfigTargetPath(host_key.clone()));
}
if let Some(timestamp_key) = log_schema().timestamp_key_target_path() {
fields.push(ConfigTargetPath(timestamp_key.clone()));
}
fields
}
}