website/content/en/highlights/2022-05-18-vrl-iteration-support.md
Since we launched Vector Remap Language (VRL) more than a year ago, the language has seen a massive growth in both usage, and feature richness. While we intentionally left the core language in a stable state since its launch, we have been steadily expanding the standard library, increasing performance, adding event enrichment features, and squashing many bugs.
One of the last major pieces missing from the language — and one requested by many of you — is support for mapping collections. We needed to introduce this feature thoughtfully since mapping can be a common source of performance and reliability bugs (i.e., infinite loops). And our design accomplishes this by providing opinionated mapping functions that align closely with the use case. So, without further ado, we're happy to announce that as of Vector 0.22.0, mapping for collections is now available!
To explain how collection mapping in VRL works, we’ll dissect a simple example:
{
"foo": true,
"bar": { "bar": "" },
"baz": "",
"qux": ["a", "b", "a", "c"]
}
Let’s assume we want to achieve the following results:
null.qux array.Here’s how we would solve these individual tasks:
# 1. Upcase all keys in the object.
. = map_keys(., recursive: true) -> |key| { upcase(key) }
# 2. Change all empty string values to `null`.
. = map_values(., recursive: true) -> |value| {
if value == ”” { null } else { value }
}
# 3. Count the frequency of elements in the `qux` array.
.qux_tally = {}
for_each(.qux) -> |_index, value| {
tally = int(get!(.qux_tally, [value])) ?? 0
.qux_tally = set!(.qux_tally, [value], tally + 1)
}
Running this VRL program results in the following output:
{
"FOO": true,
"BAR": { "BAR": null },
"BAZ": null,
"QUX": ["a", "b", "a", "c"],
"qux_tally": {
"a": 2,
"b": 1,
"c": 1
}
}
For a longer list of examples, see our RFC and test harness.
As you can see, VRL iteration happens through regular function calls, combined with the new closure syntax. We chose this solution for a few reasons:
The three functions we introduce in this release (map_keys, map_values, and
for_each) serve as a good starting point for any generic iteration logic, but
we already have a list of special-purpose iteration functions available in the
standard library, and plan to add more, as long as they fit the purpose of the
language, remapping observability data.
Take a look at our existing iteration functions, and feel free to file a request for any special purpose function that would make your program easier to maintain and/or more performant to run.
For more details on the design of this feature, you can read our technical RFC.
We hope you are as happy with this enhancement to VRL as we are. Iteration support unlocks one of the last areas for which many of you had to fall back to the LUA runtime transform. You can now keep your remapping logic in VRL, with all the performance and runtime correctness guarantees VRL delivers.
Please join us on Discord or tweet at us at @vectordotdev to discuss this, or any other aspect of Vector and VRL.