VRL example reference
Here you’ll find a comprehensive list of all VRL program examples. These examples demonstrate the breadth of the language and its observability-focused facilities.
Try Using the VRL subcommand
You can run these examples using the vector vrl subcommand with --input (input is newline
delimited JSON file representing a list of events). and --program (VRL program) to pass in the
example input and program as well as --print-object to show the modified object. The below
examples show pretty-printed JSON for the input events, so collapse these to single lines when
passing in via --input.
For example: vector vrl --input input.json --program program.vrl --print-object. This closely
matches how VRL will receive the input in a running Vector instance.
VRL REPL
Additionally, if vector vrl is run without any arguments, it will spawn a REPL
(Read–eval–print loop).
Assuming you have Vector installed, you can run vector vrl to start the REPL.
From there, you can type help and press return to get further help.
The REPL behaves nearly identical to the programs you write for your Vector configuration, and can be used to test individual snippets of complex programs before you commit them to your production configuration.
The vector vrl command has many other capabilities, run the command using
vector vrl --help to see more information.
Real world examples
Parse Syslog logs
{
"message": "\u003c102\u003e1 2020-12-22T15:22:31.111Z vector-user.biz su 2666 ID389 - Something went wrong"
}. |= parse_syslog!(.message){
"log": {
"appname": "su",
"facility": "ntp",
"hostname": "vector-user.biz",
"message": "Something went wrong",
"msgid": "ID389",
"procid": 2666,
"severity": "info",
"timestamp": "2020-12-22T15:22:31.111Z",
"version": 1
}
}Parse key/value (logfmt) logs
{
"message": "@timestamp=\"Sun Jan 10 16:47:39 EST 2021\" level=info msg=\"Stopping all fetchers\" tag#production=stopping_fetchers id=ConsumerFetcherManager-1382721708341 module=kafka.consumer.ConsumerFetcherManager"
}. = parse_key_value!(.message){
"log": {
"@timestamp": "Sun Jan 10 16:47:39 EST 2021",
"id": "ConsumerFetcherManager-1382721708341",
"level": "info",
"module": "kafka.consumer.ConsumerFetcherManager",
"msg": "Stopping all fetchers",
"tag#production": "stopping_fetchers"
}
}Parse custom logs
{
"message": "2021/01/20 06:39:15 +0000 [error] 17755#17755: *3569904 open() \"/usr/share/nginx/html/test.php\" failed (2: No such file or directory), client: xxx.xxx.xxx.xxx, server: localhost, request: \"GET /test.php HTTP/1.1\", host: \"yyy.yyy.yyy.yyy\""
}. |= parse_regex!(.message, r'^(?P<timestamp>\d+/\d+/\d+ \d+:\d+:\d+ \+\d+) \[(?P<severity>\w+)\] (?P<pid>\d+)#(?P<tid>\d+):(?: \*(?P<connid>\d+))? (?P<message>.*)$')
# Coerce parsed fields
.timestamp = parse_timestamp(.timestamp, "%Y/%m/%d %H:%M:%S %z") ?? now()
.pid = to_int!(.pid)
.tid = to_int!(.tid)
# Extract structured data
message_parts = split(.message, ", ", limit: 2)
structured = parse_key_value(message_parts[1], key_value_delimiter: ":", field_delimiter: ",") ?? {}
.message = message_parts[0]
. = merge(., structured){
"log": {
"client": "xxx.xxx.xxx.xxx",
"connid": "3569904",
"host": "yyy.yyy.yyy.yyy",
"message": "open() \"/usr/share/nginx/html/test.php\" failed (2: No such file or directory)",
"pid": 17755,
"request": "GET /test.php HTTP/1.1",
"server": "localhost",
"severity": "error",
"tid": 17755,
"timestamp": "2021-01-20T06:39:15Z"
}
}Multiple parsing strategies
{
"message": "\u003c102\u003e1 2020-12-22T15:22:31.111Z vector-user.biz su 2666 ID389 - Something went wrong"
}structured =
parse_syslog(.message) ??
parse_common_log(.message) ??
parse_regex!(.message, r'^(?P<timestamp>\d+/\d+/\d+ \d+:\d+:\d+) \[(?P<severity>\w+)\] (?P<pid>\d+)#(?P<tid>\d+):(?: \*(?P<connid>\d+))? (?P<message>.*)$')
. = merge(., structured){
"log": {
"appname": "su",
"facility": "ntp",
"hostname": "vector-user.biz",
"message": "Something went wrong",
"msgid": "ID389",
"procid": 2666,
"severity": "info",
"timestamp": "2020-12-22T15:22:31.111Z",
"version": 1
}
}Modify metric tags
{
"counter": {
"value": 102
},
"kind": "incremental",
"name": "user_login_total",
"tags": {
"email": "vic@vector.dev",
"host": "my.host.com",
"instance_id": "abcd1234"
}
}.tags.environment = get_env_var!("ENV") # add
.tags.hostname = del(.tags.host) # rename
del(.tags.email){
"metric": {
"counter": {
"value": 102
},
"kind": "incremental",
"name": "user_login_total",
"tags": {
"environment": "production",
"hostname": "my.host.com",
"instance_id": "abcd1234"
}
}
}Emitting multiple logs from JSON
{
"message": "[{\"message\": \"first_log\"}, {\"message\": \"second_log\"}]"
}. = parse_json!(.message) # sets `.` to an array of objects[
{
"log": {
"message": "first_log"
}
},
{
"log": {
"message": "second_log"
}
}
]Emitting multiple non-object logs from JSON
{
"message": "[5, true, \"hello\"]"
}. = parse_json!(.message) # sets `.` to an array[
{
"log": {
"message": 5
}
},
{
"log": {
"message": true
}
},
{
"log": {
"message": "hello"
}
}
]Invalid argument type
{
"not_a_string": 1
}upcase(42)error[E110]: invalid argument type
┌─ :1:8
│
1 │ upcase(42)
│ ^^
│ │
│ this expression resolves to the exact type integer
│ but the parameter "value" expects the exact type string
│
= try: ensuring an appropriate type at runtime
=
= 42 = string!(42)
= upcase(42)
=
= try: coercing to an appropriate type and specifying a default value as a fallback in case coercion fails
=
= 42 = to_string(42) ?? "default"
= upcase(42)
=
= see documentation about error handling at https://errors.vrl.dev/#handling
= learn more about error code 110 at https://errors.vrl.dev/110
= see language documentation at https://vrl.dev
= try your code in the VRL REPL, learn more at https://vrl.dev/examples
Unhandled fallible assignment
{
"message": "key1=value1 key2=value2"
}structured = parse_key_value(.message)error[E103]: unhandled fallible assignment
┌─ :1:14
│
1 │ structured = parse_key_value(.message)
│ ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^
│ │ │
│ │ this expression is fallible because at least one argument's type cannot be verified to be valid
│ │ update the expression to be infallible by adding a `!`: `parse_key_value!(.message)`
│ │ `.message` argument type is `any` and this function expected a parameter `value` of type `string`
│ or change this to an infallible assignment:
│ structured, err = parse_key_value(.message)
│
= see documentation about error handling at https://errors.vrl.dev/#handling
= see functions characteristics documentation at https://vrl.dev/expressions/#function-call-characteristics
= learn more about error code 103 at https://errors.vrl.dev/103
= see language documentation at https://vrl.dev
= try your code in the VRL REPL, learn more at https://vrl.dev/examples
Array examples
append
items array to the end of the value array.chunks
value into slices of length chunk_size bytes.pop
value array.push
item to the end of the value array.zip
Iterate over several arrays in parallel, producing a new array containing arrays of items from each source.
The resulting array will be as long as the shortest input array, with all the remaining elements dropped.
This function is modeled from the zip function in Python,
but similar methods can be found in Ruby
and Rust.
If a single parameter is given, it must contain an array of all the input arrays.
Merge two arrays
zip([1, 2, 3], [4, 5, 6, 7])[[1,4],[2,5],[3,6]]Merge three arrays
zip([[1, 2], [3, 4], [5, 6]])[[1,3,5],[2,4,6]]Merge an array of three arrays into an array of 3-tuples
zip([["a", "b", "c"], [1, null, true], [4, 5, 6]])[["a",1,4],["b",null,5],["c",true,6]]Merge two array parameters
zip([1, 2, 3, 4], [5, 6, 7])[[1,5],[2,6],[3,7]]Codec examples
decode_base16
value (a Base16 string) into its original string.Decode Base16 data
decode_base16!("736F6D6520737472696E672076616C7565")some string valueDecode longer Base16 data
decode_base16!("796f752068617665207375636365737366756c6c79206465636f646564206d65")you have successfully decoded medecode_base64
value (a Base64 string) into its original string.Decode Base64 data (default)
decode_base64!("eW91IGhhdmUgc3VjY2Vzc2Z1bGx5IGRlY29kZWQgbWU=")you have successfully decoded meDecode Base64 data (URL safe)
decode_base64!("eW91IGNhbid0IG1ha2UgeW91ciBoZWFydCBmZWVsIHNvbWV0aGluZyBpdCB3b24ndA==", charset: "url_safe")you can't make your heart feel something it won'tdecode_charset
value (a non-UTF8 string) to a UTF8 string using the specified
character set.Decode EUC-KR string
decode_charset!(decode_base64!("vsiz58fPvLy/5A=="), "euc-kr")안녕하세요Decode EUC-JP string
decode_charset!(decode_base64!("pLOk86TLpMGkzw=="), "euc-jp")こんにちはDecode GB2312 string
decode_charset!(decode_base64!("xOO6ww=="), "gb2312")你好decode_gzip
value (a Gzip string) into its original string.Decode Gzip data
decode_gzip!(decode_base64!("H4sIAB8BymMAAyvISU0sTlVISU3OT0lVyE0FAJsZ870QAAAA"))please decode medecode_lz4
value (an lz4 string) into its original string. buf_size is the size of the buffer to decode into, this must be equal to or larger than the uncompressed size.
If prepended_size is set to true, it expects the original uncompressed size to be prepended to the compressed data.
prepended_size is useful for some implementations of lz4 that require the original size to be known before decoding.LZ4 block with prepended size
decode_lz4!(decode_base64!("LAAAAPAdVGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIDEzIGxhenkgZG9ncy4="), prepended_size: true)The quick brown fox jumps over 13 lazy dogs.Decode Lz4 data without prepended size.
decode_lz4!(decode_base64!("BCJNGGBAgiwAAIBUaGUgcXVpY2sgYnJvd24gZm94IGp1bXBzIG92ZXIgMTMgbGF6eSBkb2dzLgAAAAA="))The quick brown fox jumps over 13 lazy dogs.decode_mime_q
value with their original string.Decode single encoded-word
decode_mime_q!("=?utf-8?b?SGVsbG8sIFdvcmxkIQ==?=")Hello, World!Embedded
decode_mime_q!("From: =?utf-8?b?SGVsbG8sIFdvcmxkIQ==?= <=?utf-8?q?hello=5Fworld=40example=2ecom?=>")From: Hello, World! <hello_world@example.com>Without charset
decode_mime_q!("?b?SGVsbG8sIFdvcmxkIQ==")Hello, World!decode_percent
value like a URL.Percent decode a value
decode_percent("foo%20bar%3F")foo bar?decode_punycode
value, such as an internationalized domain name (IDN). This function assumes that the value passed is meant to be used in IDN context and that it is either a domain name or a part of it.Decode a punycode encoded internationalized domain name
decode_punycode!("www.xn--caf-dma.com")www.café.comDecode an ASCII only string
decode_punycode!("www.cafe.com")www.cafe.comIgnore validation
decode_punycode!("xn--8hbb.xn--fiba.xn--8hbf.xn--eib.", validate: false)١٠.٦٦.٣٠.٥.decode_snappy
value (a Snappy string) into its original string.Decode Snappy data
decode_snappy!(decode_base64!("LKxUaGUgcXVpY2sgYnJvd24gZm94IGp1bXBzIG92ZXIgMTMgbGF6eSBkb2dzLg=="))The quick brown fox jumps over 13 lazy dogs.decode_zlib
value (a Zlib string) into its original string.Decode Zlib data
decode_zlib!(decode_base64!("eJxLzUvOT0mNz00FABI5A6A="))encode_medecode_zstd
value (a Zstandard string) into its original string.Decode Zstd data
decode_zstd!(decode_base64!("KLUv/QBY/QEAYsQOFKClbQBedqXsb96EWDax/f/F/z+gNU4ZTInaUeAj82KqPFjUzKqhcfDqAIsLvAsnY1bI/N2mHzDixRQA"))you_have_successfully_decoded_me.congratulations.you_are_breathtaking.encode_base16
value to Base16.Encode to Base16
encode_base16("some string value")736f6d6520737472696e672076616c7565encode_base64
value to Base64.Encode to Base64 (default)
encode_base64("please encode me")cGxlYXNlIGVuY29kZSBtZQ==Encode to Base64 (without padding)
encode_base64("please encode me, no padding though", padding: false)cGxlYXNlIGVuY29kZSBtZSwgbm8gcGFkZGluZyB0aG91Z2gEncode to Base64 (URL safe)
encode_base64("please encode me, but safe for URLs", charset: "url_safe")cGxlYXNlIGVuY29kZSBtZSwgYnV0IHNhZmUgZm9yIFVSTHM=Encode to Base64 (without padding and URL safe)
encode_base64("some string value", padding: false, charset: "url_safe")c29tZSBzdHJpbmcgdmFsdWUencode_charset
value (a UTF8 string) to a non-UTF8 string using the specified
character set.Encode UTF8 string to EUC-KR
encode_base64(encode_charset!("안녕하세요", "euc-kr"))vsiz58fPvLy/5A==Encode UTF8 string to EUC-JP
encode_base64(encode_charset!("こんにちは", "euc-jp"))pLOk86TLpMGkzw==Encode UTF8 string to GB2312
encode_base64(encode_charset!("你好", "gb2312"))xOO6ww==encode_gzip
value to Gzip.Encode to Gzip
encode_base64(encode_gzip("please encode me"))H4sIAAAAAAAA/yvISU0sTlVIzUvOT0lVyE0FAI4R4vcQAAAAencode_json
value to JSON.Encode object to JSON
encode_json({"field": "value", "another": [1,2,3]})s'{"another":[1,2,3],"field":"value"}'Encode object to as pretty-printed JSON
encode_json({"field": "value", "another": [1,2,3]}, true){
"another": [
1,
2,
3
],
"field": "value"
}encode_key_value
value into key-value format with customizable delimiters. Default delimiters match the logfmt format.Encode with default delimiters (no ordering)
encode_key_value(
{
"ts": "2021-06-05T17:20:00Z",
"msg": "This is a message",
"lvl": "info"
}
)
lvl=info msg="This is a message" ts=2021-06-05T17:20:00ZEncode with default delimiters (fields ordering)
encode_key_value!(
{
"ts": "2021-06-05T17:20:00Z",
"msg": "This is a message",
"lvl": "info",
"log_id": 12345
},
["ts", "lvl", "msg"]
)
ts=2021-06-05T17:20:00Z lvl=info msg="This is a message" log_id=12345Encode with default delimiters (nested fields)
encode_key_value(
{
"agent": {"name": "foo"},
"log": {"file": {"path": "my.log"}},
"event": "log"
}
)
agent.name=foo event=log log.file.path=my.logEncode with default delimiters (nested fields ordering)
encode_key_value!(
{
"agent": {"name": "foo"},
"log": {"file": {"path": "my.log"}},
"event": "log"
},
["event", "log.file.path", "agent.name"])
event=log log.file.path=my.log agent.name=fooEncode with custom delimiters (no ordering)
encode_key_value(
{"ts": "2021-06-05T17:20:00Z", "msg": "This is a message", "lvl": "info"},
field_delimiter: ",",
key_value_delimiter: ":"
)
lvl:info,msg:"This is a message",ts:2021-06-05T17:20:00ZEncode with custom delimiters and flatten boolean
encode_key_value(
{"ts": "2021-06-05T17:20:00Z", "msg": "This is a message", "lvl": "info", "beta": true, "dropped": false},
field_delimiter: ",",
key_value_delimiter: ":",
flatten_boolean: true
)
beta,lvl:info,msg:"This is a message",ts:2021-06-05T17:20:00Zencode_logfmt
value to logfmt.Encode to logfmt (no ordering)
encode_logfmt({"ts": "2021-06-05T17:20:00Z", "msg": "This is a message", "lvl": "info"})lvl=info msg="This is a message" ts=2021-06-05T17:20:00ZEncode to logfmt (fields ordering)
encode_logfmt!({"ts": "2021-06-05T17:20:00Z", "msg": "This is a message", "lvl": "info", "log_id": 12345}, ["ts", "lvl", "msg"])ts=2021-06-05T17:20:00Z lvl=info msg="This is a message" log_id=12345Encode to logfmt (nested fields)
encode_logfmt({"agent": {"name": "foo"}, "log": {"file": {"path": "my.log"}}, "event": "log"})agent.name=foo event=log log.file.path=my.logEncode to logfmt (nested fields ordering)
encode_logfmt!({"agent": {"name": "foo"}, "log": {"file": {"path": "my.log"}}, "event": "log"}, ["event", "log.file.path", "agent.name"])event=log log.file.path=my.log agent.name=fooencode_lz4
value to Lz4. This function compresses the
input string into an lz4 block. If prepend_size is set to true, it prepends the
original uncompressed size to the compressed data. This is useful for some
implementations of lz4 that require the original size to be known before decoding.Encode to Lz4
encode_base64(encode_lz4!("The quick brown fox jumps over 13 lazy dogs.", true))LAAAAPAdVGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIDEzIGxhenkgZG9ncy4=encode_percent
value with percent encoding to safely be used in URLs.Percent encode all non-alphanumeric characters (default)
encode_percent("foo bar?")foo%20bar%3FPercent encode only control characters
encode_percent("foo \tbar", ascii_set: "CONTROLS")foo %09barPercent encode special characters
encode_percent("foo@bar?")foo%40bar%3Fencode_proto
value into a protocol buffer payload.Encode to proto
encode_base64(encode_proto!({ "name": "someone", "phones": [{"number": "123456"}]}, "test_protobuf.desc", "test_protobuf.v1.Person"))Cgdzb21lb25lIggKBjEyMzQ1Ng==encode_punycode
value to punycode. Useful for internationalized domain names (IDN). This function assumes that the value passed is meant to be used in IDN context and that it is either a domain name or a part of it.Encode an internationalized domain name
encode_punycode!("www.café.com")www.xn--caf-dma.comEncode an internationalized domain name with mixed case
encode_punycode!("www.CAFé.com")www.xn--caf-dma.comEncode an ASCII only string
encode_punycode!("www.cafe.com")www.cafe.comIgnore validation
encode_punycode!("xn--8hbb.xn--fiba.xn--8hbf.xn--eib.", validate: false)xn--8hbb.xn--fiba.xn--8hbf.xn--eib.encode_snappy
value to Snappy.Encode to Snappy
encode_base64(encode_snappy!("The quick brown fox jumps over 13 lazy dogs."))LKxUaGUgcXVpY2sgYnJvd24gZm94IGp1bXBzIG92ZXIgMTMgbGF6eSBkb2dzLg==encode_zlib
value to Zlib.Encode to Zlib
encode_base64(encode_zlib("please encode me"))eJwryElNLE5VSM1Lzk9JVchNBQA0RQX7encode_zstd
value to Zstandard.Encode to Zstd
encode_base64(encode_zstd("please encode me"))KLUv/QBYgQAAcGxlYXNlIGVuY29kZSBtZQ==Coerce examples
to_bool
value into a boolean.to_float
value into a float.Coerce to a float (timestamp)
to_float(t'2020-12-30T22:20:53.824727Z')1609366853.824727to_int
value into an integer.Coerce to an int (timestamp)
to_int(t'2020-12-30T22:20:53.824727Z')1609366853to_regex
value into a regex.to_string
value into a string.Coerce to a string (Boolean)
to_string(true)s'true'Coerce to a string (float)
to_string(52.2)s'52.2'Timestamp
to_string(t'2020-01-01T00:00:00Z')2020-01-01T00:00:00ZConvert examples
from_unix_timestamp
Converts the value integer from a Unix timestamp to a VRL timestamp.
Converts from the number of seconds since the Unix epoch by default. To convert from milliseconds or nanoseconds, set the unit argument to milliseconds or nanoseconds.
Convert from a Unix timestamp (seconds)
from_unix_timestamp!(5)t'1970-01-01T00:00:05Z'Convert from a Unix timestamp (milliseconds)
from_unix_timestamp!(5000, unit: "milliseconds")t'1970-01-01T00:00:05Z'Convert from a Unix timestamp (microseconds)
from_unix_timestamp!(5000, unit: "microseconds")t'1970-01-01T00:00:00.005Z'Convert from a Unix timestamp (nanoseconds)
from_unix_timestamp!(5000, unit: "nanoseconds")t'1970-01-01T00:00:00.000005Z'to_syslog_facility
value, a Syslog facility code, into its corresponding Syslog keyword. For example, 0 into "kern", 1 into "user", etc.Coerce to a Syslog facility
to_syslog_facility!(4)authto_syslog_facility_code
Coerce to Syslog facility code
to_syslog_facility_code!("authpriv")10invalid
to_syslog_facility_code!(s'foobar')to_syslog_level
value, a Syslog severity level, into its corresponding keyword, i.e. 0 into "emerg", 1 into "alert", etc.Coerce to a Syslog level
to_syslog_level!(5)noticeto_syslog_severity
Coerce to Syslog severity
to_syslog_severity!("alert")1to_unix_timestamp
Converts the value timestamp into a Unix timestamp.
Returns the number of seconds since the Unix epoch by default. To return the number in milliseconds or nanoseconds, set the unit argument to milliseconds or nanoseconds.
Convert to a Unix timestamp (seconds)
to_unix_timestamp(t'2021-01-01T00:00:00+00:00')1609459200Convert to a Unix timestamp (milliseconds)
to_unix_timestamp(t'2021-01-01T00:00:00Z', unit: "milliseconds")1609459200000Convert to a Unix timestamp (microseconds)
to_unix_timestamp(t'2021-01-01T00:00:00Z', unit: "microseconds")1609459200000000Convert to a Unix timestamp (nanoseconds)
to_unix_timestamp(t'2021-01-01T00:00:00Z', unit: "nanoseconds")1609459200000000000Debug examples
assert
condition, which must be a Boolean expression. The program is aborted with message if the condition evaluates to false.assert_eq
left and right, have the same value. The program is aborted with message if they do not have the same value.Unsuccessful assertion with custom log message
assert_eq!(1, 0, message: "Unequal integers")log
Enrichment examples
find_enrichment_table_records
Searches an enrichment table for rows that match the provided condition.
For file enrichment tables, this condition needs to be a VRL object in which
the key-value pairs indicate a field to search mapped to a value to search in that field.
This function returns the rows that match the provided condition(s). All fields need to
match for rows to be returned; if any fields do not match, then no rows are returned.
There are currently three forms of search criteria:
Exact match search. The given field must match the value exactly. Case sensitivity can be specified using the
case_sensitiveargument. An exact match search can use an index directly into the dataset, which should make this search fairly “cheap” from a performance perspective.Wildcard match search. The given fields specified by the exact match search may also be matched exactly to the value provided to the
wildcardparameter. A wildcard match search can also use an index directly into the dataset.Date range search. The given field must be greater than or equal to the
fromdate and/or less than or equal to thetodate. A date range search involves sequentially scanning through the rows that have been located using any exact match criteria. This can be an expensive operation if there are many rows returned by any exact match criteria. Therefore, use date ranges as the only criteria when the enrichment data set is very small.
For geoip and mmdb enrichment tables, this condition needs to be a VRL object with a single key-value pair
whose value needs to be a valid IP address. Example: {"ip": .ip }. If a return field is expected
and without a value, null is used. This table can return the following fields:
ISP databases:
autonomous_system_numberautonomous_system_organizationisporganization
City databases:
city_namecontinent_codecountry_codecountry_nameregion_coderegion_namemetro_codelatitudelongitudepostal_codetimezone
Connection-Type databases:
connection_type
To use this function, you need to update your configuration to
include an
enrichment_tables
parameter.
Exact match
find_enrichment_table_records!(
"test",
{"surname": "Smith"}
)
[{"firstname":"Bob","id":1,"surname":"Smith"},{"firstname":"Fred","id":2,"surname":"Smith"}]Case insensitive match
find_enrichment_table_records!(
"test",
{"surname": "smith"},
case_sensitive: false
)
[{"firstname":"Bob","id":1,"surname":"Smith"},{"firstname":"Fred","id":2,"surname":"Smith"}]Wildcard match
find_enrichment_table_records!(
"test",
{"firstname": "Bob"},
wildcard: "fred",
case_sensitive: false
)
[{"firstname":"Bob","id":1,"surname":"Smith"},{"firstname":"Fred","id":2,"surname":"Smith"}]Date range search
find_enrichment_table_records!(
"test",
{
"surname": "Smith",
"date_of_birth": {
"from": t'1985-01-01T00:00:00Z',
"to": t'1985-12-31T00:00:00Z'
}
}
)
[{"firstname":"Bob","id":1,"surname":"Smith"},{"firstname":"Fred","id":2,"surname":"Smith"}]get_enrichment_table_record
Searches an enrichment table for a row that matches the provided condition. A single row must be matched. If no rows are found or more than one row is found, an error is returned.
For file enrichment tables, this condition needs to be a VRL object in which
the key-value pairs indicate a field to search mapped to a value to search in that field.
This function returns the rows that match the provided condition(s). All fields need to
match for rows to be returned; if any fields do not match, then no rows are returned.
There are currently three forms of search criteria:
Exact match search. The given field must match the value exactly. Case sensitivity can be specified using the
case_sensitiveargument. An exact match search can use an index directly into the dataset, which should make this search fairly “cheap” from a performance perspective.Wildcard match search. The given fields specified by the exact match search may also be matched exactly to the value provided to the
wildcardparameter. A wildcard match search can also use an index directly into the dataset.Date range search. The given field must be greater than or equal to the
fromdate and/or less than or equal to thetodate. A date range search involves sequentially scanning through the rows that have been located using any exact match criteria. This can be an expensive operation if there are many rows returned by any exact match criteria. Therefore, use date ranges as the only criteria when the enrichment data set is very small.
For geoip and mmdb enrichment tables, this condition needs to be a VRL object with a single key-value pair
whose value needs to be a valid IP address. Example: {"ip": .ip }. If a return field is expected
and without a value, null is used. This table can return the following fields:
ISP databases:
autonomous_system_numberautonomous_system_organizationisporganization
City databases:
city_namecontinent_codecountry_codecountry_nameregion_coderegion_namemetro_codelatitudelongitudepostal_codetimezone
Connection-Type databases:
connection_type
To use this function, you need to update your configuration to
include an
enrichment_tables
parameter.
Exact match
get_enrichment_table_record!("test", {"id": 1}){
"firstname": "Bob",
"id": 1,
"surname": "Smith"
}Case insensitive match
get_enrichment_table_record!(
"test",
{"surname": "bob", "firstname": "John"},
case_sensitive: false
)
{
"firstname": "Bob",
"id": 1,
"surname": "Smith"
}Date range search
get_enrichment_table_record!(
"test",
{
"surname": "Smith",
"date_of_birth": {
"from": t'1985-01-01T00:00:00Z',
"to": t'1985-12-31T00:00:00Z'
}
}
)
{
"firstname": "Bob",
"id": 1,
"surname": "Smith"
}Enumerate examples
compact
value by removing empty values, where empty values are defined using the available parameters.Compact an object with default parameters
compact({"field1": 1, "field2": "", "field3": [], "field4": null}){
"field1": 1
}Compact an array with default parameters
compact(["foo", "bar", "", null, [], "buzz"])["foo","bar","buzz"]Compact an array using nullish
compact(["-", " ", "\n", null, true], nullish: true)[true]Compact a complex object with default parameters
compact({ "a": {}, "b": null, "c": [null], "d": "", "e": "-", "f": true }){
"e": "-",
"f": true
}Compact a complex object using null: false
compact({ "a": {}, "b": null, "c": [null], "d": "", "e": "-", "f": true }, null: false){
"b": null,
"c": [
null
],
"e": "-",
"f": true
}filter
Filter elements from a collection.
This function currently does not support recursive iteration.
The function uses the function closure syntax to allow reading the key-value or index-value combination for each item in the collection.
The same scoping rules apply to closure blocks as they do for regular blocks. This means that any variable defined in parent scopes is accessible, and mutations to those variables are preserved, but any new variables instantiated in the closure block are unavailable outside of the block.
See the examples below to learn about the closure syntax.
Filter elements
. = { "tags": ["foo", "bar", "foo", "baz"] }
filter(array(.tags)) -> |_index, value| {
value != "foo"
}
["bar","baz"]Filter object
filter({ "a": 1, "b": 2 }) -> |key, _value| { key == "a" }{
"a": 1
}Filter array
filter([1, 2]) -> |_index, value| { value < 2 }[1]flatten
value into a single-level representation.Flatten array
flatten([1, [2, 3, 4], [5, [6, 7], 8], 9])[1,2,3,4,5,6,7,8,9]Flatten object
flatten({
"parent1": {
"child1": 1,
"child2": 2
},
"parent2": {
"child3": 3
}
})
{
"parent1.child1": 1,
"parent1.child2": 2,
"parent2.child3": 3
}Flatten object with custom separator
flatten({ "foo": { "bar": true }}, "_"){
"foo_bar": true
}for_each
Iterate over a collection.
This function currently does not support recursive iteration.
The function uses the “function closure syntax” to allow reading the key/value or index/value combination for each item in the collection.
The same scoping rules apply to closure blocks as they do for regular blocks. This means that any variable defined in parent scopes is accessible, and mutations to those variables are preserved, but any new variables instantiated in the closure block are unavailable outside of the block.
See the examples below to learn about the closure syntax.
Tally elements
.tags = ["foo", "bar", "foo", "baz"]
tally = {}
for_each(array(.tags)) -> |_index, value| {
count = int(get!(tally, [value])) ?? 0
tally = set!(tally, [value], count + 1)
}
tally
{
"bar": 1,
"baz": 1,
"foo": 2
}Iterate over an object
count = 0
for_each({ "a": 1, "b": 2 }) -> |_key, value| {
count = count + value
}
count
3Iterate over an array
count = 0
for_each([1, 2, 3]) -> |index, value| {
count = count + index + value
}
count
9includes
value array includes the specified item.Array includes
includes(["apple", "orange", "banana"], "banana")truekeys
Get keys from the object
keys({
"key1": "val1",
"key2": "val2"
})
["key1","key2"]length
Returns the length of the value.
- If
valueis an array, returns the number of elements. - If
valueis an object, returns the number of top-level keys. - If
valueis a string, returns the number of bytes in the string. If you want the number of characters, seestrlen.
Length (object)
length({
"portland": "Trail Blazers",
"seattle": "Supersonics"
})
2Length (nested object)
length({
"home": {
"city": "Portland",
"state": "Oregon"
},
"name": "Trail Blazers",
"mascot": {
"name": "Blaze the Trail Cat"
}
})
3Length (array)
length(["Trail Blazers", "Supersonics", "Grizzlies"])3Length (string)
length("The Planet of the Apes Musical")30map_keys
Map the keys within an object.
If recursive is enabled, the function iterates into nested
objects, using the following rules:
- Iteration starts at the root.
- For every nested object type:
- First return the key of the object type itself.
- Then recurse into the object, and loop back to item (1) in this list.
- Any mutation done on a nested object before recursing into it, are preserved.
- For every nested array type:
- First return the key of the array type itself.
- Then find all objects within the array, and apply item (2) to each individual object.
The above rules mean that map_keys with
recursive enabled finds all keys in the target,
regardless of whether nested objects are nested inside arrays.
The function uses the function closure syntax to allow reading the key for each item in the object.
The same scoping rules apply to closure blocks as they do for regular blocks. This means that any variable defined in parent scopes is accessible, and mutations to those variables are preserved, but any new variables instantiated in the closure block are unavailable outside of the block.
See the examples below to learn about the closure syntax.
Upcase keys
. = {
"foo": "foo",
"bar": "bar",
"baz": {"nested key": "val"}
}
map_keys(.) -> |key| { upcase(key) }
{
"BAR": "bar",
"BAZ": {
"nested key": "val"
},
"FOO": "foo"
}De-dot keys
. = {
"labels": {
"app.kubernetes.io/name": "mysql"
}
}
map_keys(., recursive: true) -> |key| { replace(key, ".", "_") }
{
"labels": {
"app_kubernetes_io/name": "mysql"
}
}Recursively map object keys
val = {
"a": 1,
"b": [{ "c": 2 }, { "d": 3 }],
"e": { "f": 4 }
}
map_keys(val, recursive: true) -> |key| { upcase(key) }
{
"A": 1,
"B": [
{
"C": 2
},
{
"D": 3
}
],
"E": {
"F": 4
}
}map_values
Map the values within a collection.
If recursive is enabled, the function iterates into nested
collections, using the following rules:
- Iteration starts at the root.
- For every nested collection type:
- First return the collection type itself.
- Then recurse into the collection, and loop back to item (1) in the list
- Any mutation done on a collection before recursing into it, are preserved.
The function uses the function closure syntax to allow mutating the value for each item in the collection.
The same scoping rules apply to closure blocks as they do for regular blocks, meaning, any variable defined in parent scopes are accessible, and mutations to those variables are preserved, but any new variables instantiated in the closure block are unavailable outside of the block.
Check out the examples below to learn about the closure syntax.
Upcase values
. = {
"foo": "foo",
"bar": "bar"
}
map_values(.) -> |value| { upcase(value) }
{
"bar": "BAR",
"foo": "FOO"
}Recursively map object values
val = {
"a": 1,
"b": [{ "c": 2 }, { "d": 3 }],
"e": { "f": 4 }
}
map_values(val, recursive: true) -> |value| {
if is_integer(value) { int!(value) + 1 } else { value }
}
{
"a": 2,
"b": [
{
"c": 3
},
{
"d": 4
}
],
"e": {
"f": 5
}
}match_array
value array matches the pattern. By default, it checks that at least one element matches, but can be set to determine if all the elements match.Match at least one element
match_array(["foobar", "bazqux"], r'foo')trueMatch all elements
match_array(["foo", "foobar", "barfoo"], r'foo', all: true)trueNot all elements match
match_array(["foo", "foobar", "baz"], r'foo', all: true)strlen
Returns the number of UTF-8 characters in value. This differs from
length which counts the number of bytes of a string.
Note: This is the count of Unicode scalar values which can sometimes differ from Unicode code points.
tally
tally
tally!(["foo", "bar", "foo", "baz"]){
"bar": 1,
"baz": 1,
"foo": 2
}tally_value
count matching values
tally_value(["foo", "bar", "foo", "baz"], "foo")2unflatten
value into a nested representation.Unflatten
unflatten({
"foo.bar.baz": true,
"foo.bar.qux": false,
"foo.quux": 42
})
{
"foo": {
"bar": {
"baz": true,
"qux": false
},
"quux": 42
}
}Unflatten recursively
unflatten({
"flattened.parent": {
"foo.bar": true,
"foo.baz": false
}
})
{
"flattened": {
"parent": {
"foo": {
"bar": true,
"baz": false
}
}
}
}Unflatten non-recursively
unflatten({
"flattened.parent": {
"foo.bar": true,
"foo.baz": false
}
}, recursive: false)
{
"flattened": {
"parent": {
"foo.bar": true,
"foo.baz": false
}
}
}Ignore inconsistent keys values
unflatten({
"a": 3,
"a.b": 2,
"a.c": 4
})
{
"a": {
"b": 2,
"c": 4
}
}Unflatten with custom separator
unflatten({ "foo_bar": true }, "_"){
"foo": {
"bar": true
}
}unique
Returns the unique values for an array.
The first occurrence of each element is kept.
Unique
unique(["foo", "bar", "foo", "baz"])["foo","bar","baz"]values
Get values from the object
values({"key1": "val1", "key2": "val2"})["val1","val2"]Get values from a complex object
values({"key1": "val1", "key2": [1, 2, 3], "key3": {"foo": "bar"}})["val1",[1,2,3],{"foo":"bar"}]Event examples
get_secret
Get the Datadog API key from the event metadata
get_secret("datadog_api_key")secret valueremove_secret
Remove the datadog api key
remove_secret("datadog_api_key")set_secret
Set the datadog api key
set_secret("datadog_api_key", "secret-value")set_semantic_meaning
Sets custom field semantic meaning
set_semantic_meaning(.foo, "bar")Path examples
del
Removes the field specified by the static path from the target.
For dynamic path deletion, see the remove function.
Rename a field
. = { "old": "foo" }
.new = del(.old)
.
{
"new": "foo"
}External target
. = { "foo": true, "bar": 10 }
del(.foo)
.
{
"bar": 10
}Delete field from variable
var = { "foo": true, "bar": 10 }
del(var.foo)
var
{
"bar": 10
}Delete object field
var = { "foo": {"nested": true}, "bar": 10 }
del(var.foo.nested, false)
var
{
"bar": 10,
"foo": {}
}Compact object field
var = { "foo": {"nested": true}, "bar": 10 }
del(var.foo.nested, true)
var
{
"bar": 10
}exists
Checks whether the path exists for the target.
This function distinguishes between a missing path
and a path with a null value. A regular path lookup,
such as .foo, cannot distinguish between the two cases
since it always returns null if the path doesn’t exist.
get
Dynamically get the value of a given path.
If you know the path you want to look up, use
static paths such as .foo.bar[1] to get the value of that
path. However, if you do not know the path names,
use the dynamic get function to get the requested value.
Single-segment top-level field
get!(value: {"foo": "bar"}, path: ["foo"])barReturns null for unknown field
get!(value: {"foo": "bar"}, path: ["baz"])Multi-segment nested field
get!(value: {"foo": { "bar": true }}, path: ["foo", "bar"])trueArray indexing (negative)
get!(value: ["foo", "bar", "baz"], path: [-2])barNested indexing
get!(value: {"foo": { "bar": [92, 42] }}, path: ["foo", "bar", 1])42Variable
var = { "foo": true }
get!(value: var, path: ["foo"])
trueMissing index
get!(value: {"foo": { "bar": [92, 42] }}, path: ["foo", "bar", 1, -1])Invalid segment type
get!(value: {"foo": { "bar": [92, 42] }}, path: ["foo", true])remove
Dynamically remove the value for a given path.
If you know the path you want to remove, use
the del function and static paths such as del(.foo.bar[1])
to remove the value at that path. The del function returns the
deleted value, and is more performant than remove.
However, if you do not know the path names, use the dynamic
remove function to remove the value at the provided path.
Single-segment top-level field
remove!(value: { "foo": "bar" }, path: ["foo"])Remove unknown field
remove!(value: {"foo": "bar"}, path: ["baz"]){
"foo": "bar"
}Multi-segment nested field
remove!(value: { "foo": { "bar": "baz" } }, path: ["foo", "bar"]){
"foo": {}
}Array indexing
remove!(value: ["foo", "bar", "baz"], path: [-2])["foo","baz"]Compaction
remove!(value: { "foo": { "bar": [42], "baz": true } }, path: ["foo", "bar", 0], compact: true){
"foo": {
"baz": true
}
}Compact object
remove!(value: {"foo": { "bar": true }}, path: ["foo", "bar"], compact: true)Compact array
remove!(value: {"foo": [42], "bar": true }, path: ["foo", 0], compact: true){
"bar": true
}Variable
var = { "foo": true }
remove!(value: var, path: ["foo"])
Missing index
remove!(value: {"foo": { "bar": [92, 42] }}, path: ["foo", "bar", 1, -1]){
"foo": {
"bar": [
92,
42
]
}
}Invalid indexing
remove!(value: [42], path: ["foo"])[42]Invalid segment type
remove!(value: {"foo": { "bar": [92, 42] }}, path: ["foo", true])set
Dynamically insert data into the path of a given object or array.
If you know the path you want to assign a value to,
use static path assignments such as .foo.bar[1] = true for
improved performance and readability. However, if you do not
know the path names, use the dynamic set function to
insert the data into the object or array.
Single-segment top-level field
set!(value: { "foo": "bar" }, path: ["foo"], data: "baz"){
"foo": "baz"
}Multi-segment nested field
set!(value: { "foo": { "bar": "baz" } }, path: ["foo", "bar"], data: "qux"){
"foo": {
"bar": "qux"
}
}Array
set!(value: ["foo", "bar", "baz"], path: [-2], data: 42)["foo",42,"baz"]Nested fields
set!(value: {}, path: ["foo", "bar"], data: "baz"){
"foo": {
"bar": "baz"
}
}Nested indexing
set!(value: {"foo": { "bar": [] }}, path: ["foo", "bar", 1], data: "baz"){
"foo": {
"bar": [
null,
"baz"
]
}
}External target
set!(value: ., path: ["bar"], data: "baz"){
"bar": "baz",
"foo": true
}Variable
var = { "foo": true }
set!(value: var, path: ["bar"], data: "baz")
{
"bar": "baz",
"foo": true
}Invalid indexing
set!(value: [], path: ["foo"], data: "baz"){
"foo": "baz"
}Invalid segment type
set!({"foo": { "bar": [92, 42] }}, ["foo", true], "baz")Cryptography examples
decrypt
Decrypts a string with a symmetric encryption algorithm.
Supported Algorithms:
- AES-256-CFB (key = 32 bytes, iv = 16 bytes)
- AES-192-CFB (key = 24 bytes, iv = 16 bytes)
- AES-128-CFB (key = 16 bytes, iv = 16 bytes)
- AES-256-OFB (key = 32 bytes, iv = 16 bytes)
- AES-192-OFB (key = 24 bytes, iv = 16 bytes)
- AES-128-OFB (key = 16 bytes, iv = 16 bytes)
- AES-128-SIV (key = 32 bytes, iv = 16 bytes)
- AES-256-SIV (key = 64 bytes, iv = 16 bytes)
- Deprecated - AES-256-CTR (key = 32 bytes, iv = 16 bytes)
- Deprecated - AES-192-CTR (key = 24 bytes, iv = 16 bytes)
- Deprecated - AES-128-CTR (key = 16 bytes, iv = 16 bytes)
- AES-256-CTR-LE (key = 32 bytes, iv = 16 bytes)
- AES-192-CTR-LE (key = 24 bytes, iv = 16 bytes)
- AES-128-CTR-LE (key = 16 bytes, iv = 16 bytes)
- AES-256-CTR-BE (key = 32 bytes, iv = 16 bytes)
- AES-192-CTR-BE (key = 24 bytes, iv = 16 bytes)
- AES-128-CTR-BE (key = 16 bytes, iv = 16 bytes)
- AES-256-CBC-PKCS7 (key = 32 bytes, iv = 16 bytes)
- AES-192-CBC-PKCS7 (key = 24 bytes, iv = 16 bytes)
- AES-128-CBC-PKCS7 (key = 16 bytes, iv = 16 bytes)
- AES-256-CBC-ANSIX923 (key = 32 bytes, iv = 16 bytes)
- AES-192-CBC-ANSIX923 (key = 24 bytes, iv = 16 bytes)
- AES-128-CBC-ANSIX923 (key = 16 bytes, iv = 16 bytes)
- AES-256-CBC-ISO7816 (key = 32 bytes, iv = 16 bytes)
- AES-192-CBC-ISO7816 (key = 24 bytes, iv = 16 bytes)
- AES-128-CBC-ISO7816 (key = 16 bytes, iv = 16 bytes)
- AES-256-CBC-ISO10126 (key = 32 bytes, iv = 16 bytes)
- AES-192-CBC-ISO10126 (key = 24 bytes, iv = 16 bytes)
- AES-128-CBC-ISO10126 (key = 16 bytes, iv = 16 bytes)
- CHACHA20-POLY1305 (key = 32 bytes, iv = 12 bytes)
- XCHACHA20-POLY1305 (key = 32 bytes, iv = 24 bytes)
- XSALSA20-POLY1305 (key = 32 bytes, iv = 24 bytes)
Decrypt value using AES-256-CFB
iv = "0123456789012345"
key = "01234567890123456789012345678912"
ciphertext = decode_base64!("c/dIOA==")
decrypt!(ciphertext, "AES-256-CFB", key: key, iv: iv)
dataDecrypt value using AES-128-CBC-PKCS7
iv = decode_base64!("fVEIRkIiczCRWNxaarsyxA==")
key = "16_byte_keyxxxxx"
ciphertext = decode_base64!("5fLGcu1VHdzsPcGNDio7asLqE1P43QrVfPfmP4i4zOU=")
decrypt!(ciphertext, "AES-128-CBC-PKCS7", key: key, iv: iv)
super_secret_messageencrypt
Encrypts a string with a symmetric encryption algorithm.
Supported Algorithms:
- AES-256-CFB (key = 32 bytes, iv = 16 bytes)
- AES-192-CFB (key = 24 bytes, iv = 16 bytes)
- AES-128-CFB (key = 16 bytes, iv = 16 bytes)
- AES-256-OFB (key = 32 bytes, iv = 16 bytes)
- AES-192-OFB (key = 24 bytes, iv = 16 bytes)
- AES-128-OFB (key = 16 bytes, iv = 16 bytes)
- AES-128-SIV (key = 32 bytes, iv = 16 bytes)
- AES-256-SIV (key = 64 bytes, iv = 16 bytes)
- Deprecated - AES-256-CTR (key = 32 bytes, iv = 16 bytes)
- Deprecated - AES-192-CTR (key = 24 bytes, iv = 16 bytes)
- Deprecated - AES-128-CTR (key = 16 bytes, iv = 16 bytes)
- AES-256-CTR-LE (key = 32 bytes, iv = 16 bytes)
- AES-192-CTR-LE (key = 24 bytes, iv = 16 bytes)
- AES-128-CTR-LE (key = 16 bytes, iv = 16 bytes)
- AES-256-CTR-BE (key = 32 bytes, iv = 16 bytes)
- AES-192-CTR-BE (key = 24 bytes, iv = 16 bytes)
- AES-128-CTR-BE (key = 16 bytes, iv = 16 bytes)
- AES-256-CBC-PKCS7 (key = 32 bytes, iv = 16 bytes)
- AES-192-CBC-PKCS7 (key = 24 bytes, iv = 16 bytes)
- AES-128-CBC-PKCS7 (key = 16 bytes, iv = 16 bytes)
- AES-256-CBC-ANSIX923 (key = 32 bytes, iv = 16 bytes)
- AES-192-CBC-ANSIX923 (key = 24 bytes, iv = 16 bytes)
- AES-128-CBC-ANSIX923 (key = 16 bytes, iv = 16 bytes)
- AES-256-CBC-ISO7816 (key = 32 bytes, iv = 16 bytes)
- AES-192-CBC-ISO7816 (key = 24 bytes, iv = 16 bytes)
- AES-128-CBC-ISO7816 (key = 16 bytes, iv = 16 bytes)
- AES-256-CBC-ISO10126 (key = 32 bytes, iv = 16 bytes)
- AES-192-CBC-ISO10126 (key = 24 bytes, iv = 16 bytes)
- AES-128-CBC-ISO10126 (key = 16 bytes, iv = 16 bytes)
- CHACHA20-POLY1305 (key = 32 bytes, iv = 12 bytes)
- XCHACHA20-POLY1305 (key = 32 bytes, iv = 24 bytes)
- XSALSA20-POLY1305 (key = 32 bytes, iv = 24 bytes)
Encrypt value using AES-256-CFB
iv = "0123456789012345" # typically you would call random_bytes(16)
key = "01234567890123456789012345678912"
encrypted_message = encrypt!("data", "AES-256-CFB", key: key, iv: iv)
encode_base64(encrypted_message)
c/dIOA==Encrypt value using AES-128-CBC-PKCS7
iv = "1234567890123456" # typically you would call random_bytes(16)
key = "16_byte_keyxxxxx"
encrypted_message = encrypt!("super secret message", "AES-128-CBC-PKCS7", key: key, iv: iv)
encode_base64(encrypted_message)
GBw8Mu00v0Kc38+/PvsVtGgWuUJ+ZNLgF8Opy8ohIYE=hmac
Calculates a HMAC of the value using the given key.
The hashing algorithm used can be optionally specified.
For most use cases, the resulting bytestream should be encoded into a hex or base64 string using either encode_base16 or encode_base64.
This function is infallible if either the default algorithm value or a recognized-valid compile-time
algorithm string literal is used. Otherwise, it is fallible.
Calculate message HMAC (defaults: SHA-256), encoding to a base64 string
encode_base64(hmac("Hello there", "super-secret-key"))eLGE8YMviv85NPXgISRUZxstBNSU47JQdcXkUWcClmI=Calculate message HMAC using SHA-224, encoding to a hex-encoded string
encode_base16(hmac("Hello there", "super-secret-key", algorithm: "SHA-224"))42fccbc2b7d22a143b92f265a8046187558a94d11ddbb30622207e90Calculate message HMAC using SHA1, encoding to a base64 string
encode_base64(hmac("Hello there", "super-secret-key", algorithm: "SHA1"))MiyBIHO8Set9+6crALiwkS0yFPE=Calculate message HMAC using a variable hash algorithm
.hash_algo = "SHA-256"
hmac_bytes, err = hmac("Hello there", "super-secret-key", algorithm: .hash_algo)
if err == null {
.hmac = encode_base16(hmac_bytes)
}
78b184f1832f8aff3934f5e0212454671b2d04d494e3b25075c5e45167029662md5
value.Create md5 hash
md5("foo")acbd18db4cc2f85cedef654fccc4a4d8seahash
value.
Note: Due to limitations in the underlying VRL data types, this function converts the unsigned 64-bit integer SeaHash result to a signed 64-bit integer. Results higher than the signed 64-bit integer maximum value wrap around to negative values.sha1
value.Calculate sha1 hash
sha1("foo")0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33sha2
value.Calculate sha2 hash using default variant
sha2("foobar")d014c752bc2be868e16330f47e0c316a5967bcbc9c286a457761d7055b9214ceCalculate sha2 hash with SHA-512/224
sha2("foo", variant: "SHA-512/224")d68f258d37d670cfc1ec1001a0394784233f88f056994f9a7e5e99beCalculate sha2 hash with SHA-384
sha2("foobar", "SHA-384")3c9c30d9f665e74d515c842960d4a451c83a0125fd3de7392d7b37231af10c72ea58aedfcdf89a5765bf902af93ecf06sha3
value.Calculate sha3 hash using default variant
sha3("foobar")ff32a30c3af5012ea395827a3e99a13073c3a8d8410a708568ff7e6eb85968fccfebaea039bc21411e9d43fdb9a851b529b9960ffea8679199781b8f45ca85e2Calculate sha3 hash with SHA3-224
sha3("foo", variant: "SHA3-224")f4f6779e153c391bbd29c95e72b0708e39d9166c7cea51d1f10ef58aCalculate sha3 hash with SHA3-384
sha3("foobar", "SHA3-384")0fa8abfbdaf924ad307b74dd2ed183b9a4a398891a2f6bac8fd2db7041b77f068580f9c6c66f699b496c2da1cbcc7ed8IP examples
decrypt_ip
Decrypts an IP address that was previously encrypted, restoring the original IP address.
Supported Modes:
- AES128 - Decrypts an IP address that was scrambled using AES-128 encryption. Can transform between IPv4 and IPv6.
- PFX (Prefix-preserving) - Decrypts an IP address that was encrypted with prefix-preserving mode, where network hierarchy was maintained.
Decrypt IPv4 address with AES128
decrypt_ip!("72b9:a747:f2e9:72af:76ca:5866:6dcf:c3b0", "sixteen byte key", "aes128")192.168.1.1Decrypt IPv6 address with AES128
decrypt_ip!("c0e6:eb35:6887:f554:4c65:8ace:17ca:6c6a", "sixteen byte key", "aes128")2001:db8::1Decrypt IPv4 address with prefix-preserving mode
decrypt_ip!("33.245.248.61", "thirty-two bytes key for pfx use", "pfx")192.168.1.1Decrypt IPv6 address with prefix-preserving mode
decrypt_ip!("88bd:d2bf:8865:8c4d:84b:44f6:6077:72c9", "thirty-two bytes key for ipv6pfx", "pfx")2001:db8::1Round-trip encryption and decryption
original_ip = "192.168.1.100"
key = "sixteen byte key"
mode = "aes128"
encrypted = encrypt_ip!(original_ip, key, mode)
decrypt_ip!(encrypted, key, mode)
192.168.1.100encrypt_ip
Encrypts an IP address, transforming it into a different valid IP address.
Supported Modes:
- AES128 - Scrambles the entire IP address using AES-128 encryption. Can transform between IPv4 and IPv6.
- PFX (Prefix-preserving) - Maintains network hierarchy by ensuring that IP addresses within the same network are encrypted to addresses that also share a common network. This preserves prefix relationships while providing confidentiality.
Encrypt IPv4 address with AES128
encrypt_ip!("192.168.1.1", "sixteen byte key", "aes128")72b9:a747:f2e9:72af:76ca:5866:6dcf:c3b0Encrypt IPv6 address with AES128
encrypt_ip!("2001:db8::1", "sixteen byte key", "aes128")c0e6:eb35:6887:f554:4c65:8ace:17ca:6c6aEncrypt IPv4 address with prefix-preserving mode
encrypt_ip!("192.168.1.1", "thirty-two bytes key for pfx use", "pfx")33.245.248.61Encrypt IPv6 address with prefix-preserving mode
encrypt_ip!("2001:db8::1", "thirty-two bytes key for ipv6pfx", "pfx")88bd:d2bf:8865:8c4d:84b:44f6:6077:72c9ip_aton
Converts IPv4 address in numbers-and-dots notation into network-order bytes represented as an integer.
This behavior mimics inet_aton.
ip_cidr_contains
ip is contained in the block referenced by the cidr.IPv4 contains CIDR
ip_cidr_contains!("192.168.0.0/16", "192.168.10.32")trueIPv4 is private
ip_cidr_contains!(["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"], "192.168.10.32")trueIPv6 contains CIDR
ip_cidr_contains!("2001:4f8:4:ba::/64", "2001:4f8:4:ba:2e0:81ff:fe22:d1f1")trueNot in range
ip_cidr_contains!("192.168.0.0/24", "192.168.10.32")Invalid address
ip_cidr_contains!("192.168.0.0/24", "INVALID")ip_ntoa
Converts numeric representation of IPv4 address in network-order bytes to numbers-and-dots notation.
This behavior mimics inet_ntoa.
ip_ntop
Converts IPv4 and IPv6 addresses from binary to text form.
This behavior mimics inet_ntop.
Convert IPv4 address from bytes after decoding from Base64
ip_ntop!(decode_base64!("wKgAAQ=="))192.168.0.1Convert IPv6 address from bytes after decoding from Base64
ip_ntop!(decode_base64!("IAENuIWjAAAAAIouA3BzNA=="))2001:db8:85a3::8a2e:370:7334ip_pton
Converts IPv4 and IPv6 addresses from text to binary form.
- The binary form of IPv4 addresses is 4 bytes (32 bits) long.
- The binary form of IPv6 addresses is 16 bytes (128 bits) long.
This behavior mimics inet_pton.
Convert IPv4 address to bytes and encode to Base64
encode_base64(ip_pton!("192.168.0.1"))wKgAAQ==Convert IPv6 address to bytes and encode to Base64
encode_base64(ip_pton!("2001:db8:85a3::8a2e:370:7334"))IAENuIWjAAAAAIouA3BzNA==ip_subnet
ip using the supplied subnet.IPv4 subnet
ip_subnet!("192.168.10.32", "255.255.255.0")192.168.10.0IPv6 subnet
ip_subnet!("2404:6800:4003:c02::64", "/32")2404:6800::Subnet /1
ip_subnet!("192.168.0.1", "/1")128.0.0.0ip_to_ipv6
ip to an IPv6 address.IPv4 to IPv6
ip_to_ipv6!("192.168.10.32")::ffff:192.168.10.32ipv6_to_ipv4
ip to an IPv4 address. ip is returned unchanged if it’s already an IPv4 address. If ip is
currently an IPv6 address then it needs to be IPv4 compatible, otherwise an error is thrown.IPv6 to IPv4
ipv6_to_ipv4!("::ffff:192.168.0.1")192.168.0.1is_ipv4
Check if the string is a valid IPv4 address or not.
An IPv4-mapped or IPv4-compatible IPv6 address is not considered valid for the purpose of this function.
is_ipv6
Map examples
haversine
Haversine in kilometers
haversine(0.0, 0.0, 10.0, 10.0){
"bearing": 44.561,
"distance": 1568.5227233
}Haversine in miles
haversine(0.0, 0.0, 10.0, 10.0, measurement_unit: "miles"){
"bearing": 44.561,
"distance": 974.6348468
}Metrics examples
aggregate_vector_metrics
Aggregates internal Vector metrics, using one of 4 aggregation functions, filtering by name and optionally by tags. Returns the aggregated value. Only includes counter and gauge metrics.
Internal Vector metrics functions work with a snapshot of the metrics. The interval at which the snapshot is updated is controlled through the metrics_storage_refresh_period global option. Higher values can reduce performance impact of that process, but may cause stale metrics data in the snapshot.
Sum vector internal metrics matching the name
aggregate_vector_metrics("sum", "utilization")0.5Sum vector internal metrics matching the name and tags
aggregate_vector_metrics("sum", "utilization", tags: {"component_id": "test"})0.5Average of vector internal metrics matching the name
aggregate_vector_metrics("avg", "utilization")0.5Max of vector internal metrics matching the name
aggregate_vector_metrics("max", "utilization")0.5Min of vector internal metrics matching the name
aggregate_vector_metrics("max", "utilization")0.5find_vector_metrics
Searches internal Vector metrics by name and optionally by tags. Returns all matching metrics.
Internal Vector metrics functions work with a snapshot of the metrics. The interval at which the snapshot is updated is controlled through the metrics_storage_refresh_period global option. Higher values can reduce performance impact of that process, but may cause stale metrics data in the snapshot.
Find vector internal metrics matching the name
find_vector_metrics("utilization")[{"kind":"absolute","name":"utilization","tags":{"component_id":["test"]},"type":"gauge","value":0.5}]Find vector internal metrics matching the name and tags
find_vector_metrics("utilization", tags: {"component_id": "test"})[{"kind":"absolute","name":"utilization","tags":{"component_id":["test"]},"type":"gauge","value":0.5}]get_vector_metric
Searches internal Vector metrics by name and optionally by tags. Returns the first matching metric.
Internal Vector metrics functions work with a snapshot of the metrics. The interval at which the snapshot is updated is controlled through the metrics_storage_refresh_period global option. Higher values can reduce performance impact of that process, but may cause stale metrics data in the snapshot.
Get a vector internal metric matching the name
get_vector_metric("utilization"){
"kind": "absolute",
"name": "utilization",
"tags": {
"component_id": [
"test"
]
},
"type": "gauge",
"value": 0.5
}Get a vector internal metric matching the name and tags
get_vector_metric("utilization", tags: {"component_id": "test"}){
"kind": "absolute",
"name": "utilization",
"tags": {
"component_id": [
"test"
]
},
"type": "gauge",
"value": 0.5
}Number examples
abs
value.ceil
value up to the specified precision.floor
value down to the specified precision.format_int
value into a string representation using the given base/radix.Format as a hexadecimal integer
format_int!(42, 16)2aFormat as a negative hexadecimal integer
format_int!(-42, 16)-2aFormat as a decimal integer (default base)
format_int!(42)42format_number
value into a string representation of the number.Format a number (3 decimals)
format_number(1234567.89, 3, decimal_separator: ".", grouping_separator: ",")1,234,567.890Format a number with European-style separators
format_number(4672.4, decimal_separator: ",", grouping_separator: "_")4_672,4Format a number with a middle dot separator
format_number(4321.09, 3, decimal_separator: "·")4321·090mod
value divided by modulus.round
value to the specified precision.Round a number (with precision)
round(4.345, precision: 2)4.35Object examples
match_datadog_query
OR query
match_datadog_query({"message": "contains this and that"}, "this OR that")trueAND query
match_datadog_query({"message": "contains only this"}, "this AND that")Attribute wildcard
match_datadog_query({"name": "foobar"}, "@name:foo*")trueTag range
match_datadog_query({"tags": ["a:x", "b:y", "c:z"]}, s'b:["x" TO "z"]')truemerge
from object into the to object.Object merge (shallow)
merge(
{
"parent1": {
"child1": 1,
"child2": 2
},
"parent2": {
"child3": 3
}
},
{
"parent1": {
"child2": 4,
"child5": 5
}
}
)
{
"parent1": {
"child2": 4,
"child5": 5
},
"parent2": {
"child3": 3
}
}Object merge (deep)
merge(
{
"parent1": {
"child1": 1,
"child2": 2
},
"parent2": {
"child3": 3
}
},
{
"parent1": {
"child2": 4,
"child5": 5
}
},
deep: true
)
{
"parent1": {
"child1": 1,
"child2": 4,
"child5": 5
},
"parent2": {
"child3": 3
}
}object_from_array
Iterate over either one array of arrays or a pair of arrays and create an object out of all the key-value pairs contained in them.
With one array of arrays, any entries with no value use null instead.
Any keys that are null skip the corresponding value.
If a single parameter is given, it must contain an array of all the input arrays.
Create an object from one array
object_from_array([["one", 1], [null, 2], ["two", 3]]){
"one": 1,
"two": 3
}Create an object from separate key and value arrays
object_from_array([1, 2, 3], keys: ["one", null, "two"]){
"one": 1,
"two": 3
}Create an object from a separate arrays of keys and values
object_from_array(values: [1, null, true], keys: ["a", "b", "c"]){
"a": 1,
"b": null,
"c": true
}unnest
Unnest an array field from an object to create an array of objects using that field; keeping all other fields.
Assigning the array result of this to . results in multiple events being emitted from remap. See the
remap transform docs for more details.
This is also referred to as explode in some languages.
Unnest an array field
. = {"hostname": "localhost", "messages": ["message 1", "message 2"]}
. = unnest(.messages)
[{"hostname":"localhost","messages":"message 1"},{"hostname":"localhost","messages":"message 2"}]Unnest a nested array field
. = {"hostname": "localhost", "event": {"messages": ["message 1", "message 2"]}}
. = unnest(.event.messages)
[{"event":{"messages":"message 1"},"hostname":"localhost"},{"event":{"messages":"message 2"},"hostname":"localhost"}]Parse examples
parse_apache_log
common,
combined, or the default error format.Parse using Apache log format (common)
parse_apache_log!(s'127.0.0.1 bob frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326', format: "common"){
"host": "127.0.0.1",
"identity": "bob",
"message": "GET /apache_pb.gif HTTP/1.0",
"method": "GET",
"path": "/apache_pb.gif",
"protocol": "HTTP/1.0",
"size": 2326,
"status": 200,
"timestamp": "2000-10-10T20:55:36Z",
"user": "frank"
}Parse using Apache log format (combined)
parse_apache_log!(
s'127.0.0.1 bob frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.seniorinfomediaries.com/vertical/channels/front-end/bandwidth" "Mozilla/5.0 (X11; Linux i686; rv:5.0) Gecko/1945-10-12 Firefox/37.0"',
"combined",
)
{
"agent": "Mozilla/5.0 (X11; Linux i686; rv:5.0) Gecko/1945-10-12 Firefox/37.0",
"host": "127.0.0.1",
"identity": "bob",
"message": "GET /apache_pb.gif HTTP/1.0",
"method": "GET",
"path": "/apache_pb.gif",
"protocol": "HTTP/1.0",
"referrer": "http://www.seniorinfomediaries.com/vertical/channels/front-end/bandwidth",
"size": 2326,
"status": 200,
"timestamp": "2000-10-10T20:55:36Z",
"user": "frank"
}Parse using Apache log format (error)
parse_apache_log!(
s'[01/Mar/2021:12:00:19 +0000] [ab:alert] [pid 4803:tid 3814] [client 147.159.108.175:24259] I will bypass the haptic COM bandwidth, that should matrix the CSS driver!',
"error"
)
{
"client": "147.159.108.175",
"message": "I will bypass the haptic COM bandwidth, that should matrix the CSS driver!",
"module": "ab",
"pid": 4803,
"port": 24259,
"severity": "alert",
"thread": "3814",
"timestamp": "2021-03-01T12:00:19Z"
}parse_aws_alb_log
value in the Elastic Load Balancer Access format.Parse AWS ALB log
parse_aws_alb_log!(
"http 2018-11-30T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 192.168.131.39:2817 - 0.000 0.001 0.000 200 200 34 366 \"GET http://www.example.com:80/ HTTP/1.1\" \"curl/7.46.0\" - - arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 \"Root=1-58337364-23a8c76965a2ef7629b185e3\" \"-\" \"-\" 0 2018-11-30T22:22:48.364000Z \"forward\" \"-\" \"-\" \"-\" \"-\" \"-\" \"-\""
)
{
"actions_executed": "forward",
"chosen_cert_arn": null,
"classification": null,
"classification_reason": null,
"client_host": "192.168.131.39:2817",
"domain_name": null,
"elb": "app/my-loadbalancer/50dc6c495c0c9188",
"elb_status_code": "200",
"error_reason": null,
"matched_rule_priority": "0",
"received_bytes": 34,
"redirect_url": null,
"request_creation_time": "2018-11-30T22:22:48.364000Z",
"request_method": "GET",
"request_processing_time": 0,
"request_protocol": "HTTP/1.1",
"request_url": "http://www.example.com:80/",
"response_processing_time": 0,
"sent_bytes": 366,
"ssl_cipher": null,
"ssl_protocol": null,
"target_group_arn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
"target_host": null,
"target_port_list": [],
"target_processing_time": 0.001,
"target_status_code": "200",
"target_status_code_list": [],
"timestamp": "2018-11-30T22:23:00.186641Z",
"trace_id": "Root=1-58337364-23a8c76965a2ef7629b185e3",
"traceability_id": null,
"type": "http",
"user_agent": "curl/7.46.0"
}Parse AWS ALB log with trailing fields (non-strict mode)
parse_aws_alb_log!(
"http 2018-11-30T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 192.168.131.39:2817 - 0.000 0.001 0.000 200 200 34 366 \"GET http://www.example.com:80/ HTTP/1.1\" \"curl/7.46.0\" - - arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 \"Root=1-58337364-23a8c76965a2ef7629b185e3\" \"-\" \"-\" 0 2018-11-30T22:22:48.364000Z \"forward\" \"-\" \"-\" \"-\" \"-\" \"-\" \"-\" TID_12345 \"-\" \"-\" \"-\"",
strict_mode: false
)
{
"actions_executed": "forward",
"chosen_cert_arn": null,
"classification": null,
"classification_reason": null,
"client_host": "192.168.131.39:2817",
"domain_name": null,
"elb": "app/my-loadbalancer/50dc6c495c0c9188",
"elb_status_code": "200",
"error_reason": null,
"matched_rule_priority": "0",
"received_bytes": 34,
"redirect_url": null,
"request_creation_time": "2018-11-30T22:22:48.364000Z",
"request_method": "GET",
"request_processing_time": 0,
"request_protocol": "HTTP/1.1",
"request_url": "http://www.example.com:80/",
"response_processing_time": 0,
"sent_bytes": 366,
"ssl_cipher": null,
"ssl_protocol": null,
"target_group_arn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067",
"target_host": null,
"target_port_list": [],
"target_processing_time": 0.001,
"target_status_code": "200",
"target_status_code_list": [],
"timestamp": "2018-11-30T22:23:00.186641Z",
"trace_id": "Root=1-58337364-23a8c76965a2ef7629b185e3",
"traceability_id": "TID_12345",
"type": "http",
"user_agent": "curl/7.46.0"
}parse_aws_cloudwatch_log_subscription_message
aws_kinesis_firehose source.Parse AWS Cloudwatch Log subscription message
parse_aws_cloudwatch_log_subscription_message!(s'{
"messageType": "DATA_MESSAGE",
"owner": "111111111111",
"logGroup": "test",
"logStream": "test",
"subscriptionFilters": [
"Destination"
],
"logEvents": [
{
"id": "35683658089614582423604394983260738922885519999578275840",
"timestamp": 1600110569039,
"message": "{\"bytes\":26780,\"datetime\":\"14/Sep/2020:11:45:41-0400\",\"host\":\"157.130.216.193\",\"method\":\"PUT\",\"protocol\":\"HTTP/1.0\",\"referer\":\"https://www.principalcross-platform.io/markets/ubiquitous\",\"request\":\"/expedite/convergence\",\"source_type\":\"stdin\",\"status\":301,\"user-identifier\":\"-\"}"
}
]
}')
{
"log_events": [
{
"id": "35683658089614582423604394983260738922885519999578275840",
"message": "{\"bytes\":26780,\"datetime\":\"14/Sep/2020:11:45:41-0400\",\"host\":\"157.130.216.193\",\"method\":\"PUT\",\"protocol\":\"HTTP/1.0\",\"referer\":\"https://www.principalcross-platform.io/markets/ubiquitous\",\"request\":\"/expedite/convergence\",\"source_type\":\"stdin\",\"status\":301,\"user-identifier\":\"-\"}",
"timestamp": "2020-09-14T19:09:29.039Z"
}
],
"log_group": "test",
"log_stream": "test",
"message_type": "DATA_MESSAGE",
"owner": "111111111111",
"subscription_filters": [
"Destination"
]
}parse_aws_vpc_flow_log
value in the VPC Flow Logs format.Parse AWS VPC Flow log (default format)
parse_aws_vpc_flow_log!("2 123456789010 eni-1235b8ca123456789 - - - - - - - 1431280876 1431280934 - NODATA"){
"account_id": "123456789010",
"action": null,
"bytes": null,
"dstaddr": null,
"dstport": null,
"end": 1431280934,
"interface_id": "eni-1235b8ca123456789",
"log_status": "NODATA",
"packets": null,
"protocol": null,
"srcaddr": null,
"srcport": null,
"start": 1431280876,
"version": 2
}Parse AWS VPC Flow log (custom format)
parse_aws_vpc_flow_log!(
"- eni-1235b8ca123456789 10.0.1.5 10.0.0.220 10.0.1.5 203.0.113.5",
"instance_id interface_id srcaddr dstaddr pkt_srcaddr pkt_dstaddr"
)
{
"dstaddr": "10.0.0.220",
"instance_id": null,
"interface_id": "eni-1235b8ca123456789",
"pkt_dstaddr": "203.0.113.5",
"pkt_srcaddr": "10.0.1.5",
"srcaddr": "10.0.1.5"
}Parse AWS VPC Flow log including v5 fields
parse_aws_vpc_flow_log!(
"5 52.95.128.179 10.0.0.71 80 34210 6 1616729292 1616729349 IPv4 14 15044 123456789012 vpc-abcdefab012345678 subnet-aaaaaaaa012345678 i-0c50d5961bcb2d47b eni-1235b8ca123456789 ap-southeast-2 apse2-az3 - - ACCEPT 19 52.95.128.179 10.0.0.71 S3 - - ingress OK",
format: "version srcaddr dstaddr srcport dstport protocol start end type packets bytes account_id vpc_id subnet_id instance_id interface_id region az_id sublocation_type sublocation_id action tcp_flags pkt_srcaddr pkt_dstaddr pkt_src_aws_service pkt_dst_aws_service traffic_path flow_direction log_status"
)
{
"account_id": "123456789012",
"action": "ACCEPT",
"az_id": "apse2-az3",
"bytes": 15044,
"dstaddr": "10.0.0.71",
"dstport": 34210,
"end": 1616729349,
"flow_direction": "ingress",
"instance_id": "i-0c50d5961bcb2d47b",
"interface_id": "eni-1235b8ca123456789",
"log_status": "OK",
"packets": 14,
"pkt_dst_aws_service": null,
"pkt_dstaddr": "10.0.0.71",
"pkt_src_aws_service": "S3",
"pkt_srcaddr": "52.95.128.179",
"protocol": 6,
"region": "ap-southeast-2",
"srcaddr": "52.95.128.179",
"srcport": 80,
"start": 1616729292,
"sublocation_id": null,
"sublocation_type": null,
"subnet_id": "subnet-aaaaaaaa012345678",
"tcp_flags": 19,
"traffic_path": null,
"type": "IPv4",
"version": 5,
"vpc_id": "vpc-abcdefab012345678"
}parse_bytes
value into a human-readable bytes format specified by unit and base.Parse bytes (kilobytes)
parse_bytes!("1024KiB", unit: "MiB")1Parse kilobytes in default binary units
parse_bytes!("1KiB", unit: "B")1024Parse bytes in SI unit (terabytes)
parse_bytes!("4TB", unit: "MB", base: "10")4000000Parse gigabytes in decimal units
parse_bytes!("1GB", unit: "B", base: "10")1000000000Parse bytes in ambiguous unit (gigabytes)
parse_bytes!("1GB", unit: "B", base: "2")1073741824Parse gigabytes in ambiguous decimal units
parse_bytes!("1GB", unit: "MB", base: "2")1024parse_cbor
value as CBOR.Parse CBOR
parse_cbor!(decode_base64!("oWVmaWVsZGV2YWx1ZQ==")){
"field": "value"
}array
parse_cbor!(decode_base64!("gvUA"))[true,0]string
parse_cbor!(decode_base64!("ZWhlbGxv"))hellofloat
parse_cbor!(decode_base64!("+0BFEKPXCj1x"))42.13parse_cef
value in CEF (Common Event Format) format. Ignores everything up to CEF header. Empty values are returned as empty strings. Surrounding quotes are removed from values.Parse output generated by PTA
parse_cef!(
"CEF:0|CyberArk|PTA|12.6|1|Suspected credentials theft|8|suser=mike2@prod1.domain.com shost=prod1.domain.com src=1.1.1.1 duser=andy@dev1.domain.com dhost=dev1.domain.com dst=2.2.2.2 cs1Label=ExtraData cs1=None cs2Label=EventID cs2=52b06812ec3500ed864c461e deviceCustomDate1Label=detectionDate deviceCustomDate1=1388577900000 cs3Label=PTAlink cs3=https://1.1.1.1/incidents/52b06812ec3500ed864c461e cs4Label=ExternalLink cs4=None"
)
{
"cefVersion": "0",
"cs1": "None",
"cs1Label": "ExtraData",
"cs2": "52b06812ec3500ed864c461e",
"cs2Label": "EventID",
"cs3": "https://1.1.1.1/incidents/52b06812ec3500ed864c461e",
"cs3Label": "PTAlink",
"cs4": "None",
"cs4Label": "ExternalLink",
"deviceCustomDate1": "1388577900000",
"deviceCustomDate1Label": "detectionDate",
"deviceEventClassId": "1",
"deviceProduct": "PTA",
"deviceVendor": "CyberArk",
"deviceVersion": "12.6",
"dhost": "dev1.domain.com",
"dst": "2.2.2.2",
"duser": "andy@dev1.domain.com",
"name": "Suspected credentials theft",
"severity": "8",
"shost": "prod1.domain.com",
"src": "1.1.1.1",
"suser": "mike2@prod1.domain.com"
}Ignore syslog header
parse_cef!(
"Sep 29 08:26:10 host CEF:1|Security|threatmanager|1.0|100|worm successfully stopped|10|src=10.0.0.1 dst=2.1.2.2 spt=1232"
)
{
"cefVersion": "1",
"deviceEventClassId": "100",
"deviceProduct": "threatmanager",
"deviceVendor": "Security",
"deviceVersion": "1.0",
"dst": "2.1.2.2",
"name": "worm successfully stopped",
"severity": "10",
"spt": "1232",
"src": "10.0.0.1"
}Translate custom fields
parse_cef!(
"CEF:0|Dev|firewall|2.2|1|Connection denied|5|c6a1=2345:0425:2CA1:0000:0000:0567:5673:23b5 c6a1Label=Device IPv6 Address",
translate_custom_fields: true
)
{
"Device IPv6 Address": "2345:0425:2CA1:0000:0000:0567:5673:23b5",
"cefVersion": "0",
"deviceEventClassId": "1",
"deviceProduct": "firewall",
"deviceVendor": "Dev",
"deviceVersion": "2.2",
"name": "Connection denied",
"severity": "5"
}Parse CEF with only header
parse_cef!("CEF:1|Security|threatmanager|1.0|100|worm successfully stopped|10|"){
"cefVersion": "1",
"deviceEventClassId": "100",
"deviceProduct": "threatmanager",
"deviceVendor": "Security",
"deviceVersion": "1.0",
"name": "worm successfully stopped",
"severity": "10"
}Parse CEF with empty value
parse_cef!("CEF:0|CyberArk|PTA|12.6|1|Suspected credentials theft||suser=mike2@prod1.domain.com shost= src=1.1.1.1"){
"cefVersion": "0",
"deviceEventClassId": "1",
"deviceProduct": "PTA",
"deviceVendor": "CyberArk",
"deviceVersion": "12.6",
"name": "Suspected credentials theft",
"severity": "",
"shost": "",
"src": "1.1.1.1",
"suser": "mike2@prod1.domain.com"
}Parse CEF with escapes
parse_cef!(s'CEF:0|security|threatmanager|1.0|100|Detected a \| in message. No action needed.|10|src=10.0.0.1 msg=Detected a threat.\n No action needed act=blocked a \= dst=1.1.1.1'){
"act": "blocked a =",
"cefVersion": "0",
"deviceEventClassId": "100",
"deviceProduct": "threatmanager",
"deviceVendor": "security",
"deviceVersion": "1.0",
"dst": "1.1.1.1",
"msg": "Detected a threat.\n No action needed",
"name": "Detected a | in message. No action needed.",
"severity": "10",
"src": "10.0.0.1"
}parse_common_log
value using the Common Log Format (CLF).Parse using Common Log Format (with default timestamp format)
parse_common_log!(s'127.0.0.1 bob frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326'){
"host": "127.0.0.1",
"identity": "bob",
"message": "GET /apache_pb.gif HTTP/1.0",
"method": "GET",
"path": "/apache_pb.gif",
"protocol": "HTTP/1.0",
"size": 2326,
"status": 200,
"timestamp": "2000-10-10T20:55:36Z",
"user": "frank"
}Parse using Common Log Format (with custom timestamp format)
parse_common_log!(
s'127.0.0.1 bob frank [2000-10-10T20:55:36Z] "GET /apache_pb.gif HTTP/1.0" 200 2326',
"%+"
)
{
"host": "127.0.0.1",
"identity": "bob",
"message": "GET /apache_pb.gif HTTP/1.0",
"method": "GET",
"path": "/apache_pb.gif",
"protocol": "HTTP/1.0",
"size": 2326,
"status": 200,
"timestamp": "2000-10-10T20:55:36Z",
"user": "frank"
}parse_csv
Parse a single CSV formatted row
parse_csv!(s'foo,bar,"foo "", bar"')["foo","bar","foo \", bar"]Parse a single CSV formatted row with custom delimiter
parse_csv!("foo bar", delimiter: " ")["foo","bar"]parse_dnstap
value as base64 encoded DNSTAP data.Parse dnstap query message
parse_dnstap!("ChVqYW1lcy1WaXJ0dWFsLU1hY2hpbmUSC0JJTkQgOS4xNi4zGgBy5wEIAxACGAEiEAAAAAAAAAAAAAAAAAAAAAAqECABBQJwlAAAAAAAAAAAADAw8+0CODVA7+zq9wVNMU3WNlI2kwIAAAABAAAAAAABCWZhY2Vib29rMQNjb20AAAEAAQAAKQIAAACAAAAMAAoACOxjCAG9zVgzWgUDY29tAGAAbQAAAAByZLM4AAAAAQAAAAAAAQJoNQdleGFtcGxlA2NvbQAABgABAAApBNABAUAAADkADwA1AAlubyBTRVAgbWF0Y2hpbmcgdGhlIERTIGZvdW5kIGZvciBkbnNzZWMtZmFpbGVkLm9yZy54AQ=="){
"dataType": "Message",
"dataTypeId": 1,
"extraInfo": "",
"messageType": "ResolverQuery",
"messageTypeId": 3,
"queryZone": "com.",
"requestData": {
"fullRcode": 0,
"header": {
"aa": false,
"ad": false,
"anCount": 0,
"arCount": 1,
"cd": false,
"id": 37634,
"nsCount": 0,
"opcode": 0,
"qdCount": 1,
"qr": 0,
"ra": false,
"rcode": 0,
"rd": false,
"tc": false
},
"opt": {
"do": true,
"ednsVersion": 0,
"extendedRcode": 0,
"options": [
{
"optCode": 10,
"optName": "Cookie",
"optValue": "7GMIAb3NWDM="
}
],
"udpPayloadSize": 512
},
"question": [
{
"class": "IN",
"domainName": "facebook1.com.",
"questionType": "A",
"questionTypeId": 1
}
],
"rcodeName": "NoError"
},
"responseAddress": "2001:502:7094::30",
"responseData": {
"fullRcode": 16,
"header": {
"aa": false,
"ad": false,
"anCount": 0,
"arCount": 1,
"cd": false,
"id": 45880,
"nsCount": 0,
"opcode": 0,
"qdCount": 1,
"qr": 0,
"ra": false,
"rcode": 16,
"rd": false,
"tc": false
},
"opt": {
"do": false,
"ede": [
{
"extraText": "no SEP matching the DS found for dnssec-failed.org.",
"infoCode": 9,
"purpose": "DNSKEY Missing"
}
],
"ednsVersion": 1,
"extendedRcode": 1,
"udpPayloadSize": 1232
},
"question": [
{
"class": "IN",
"domainName": "h5.example.com.",
"questionType": "SOA",
"questionTypeId": 6
}
],
"rcodeName": "BADVERS"
},
"responsePort": 53,
"serverId": "james-Virtual-Machine",
"serverVersion": "BIND 9.16.3",
"socketFamily": "INET6",
"socketProtocol": "UDP",
"sourceAddress": "::",
"sourcePort": 46835,
"time": 1593489007920014000,
"timePrecision": "ns",
"timestamp": "2020-06-30T03:50:07.920014129Z"
}parse_duration
value into a human-readable duration format specified by unit.Parse duration (milliseconds)
parse_duration!("1005ms", unit: "s")1.005Parse multiple durations (seconds & milliseconds)
parse_duration!("1s 1ms", unit: "ms")1001parse_etld
value representing domain name.Parse eTLD
parse_etld!("sub.sussex.ac.uk"){
"etld": "ac.uk",
"etld_plus": "ac.uk",
"known_suffix": true
}Parse eTLD+1
parse_etld!("sub.sussex.ac.uk", plus_parts: 1){
"etld": "ac.uk",
"etld_plus": "sussex.ac.uk",
"known_suffix": true
}Parse eTLD with unknown suffix
parse_etld!("vector.acmecorp"){
"etld": "acmecorp",
"etld_plus": "acmecorp",
"known_suffix": false
}Parse eTLD with custom PSL
parse_etld!("vector.acmecorp", psl: "lib/tests/tests/functions/custom_public_suffix_list.dat"){
"etld": "acmecorp",
"etld_plus": "acmecorp",
"known_suffix": false
}parse_glog
value using the glog (Google Logging Library) format.Parse using glog
parse_glog!("I20210131 14:48:54.411655 15520 main.c++:9] Hello world!"){
"file": "main.c++",
"id": 15520,
"level": "info",
"line": 9,
"message": "Hello world!",
"timestamp": "2021-01-31T14:48:54.411655Z"
}parse_grok
Parse using Grok
value = "2020-10-02T23:22:12.223222Z info Hello world"
pattern = "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}"
parse_grok!(value, pattern)
{
"level": "info",
"message": "Hello world",
"timestamp": "2020-10-02T23:22:12.223222Z"
}parse_groks
Parse using multiple Grok patterns
parse_groks!(
"2020-10-02T23:22:12.223222Z info Hello world",
patterns: [
"%{common_prefix} %{_status} %{_message}",
"%{common_prefix} %{_message}",
],
aliases: {
"common_prefix": "%{_timestamp} %{_loglevel}",
"_timestamp": "%{TIMESTAMP_ISO8601:timestamp}",
"_loglevel": "%{LOGLEVEL:level}",
"_status": "%{POSINT:status}",
"_message": "%{GREEDYDATA:message}"
}
)
{
"level": "info",
"message": "Hello world",
"timestamp": "2020-10-02T23:22:12.223222Z"
}Parse using aliases from file
parse_groks!(
"username=foo",
patterns: [ "%{PATTERN_A}" ],
alias_sources: [ "tests/data/grok/aliases.json" ]
)
# aliases.json contents:
# {
# "PATTERN_A": "%{PATTERN_B}",
# "PATTERN_B": "username=%{USERNAME:username}"
# }
{
"username": "foo"
}parse_influxdb
value as an InfluxDB line protocol string, producing a list of Vector-compatible metrics.Parse InfluxDB line protocol
parse_influxdb!("cpu,host=A,region=us-west usage_system=64i,usage_user=10u,temperature=50.5,on=true,sleep=false 1590488773254420000")[{"gauge":{"value":64},"kind":"absolute","name":"cpu_usage_system","tags":{"host":"A","region":"us-west"},"timestamp":"2020-05-26T10:26:13.254420Z"},{"gauge":{"value":10},"kind":"absolute","name":"cpu_usage_user","tags":{"host":"A","region":"us-west"},"timestamp":"2020-05-26T10:26:13.254420Z"},{"gauge":{"value":50.5},"kind":"absolute","name":"cpu_temperature","tags":{"host":"A","region":"us-west"},"timestamp":"2020-05-26T10:26:13.254420Z"},{"gauge":{"value":1},"kind":"absolute","name":"cpu_on","tags":{"host":"A","region":"us-west"},"timestamp":"2020-05-26T10:26:13.254420Z"},{"gauge":{"value":0},"kind":"absolute","name":"cpu_sleep","tags":{"host":"A","region":"us-west"},"timestamp":"2020-05-26T10:26:13.254420Z"}]parse_int
value representing a number in an optional base/radix to an integer.parse_json
Parses the provided value as JSON.
Only JSON types are returned. If you need to convert a string into a timestamp,
consider the parse_timestamp function.
Parse JSON
parse_json!(s'{"key": "val"}'){
"key": "val"
}Parse JSON array
parse_json!("[true, 0]")[true,0]Parse JSON with max_depth
parse_json!(s'{"first_level":{"second_level":"finish"}}', max_depth: 1){
"first_level": "{\"second_level\":\"finish\"}"
}parse_key_value
Parses the value in key-value format. Also known as logfmt.
- Keys and values can be wrapped with
". "characters can be escaped using\.
Parse simple key value pairs
parse_key_value!("zork=zook zonk=nork"){
"zonk": "nork",
"zork": "zook"
}Parse logfmt log
parse_key_value!(
"@timestamp=\"Sun Jan 10 16:47:39 EST 2021\" level=info msg=\"Stopping all fetchers\" tag#production=stopping_fetchers id=ConsumerFetcherManager-1382721708341 module=kafka.consumer.ConsumerFetcherManager"
)
{
"@timestamp": "Sun Jan 10 16:47:39 EST 2021",
"id": "ConsumerFetcherManager-1382721708341",
"level": "info",
"module": "kafka.consumer.ConsumerFetcherManager",
"msg": "Stopping all fetchers",
"tag#production": "stopping_fetchers"
}Parse comma delimited log
parse_key_value!(
"path:\"/cart_link\", host:store.app.com, fwd: \"102.30.171.16\", dyno: web.1, connect:0ms, service:87ms, status:304, bytes:632, protocol:https",
field_delimiter: ",",
key_value_delimiter: ":"
)
{
"bytes": "632",
"connect": "0ms",
"dyno": "web.1",
"fwd": "102.30.171.16",
"host": "store.app.com",
"path": "/cart_link",
"protocol": "https",
"service": "87ms",
"status": "304"
}Parse comma delimited log with standalone keys
parse_key_value!(
"env:prod,service:backend,region:eu-east1,beta",
field_delimiter: ",",
key_value_delimiter: ":",
)
{
"beta": true,
"env": "prod",
"region": "eu-east1",
"service": "backend"
}Parse duplicate keys
parse_key_value!(
"at=info,method=GET,path=\"/index\",status=200,tags=dev,tags=dummy",
field_delimiter: ",",
key_value_delimiter: "=",
)
{
"at": "info",
"method": "GET",
"path": "/index",
"status": "200",
"tags": [
"dev",
"dummy"
]
}Parse with strict whitespace
parse_key_value!(s'app=my-app ip=1.2.3.4 user= msg=hello-world', whitespace: "strict"){
"app": "my-app",
"ip": "1.2.3.4",
"msg": "hello-world",
"user": ""
}parse_klog
value using the klog format used by Kubernetes components.Parse using klog
parse_klog!("I0505 17:59:40.692994 28133 klog.go:70] hello from klog"){
"file": "klog.go",
"id": 28133,
"level": "info",
"line": 70,
"message": "hello from klog",
"timestamp": "2026-05-05T17:59:40.692994Z"
}parse_linux_authorization
/var/log/auth.log (for Debian-based systems) or /var/log/secure (for RedHat-based systems) according to Syslog format.Parse Linux authorization event
parse_linux_authorization!(
s'Mar 23 01:49:58 localhost sshd[1111]: Accepted publickey for eng from 10.1.1.1 port 8888 ssh2: RSA SHA256:foobar'
)
{
"appname": "sshd",
"hostname": "localhost",
"message": "Accepted publickey for eng from 10.1.1.1 port 8888 ssh2: RSA SHA256:foobar",
"procid": 1111,
"timestamp": "2026-03-23T01:49:58Z"
}parse_logfmt
Parses the value in logfmt.
- Keys and values can be wrapped using the
"character. "characters can be escaped by the\character.- As per this logfmt specification, the
parse_logfmtfunction accepts standalone keys and assigns them a Boolean value oftrue.
Parse simple logfmt log
parse_logfmt!("zork=zook zonk=nork"){
"zonk": "nork",
"zork": "zook"
}Parse logfmt log
parse_logfmt!(
"@timestamp=\"Sun Jan 10 16:47:39 EST 2021\" level=info msg=\"Stopping all fetchers\" tag#production=stopping_fetchers id=ConsumerFetcherManager-1382721708341 module=kafka.consumer.ConsumerFetcherManager"
)
{
"@timestamp": "Sun Jan 10 16:47:39 EST 2021",
"id": "ConsumerFetcherManager-1382721708341",
"level": "info",
"module": "kafka.consumer.ConsumerFetcherManager",
"msg": "Stopping all fetchers",
"tag#production": "stopping_fetchers"
}Parse logfmt log with standalone key
parse_logfmt!("zork=zook plonk zonk=nork"){
"plonk": true,
"zonk": "nork",
"zork": "zook"
}parse_nginx_log
combined, ingress_upstreaminfo, main or error format.Parse via Nginx log format (combined)
parse_nginx_log!(
s'172.17.0.1 - alice [01/Apr/2021:12:02:31 +0000] "POST /not-found HTTP/1.1" 404 153 "http://localhost/somewhere" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36" "2.75"',
"combined",
)
{
"agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36",
"client": "172.17.0.1",
"compression": "2.75",
"referer": "http://localhost/somewhere",
"request": "POST /not-found HTTP/1.1",
"size": 153,
"status": 404,
"timestamp": "2021-04-01T12:02:31Z",
"user": "alice"
}Parse via Nginx log format (error)
parse_nginx_log!(
s'2021/04/01 13:02:31 [error] 31#31: *1 open() "/usr/share/nginx/html/not-found" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "POST /not-found HTTP/1.1", host: "localhost:8081"',
"error"
)
{
"cid": 1,
"client": "172.17.0.1",
"host": "localhost:8081",
"message": "open() \"/usr/share/nginx/html/not-found\" failed (2: No such file or directory)",
"pid": 31,
"request": "POST /not-found HTTP/1.1",
"server": "localhost",
"severity": "error",
"tid": 31,
"timestamp": "2021-04-01T13:02:31Z"
}Parse via Nginx log format (ingress_upstreaminfo)
parse_nginx_log!(
s'0.0.0.0 - bob [18/Mar/2023:15:00:00 +0000] "GET /some/path HTTP/2.0" 200 12312 "https://10.0.0.1/some/referer" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36" 462 0.050 [some-upstream-service-9000] [some-other-upstream-5000] 10.0.50.80:9000 19437 0.049 200 752178adb17130b291aefd8c386279e7',
"ingress_upstreaminfo"
)
{
"body_bytes_size": 12312,
"http_referer": "https://10.0.0.1/some/referer",
"http_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
"proxy_alternative_upstream_name": "some-other-upstream-5000",
"proxy_upstream_name": "some-upstream-service-9000",
"remote_addr": "0.0.0.0",
"remote_user": "bob",
"req_id": "752178adb17130b291aefd8c386279e7",
"request": "GET /some/path HTTP/2.0",
"request_length": 462,
"request_time": 0.05,
"status": 200,
"timestamp": "2023-03-18T15:00:00Z",
"upstream_addr": "10.0.50.80:9000",
"upstream_response_length": 19437,
"upstream_response_time": 0.049,
"upstream_status": 200
}Parse via Nginx log format (main)
parse_nginx_log!(
s'172.24.0.3 - alice [31/Dec/2024:17:32:06 +0000] "GET / HTTP/1.1" 200 615 "https://domain.tld/path" "curl/8.11.1" "1.2.3.4, 10.10.1.1"',
"main"
)
{
"body_bytes_size": 615,
"http_referer": "https://domain.tld/path",
"http_user_agent": "curl/8.11.1",
"http_x_forwarded_for": "1.2.3.4, 10.10.1.1",
"remote_addr": "172.24.0.3",
"remote_user": "alice",
"request": "GET / HTTP/1.1",
"status": 200,
"timestamp": "2024-12-31T17:32:06Z"
}parse_proto
value as a protocol buffer payload.Parse proto
parse_proto!(decode_base64!("Cgdzb21lb25lIggKBjEyMzQ1Ng=="), "test_protobuf.desc", "test_protobuf.v1.Person"){
"name": "someone",
"phones": [
{
"number": "123456"
}
]
}parse_query_string
value as a query string.Parse simple query string
parse_query_string("foo=1&bar=2"){
"bar": "2",
"foo": "1"
}Parse query string
parse_query_string("foo=%2B1&bar=2&bar=3&xyz"){
"bar": [
"2",
"3"
],
"foo": "+1",
"xyz": ""
}Parse Ruby on Rails’ query string
parse_query_string("?foo%5b%5d=1&foo%5b%5d=2"){
"foo[]": [
"1",
"2"
]
}parse_regex
Parses the value using the provided Regex pattern.
This function differs from the parse_regex_all function in that it returns only the first match.
Parse using Regex (with capture groups)
parse_regex!("first group and second group.", r'(?P<number>.*?) group'){
"number": "first"
}Parse using Regex (without capture groups)
parse_regex!("first group and second group.", r'(\w+) group', numeric_groups: true){
"0": "first group",
"1": "first"
}Parse using Regex with simple match
parse_regex!("8.7.6.5 - zorp", r'^(?P<host>[\w\.]+) - (?P<user>[\w]+)'){
"host": "8.7.6.5",
"user": "zorp"
}Parse using Regex with all numeric groups
parse_regex!("8.7.6.5 - zorp", r'^(?P<host>[\w\.]+) - (?P<user>[\w]+)', numeric_groups: true){
"0": "8.7.6.5 - zorp",
"1": "8.7.6.5",
"2": "zorp",
"host": "8.7.6.5",
"user": "zorp"
}Parse using Regex with variables
variable = r'^(?P<host>[\w\.]+) - (?P<user>[\w]+)';
parse_regex!("8.7.6.5 - zorp", variable)
{
"host": "8.7.6.5",
"user": "zorp"
}parse_regex_all
Parses the value using the provided Regex pattern.
This function differs from the parse_regex function in that it returns all matches, not just the first.
Parse using Regex (all matches)
parse_regex_all!("first group and second group.", r'(?P<number>\w+) group', numeric_groups: true)[{"0":"first group","1":"first","number":"first"},{"0":"second group","1":"second","number":"second"}]Parse using Regex (simple match)
parse_regex_all!("apples and carrots, peaches and peas", r'(?P<fruit>[\w\.]+) and (?P<veg>[\w]+)')[{"fruit":"apples","veg":"carrots"},{"fruit":"peaches","veg":"peas"}]Parse using Regex (all numeric groups)
parse_regex_all!("apples and carrots, peaches and peas", r'(?P<fruit>[\w\.]+) and (?P<veg>[\w]+)', numeric_groups: true)[{"0":"apples and carrots","1":"apples","2":"carrots","fruit":"apples","veg":"carrots"},{"0":"peaches and peas","1":"peaches","2":"peas","fruit":"peaches","veg":"peas"}]Parse using Regex with variables
variable = r'(?P<fruit>[\w\.]+) and (?P<veg>[\w]+)';
parse_regex_all!("apples and carrots, peaches and peas", variable)
[{"fruit":"apples","veg":"carrots"},{"fruit":"peaches","veg":"peas"}]parse_ruby_hash
value as ruby hash.Parse ruby hash
parse_ruby_hash!(s'{ "test" => "value", "testNum" => 0.2, "testObj" => { "testBool" => true, "testNull" => nil } }'){
"test": "value",
"testNum": 0.2,
"testObj": {
"testBool": true,
"testNull": null
}
}parse_syslog
value in Syslog format.Parse Syslog log (5424)
parse_syslog!(s'<13>1 2020-03-13T20:45:38.119Z dynamicwireless.name non 2426 ID931 [exampleSDID@32473 iut="3" eventSource= "Application" eventID="1011"] Try to override the THX port, maybe it will reboot the neural interface!'){
"appname": "non",
"exampleSDID@32473": {
"eventID": "1011",
"eventSource": "Application",
"iut": "3"
},
"facility": "user",
"hostname": "dynamicwireless.name",
"message": "Try to override the THX port, maybe it will reboot the neural interface!",
"msgid": "ID931",
"procid": 2426,
"severity": "notice",
"timestamp": "2020-03-13T20:45:38.119Z",
"version": 1
}parse_timestamp
Parse timestamp
parse_timestamp!("10-Oct-2020 16:00+00:00", format: "%v %R %:z")t'2020-10-10T16:00:00Z'Parse timestamp with timezone
parse_timestamp!("16/10/2019 12:00:00", format: "%d/%m/%Y %H:%M:%S", timezone: "Asia/Taipei")t'2019-10-16T04:00:00Z'parse_tokens
Parses the value in token format. A token is considered to be one of the following:
- A word surrounded by whitespace.
- Text delimited by double quotes:
"..". Quotes can be included in the token if they are escaped by a backslash (\). - Text delimited by square brackets:
[..]. Closing square brackets can be included in the token if they are escaped by a backslash (\).
Parse tokens
parse_tokens(s'A sentence "with \"a\" sentence inside" and [some brackets]')["A","sentence","with \\\"a\\\" sentence inside","and","some brackets"]parse_url
value in URL format.Parse URL
parse_url!("ftp://foo:bar@example.com:4343/foobar?hello=world#123"){
"fragment": "123",
"host": "example.com",
"password": "bar",
"path": "/foobar",
"port": 4343,
"query": {
"hello": "world"
},
"scheme": "ftp",
"username": "foo"
}Parse URL with default port
parse_url!("https://example.com", default_known_ports: true){
"fragment": null,
"host": "example.com",
"password": "",
"path": "/",
"port": 443,
"query": {},
"scheme": "https",
"username": ""
}parse_user_agent
Parses the provided value as a user agent, which has
a loosely defined format.
Parses on the basis of best effort. Returned schema depends only on the configured mode,
so if the function fails to parse a field it will set it to null.
Fast mode
parse_user_agent(
"Mozilla Firefox 1.0.1 Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1"
)
{
"browser": {
"family": "Firefox",
"version": "1.0.1"
},
"device": {
"category": "pc"
},
"os": {
"family": "Linux",
"version": null
}
}Reliable mode
parse_user_agent(
"Mozilla/4.0 (compatible; MSIE 7.66; Windows NT 5.1; SV1; .NET CLR 1.1.4322)",
mode: "reliable")
{
"browser": {
"family": "Internet Explorer",
"version": "7.66"
},
"device": {
"category": "pc"
},
"os": {
"family": "Windows XP",
"version": "NT 5.1"
}
}Enriched mode
parse_user_agent(
"Opera/9.80 (J2ME/MIDP; Opera Mini/4.3.24214; iPhone; CPU iPhone OS 4_2_1 like Mac OS X; AppleWebKit/24.783; U; en) Presto/2.5.25 Version/10.54",
mode: "enriched"
)
{
"browser": {
"family": "Opera Mini",
"major": "4",
"minor": "3",
"patch": "24214",
"version": "10.54"
},
"device": {
"brand": "Apple",
"category": "smartphone",
"family": "iPhone",
"model": "iPhone"
},
"os": {
"family": "iOS",
"major": "4",
"minor": "2",
"patch": "1",
"patch_minor": null,
"version": "4.2.1"
}
}parse_xml
value as XML.Parse XML
value = s'<book category="CHILDREN"><title lang="en">Harry Potter</title><author>J K. Rowling</author><year>2005</year></book>';
parse_xml!(value, text_key: "value", parse_number: false)
{
"book": {
"@category": "CHILDREN",
"author": "J K. Rowling",
"title": {
"@lang": "en",
"value": "Harry Potter"
},
"year": "2005"
}
}Random examples
random_bool
random_bytes
Generate random base 64 encoded bytes
encode_base64(random_bytes(16))LNu0BBgUbh7XAlXbjSOomQ==Generate 16 random bytes
length(random_bytes(16))16random_float
Random float from 0.0 to 10.0, not including 10.0
f = random_float(0.0, 10.0)
f >= 0 && f < 10
truerandom_int
Random integer from 0 to 10, not including 10
i = random_int(0, 10)
i >= 0 && i < 10
trueuuid_from_friendly_id
Convert a Friendly ID to a UUID
uuid_from_friendly_id!("3s87yEvnmkiPBMHsj8bwwc")7f41deed-d5e2-8b5e-7a13-ab4ff93cfad2uuid_v4
Create a UUIDv4
uuid_v4()1d262f4f-199b-458d-879f-05fd0a5f0683uuid_v7
Create a UUIDv7 with implicit now()
uuid_v7()0135ddb4-a444-794c-a7a2-088f260104c0Create a UUIDv7 with explicit now()
uuid_v7(now())0135ddb4-a444-794c-a7a2-088f260104c0Create a UUIDv7 with custom timestamp
uuid_v7(t'2020-12-30T22:20:53.824727Z')0176b5bd-5d19-794c-a7a2-088f260104c0String examples
basename
path. This is similar to the Unix basename command. If the path ends in a directory separator, the function returns the name of the directory.Extract basename from file path
basename!("/usr/local/bin/vrl")vrlExtract basename from file path with extension
basename!("/home/user/file.txt")file.txtExtract basename from directory path
basename!("/home/user/")usercamelcase
value string, and turns it into camelCase. Optionally, you can pass in the existing case of the function, or else an attempt is made to determine the case automatically.camelCase a string without specifying original case
camelcase("input-string")inputStringcamelcase a snake_case string
camelcase("foo_bar_baz", "snake_case")fooBarBazcamelcase specifying the wrong original case (noop)
camelcase("foo_bar_baz", "kebab-case")foo_bar_bazcommunity_id
Generate Community ID for TCP
community_id!(source_ip: "1.2.3.4", destination_ip: "5.6.7.8", source_port: 1122, destination_port: 3344, protocol: 6)1:wCb3OG7yAFWelaUydu0D+125CLM=Generate Community ID for UDP
community_id!(source_ip: "1.2.3.4", destination_ip: "5.6.7.8", source_port: 1122, destination_port: 3344, protocol: 17)1:0Mu9InQx6z4ZiCZM/7HXi2WMhOg=Generate Community ID for ICMP
community_id!(source_ip: "1.2.3.4", destination_ip: "5.6.7.8", source_port: 8, destination_port: 0, protocol: 1)1:crodRHL2FEsHjbv3UkRrfbs4bZ0=Generate Community ID for RSVP
community_id!(source_ip: "1.2.3.4", destination_ip: "5.6.7.8", protocol: 46)1:ikv3kmf89luf73WPz1jOs49S768=contains
value string contains the specified substring.contains_all
value string contains all the specified substrings.String contains all with default parameters (case sensitive)
contains_all("The NEEDLE in the Haystack", ["NEEDLE", "Haystack"])trueString doesn’t contain all with default parameters (case sensitive)
contains_all("The NEEDLE in the Haystack", ["needle", "Haystack"])String contains all (case insensitive)
contains_all("The NEEDLE in the HaYsTaCk", ["nEeDlE", "haystack"], case_sensitive: false)truedirname
path. This is similar to the Unix dirname command. The directory component is the path with the final component removed.Extract dirname from file path
dirname!("/usr/local/bin/vrl")/usr/local/binExtract dirname from file path with extension
dirname!("/home/user/file.txt")/home/userExtract dirname from directory path
dirname!("/home/user/")/homeRelative files have current directory as dirname
dirname!("file.txt").downcase
value string, where downcase is defined according to the Unicode Derived Core Property Lowercase.ends_with
value string ends with the specified substring.String ends with (case sensitive)
ends_with("The Needle In The Haystack", "The Haystack")trueString ends with (case insensitive)
ends_with("The Needle In The Haystack", "the haystack", case_sensitive: false)trueString ends with (case sensitive failure)
ends_with("foobar", "R")find
value that matches pattern. Returns -1 if not found.join
value array into a single string, with items optionally separated from one another by a separator.kebabcase
value string, and turns it into kebab-case. Optionally, you can pass in the existing case of the function, or else we will try to figure out the case automatically.kebab-case a string without specifying original case
kebabcase("InputString")input-stringkebab-case a snake_case string
kebabcase("foo_bar_baz", "snake_case")foo-bar-bazkebab-case specifying the wrong original case (noop)
kebabcase("foo_bar_baz", "PascalCase")foo_bar_bazmatch
value matches the pattern.match_any
value matches any of the given patterns. All patterns are checked in a single pass over the target string, giving this function a potential performance advantage over the multiple calls in the match function.parse_float
value representing a floating point number in base 10 to a float.pascalcase
value string, and turns it into PascalCase. Optionally, you can pass in the existing case of the function, or else we will try to figure out the case automatically.PascalCase a string without specifying original case
pascalcase("input-string")InputStringPascalCase a snake_case string
pascalcase("foo_bar_baz", "snake_case")FooBarBazPascalCase specifying the wrong original case (only capitalizes)
pascalcase("foo_bar_baz", "kebab-case")Foo_bar_bazredact
Redact sensitive data in value such as:
- US social security card numbers
- Other forms of personally identifiable information with custom patterns
This can help achieve compliance by ensuring sensitive data does not leave your network.
Replace text using a regex
redact("my id is 123456", filters: [r'\d+'])my id is [REDACTED]Replace us social security numbers in any field
redact({ "name": "John Doe", "ssn": "123-12-1234"}, filters: ["us_social_security_number"]){
"name": "John Doe",
"ssn": "[REDACTED]"
}Replace with custom text
redact("my id is 123456", filters: [r'\d+'], redactor: {"type": "text", "replacement": "***"})my id is ***Replace with SHA-2 hash
redact("my id is 123456", filters: [r'\d+'], redactor: "sha2")my id is GEtTedW1p6tC094dDKH+3B8P+xSnZz69AmpjaXRd63I=Replace with SHA-3 hash
redact("my id is 123456", filters: [r'\d+'], redactor: "sha3")my id is ZNCdmTDI7PeeUTFnpYjLdUObdizo+bIupZdl8yqnTKGdLx6X3JIqPUlUWUoFBikX+yTR+OcvLtAqWO11NPlNJw==Replace with SHA-256 hash using hex encoding
redact("my id is 123456", filters: [r'\d+'], redactor: {"type": "sha2", "variant": "SHA-256", "encoding": "base16"})my id is 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92replace
Replaces all matching instances of pattern in value.
The pattern argument accepts regular expression capture groups.
Note when using capture groups:
- You will need to escape the
$by using$$to avoid Vector interpreting it as an environment variable when loading configuration - If you want a literal
$in the replacement pattern, you will also need to escape this with$$. When combined with environment variable interpolation in config files this means you will need to use$$$$to have a literal$in the replacement pattern.
Replace literal text
replace("Apples and Bananas", "and", "not")Apples not BananasReplace using regular expression
replace("Apples and Bananas", r'(?i)bananas', "Pineapples")Apples and PineapplesReplace first instance
replace("Bananas and Bananas", "Bananas", "Pineapples", count: 1)Pineapples and BananasReplace with capture groups
# Note that in the context of Vector configuration files, an extra `$` escape character is required
# (i.e. `$$num`) to avoid interpreting `num` as an environment variable.
replace("foo123bar", r'foo(?P<num>\d+)bar', "$num")
123replace_with
Replaces all matching instances of pattern using a closure.
The pattern argument accepts a regular expression that can use capture groups.
The function uses the function closure syntax to compute the replacement values.
The closure takes a single parameter, which is an array, where the first item is always
present and contains the entire string that matched pattern. The items from index one on
contain the capture groups of the corresponding index. If a capture group is optional, the
value may be null if it didn’t match.
The value returned by the closure must be a string and will replace the section of the input that was matched.
This returns a new string with the replacements, the original string is not mutated.
Capitalize words
replace_with("apples and bananas", r'\b(\w)(\w*)') -> |match| {
upcase!(match.captures[0]) + string!(match.captures[1])
}
Apples And BananasReplace with hash
replace_with("email from test@example.com", r'\w+@example.com') -> |match| {
sha2(match.string, variant: "SHA-512/224")
}
email from adf6e1bc4415d24912bd93072ad34ef825a7b6eb3bf53f68def1fc17Replace first instance
replace_with("Apples and Apples", r'(?i)apples|cones', count: 1) -> |match| {
"Pine" + downcase(match.string)
}
Pineapples and ApplesNamed capture group
replace_with("level=error A message", r'level=(?P<level>\w+)') -> |match| {
lvl = upcase!(match.level)
"[{{lvl}}]"
}
[ERROR] A messageReplace with processed capture group
replace_with(s'Got message: {"msg": "b"}', r'message: (\{.*\})') -> |m| {
to_string!(parse_json!(m.captures[0]).msg)
}
Got bReplace with optional capture group
replace_with("bar of chocolate and bar of gold", r'bar( of gold)?') -> |m| {
if m.captures[0] == null { "pile" } else { "money" }
}
pile of chocolate and moneyscreamingsnakecase
value string, and turns it into SCREAMING_SNAKE case. Optionally, you can pass in the existing case of the function, or else we will try to figure out the case automatically.SCREAMING_SNAKE_CASE a string without specifying original case
screamingsnakecase("input-string")INPUT_STRINGSCREAMING_SNAKE_CASE a snake_case string
screamingsnakecase("foo_bar_baz", "snake_case")FOO_BAR_BAZSCREAMING_SNAKE_CASE specifying the wrong original case (capitalizes but doesn’t include _ properly)
screamingsnakecase("FooBarBaz", "kebab-case")FOOBARBAZshannon_entropy
Simple byte segmentation example
floor(shannon_entropy("vector.dev"), precision: 4)2.9219UTF-8 string with bytes segmentation
floor(shannon_entropy("test123%456.فوائد.net."), precision: 4)4.0784UTF-8 string with grapheme segmentation
floor(shannon_entropy("test123%456.فوائد.net.", segmentation: "grapheme"), precision: 4)3.9362UTF-8 emoji (7 Unicode scalar values) with grapheme segmentation
shannon_entropy("👨👩👧👦", segmentation: "grapheme")sieve
Keeps only matches of pattern in value.
This can be used to define patterns that are allowed in the string and remove everything else.
Keep only lowercase letters
sieve("vector.dev/lowerUPPER", permitted_characters: r'[a-z]')vectordevlowerSieve with regex
sieve("test123%456.فوائد.net.", r'[a-z0-9.]')test123456..net.Custom replacements
sieve("test123%456.فوائد.net.", r'[a-z.0-9]', replace_single: "X", replace_repeated: "<REMOVED>")test123X456.<REMOVED>.net.slice
Returns a slice of value between the start and end positions.
If the start and end parameters are negative, they refer to positions counting from the right of the
string or array. If end refers to a position that is greater than the length of the string or array,
a slice up to the end of the string or array is returned.
Slice a string (positive index)
slice!("Supercalifragilisticexpialidocious", start: 5, end: 13)califragSlice a string (negative index)
slice!("Supercalifragilisticexpialidocious", start: 5, end: -14)califragilisticsnakecase
value string, and turns it into snake_case. Optionally, you can pass in the existing case of the function, or else we will try to figure out the case automatically.snake_case a string
snakecase("input-string")input_stringsnake_case a string with original case
snakecase("input-string", original_case: "kebab-case")input_stringsnake_case with excluded boundaries
snakecase("s3BucketDetails", excluded_boundaries: ["lower_digit"])s3_bucket_detailssplit
value string using pattern.Split a string (no limit)
split("apples and pears and bananas", " and ")["apples","pears","bananas"]Split a string (with a limit)
split("apples and pears and bananas", " and ", limit: 2)["apples","pears and bananas"]split_path
path into its constituent components, returning an array of strings. Each component represents a part of the file system path hierarchy.Split path with trailing slash
split_path("/home/user/")["/","home","user"]Split path from file path
split_path("/home/user")["/","home","user"]starts_with
value begins with substring.String starts with (case sensitive)
starts_with("The Needle In The Haystack", "The Needle")trueString starts with (case insensitive)
starts_with("The Needle In The Haystack", "the needle", case_sensitive: false)trueString starts with (case sensitive failure)
starts_with("foobar", "F")strip_ansi_escape_codes
value.strip_whitespace
value, where whitespace is defined by the Unicode White_Space property.Strip whitespace
strip_whitespace(" A sentence. ")A sentence.Start whitespace
strip_whitespace(" foobar")foobarEnd whitespace
strip_whitespace("foo bar ")foo barNewlines
strip_whitespace("\n\nfoo bar\n ")foo bartruncate
value string up to the limit number of characters.Truncate a string
truncate("A rather long sentence.", limit: 11, suffix: "...")A rather lo...Truncate a string (custom suffix)
truncate("A rather long sentence.", limit: 11, suffix: "[TRUNCATED]")A rather lo[TRUNCATED]upcase
value, where upcase is defined according to the Unicode Derived Core Property Uppercase.Upcase a string
upcase("Hello, World!")HELLO, WORLD!System examples
dns_lookup
Basic lookup
res = dns_lookup!("dns.google")
# reset non-static ttl so result is static
res.answers = map_values(res.answers) -> |value| {
value.ttl = 600
value
}
# remove extra responses for example
res.answers = filter(res.answers) -> |_, value| {
value.rData == "8.8.8.8"
}
# remove class since this is also dynamic
res.additional = map_values(res.additional) -> |value| {
del(value.class)
value
}
res
{
"additional": [
{
"domainName": "",
"rData": "OPT ...",
"recordType": "OPT",
"recordTypeId": 41,
"ttl": 0
}
],
"answers": [
{
"class": "IN",
"domainName": "dns.google",
"rData": "8.8.8.8",
"recordType": "A",
"recordTypeId": 1,
"ttl": 600
}
],
"authority": [],
"fullRcode": 0,
"header": {
"aa": false,
"ad": false,
"anCount": 2,
"arCount": 1,
"cd": false,
"nsCount": 0,
"opcode": 0,
"qdCount": 1,
"qr": true,
"ra": true,
"rcode": 0,
"rd": true,
"tc": false
},
"question": [
{
"class": "IN",
"domainName": "dns.google",
"questionType": "A",
"questionTypeId": 1
}
],
"rcodeName": "NOERROR"
}Custom class and qtype
res = dns_lookup!("dns.google", class: "IN", qtype: "A")
# reset non-static ttl so result is static
res.answers = map_values(res.answers) -> |value| {
value.ttl = 600
value
}
# remove extra responses for example
res.answers = filter(res.answers) -> |_, value| {
value.rData == "8.8.8.8"
}
# remove class since this is also dynamic
res.additional = map_values(res.additional) -> |value| {
del(value.class)
value
}
res
{
"additional": [
{
"domainName": "",
"rData": "OPT ...",
"recordType": "OPT",
"recordTypeId": 41,
"ttl": 0
}
],
"answers": [
{
"class": "IN",
"domainName": "dns.google",
"rData": "8.8.8.8",
"recordType": "A",
"recordTypeId": 1,
"ttl": 600
}
],
"authority": [],
"fullRcode": 0,
"header": {
"aa": false,
"ad": false,
"anCount": 2,
"arCount": 1,
"cd": false,
"nsCount": 0,
"opcode": 0,
"qdCount": 1,
"qr": true,
"ra": true,
"rcode": 0,
"rd": true,
"tc": false
},
"question": [
{
"class": "IN",
"domainName": "dns.google",
"questionType": "A",
"questionTypeId": 1
}
],
"rcodeName": "NOERROR"
}Custom options
res = dns_lookup!("dns.google", options: {"timeout": 30, "attempts": 5})
res.answers = map_values(res.answers) -> |value| {
value.ttl = 600
value
}
# remove extra responses for example
res.answers = filter(res.answers) -> |_, value| {
value.rData == "8.8.8.8"
}
# remove class since this is also dynamic
res.additional = map_values(res.additional) -> |value| {
del(value.class)
value
}
res
{
"additional": [
{
"domainName": "",
"rData": "OPT ...",
"recordType": "OPT",
"recordTypeId": 41,
"ttl": 0
}
],
"answers": [
{
"class": "IN",
"domainName": "dns.google",
"rData": "8.8.8.8",
"recordType": "A",
"recordTypeId": 1,
"ttl": 600
}
],
"authority": [],
"fullRcode": 0,
"header": {
"aa": false,
"ad": false,
"anCount": 2,
"arCount": 1,
"cd": false,
"nsCount": 0,
"opcode": 0,
"qdCount": 1,
"qr": true,
"ra": true,
"rcode": 0,
"rd": true,
"tc": false
},
"question": [
{
"class": "IN",
"domainName": "dns.google",
"questionType": "A",
"questionTypeId": 1
}
],
"rcodeName": "NOERROR"
}Custom server
res = dns_lookup!("dns.google", options: {"servers": ["dns.quad9.net"]})
res.answers = map_values(res.answers) -> |value| {
value.ttl = 600
value
}
# remove extra responses for example
res.answers = filter(res.answers) -> |_, value| {
value.rData == "8.8.8.8"
}
# remove class since this is also dynamic
res.additional = map_values(res.additional) -> |value| {
del(value.class)
value
}
res
{
"additional": [
{
"domainName": "",
"rData": "OPT ...",
"recordType": "OPT",
"recordTypeId": 41,
"ttl": 0
}
],
"answers": [
{
"class": "IN",
"domainName": "dns.google",
"rData": "8.8.8.8",
"recordType": "A",
"recordTypeId": 1,
"ttl": 600
}
],
"authority": [],
"fullRcode": 0,
"header": {
"aa": false,
"ad": false,
"anCount": 2,
"arCount": 1,
"cd": false,
"nsCount": 0,
"opcode": 0,
"qdCount": 1,
"qr": true,
"ra": true,
"rcode": 0,
"rd": true,
"tc": false
},
"question": [
{
"class": "IN",
"domainName": "dns.google",
"questionType": "A",
"questionTypeId": 1
}
],
"rcodeName": "NOERROR"
}get_env_var
name.Get an environment variable
get_env_var!("HOME")/rootget_hostname
get_timezone_name
local, then it attempts to
determine the name of the timezone from the host OS. If this
is not possible, then it returns the fixed offset of the
local timezone for the current time in the format "[+-]HH:MM",
for example, "+02:00".Get the IANA name of Vector’s timezone
get_timezone_name!()UTChttp_request
Basic HTTP request
http_request("https://httpbin.org/get"){
"args": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org"
},
"url": "https://httpbin.org/get"
}HTTP request with bearer token
http_request("https://httpbin.org/bearer", headers: {"Authorization": "Bearer my_token"}){
"authenticated": true,
"token": "my_token"
}HTTP PUT request
http_request("https://httpbin.org/put", method: "put"){
"args": {},
"data": "",
"url": "https://httpbin.org/put"
}HTTP POST request with body
http_request("https://httpbin.org/post", method: "post", body: "{\"data\":{\"hello\":\"world\"}}"){
"data": "{\"data\":{\"hello\":\"world\"}}"
}reverse_dns
Timestamp examples
format_timestamp
value into a string representation of the timestamp.Format a timestamp (ISO8601/RFC 3339)
format_timestamp!(t'2020-10-21T16:00:00Z', format: "%+")2020-10-21T16:00:00+00:00Format a timestamp (custom)
format_timestamp!(t'2020-10-21T16:00:00Z', format: "%v %R")21-Oct-2020 16:00Format a timestamp with custom format string
format_timestamp!(t'2021-02-10T23:32:00+00:00', format: "%d %B %Y %H:%M")10 February 2021 23:32Format a timestamp with timezone conversion
format_timestamp!(t'2021-02-10T23:32:00+00:00', format: "%d %B %Y %H:%M", timezone: "Europe/Berlin")11 February 2021 00:32now
Generate a current timestamp
now()2012-03-04T12:34:56.789012345ZType examples
array
value if it is an array, otherwise returns an error. This enables the type checker to guarantee that the returned value is an array and can be used in any function that expects an array.bool
value if it is a Boolean, otherwise returns an error. This enables the type
checker to guarantee that the returned value is a Boolean and can be used in any
function that expects a Boolean.float
value if it is a float, otherwise returns an error. This enables the type checker to guarantee that the returned value is a float and can be used in any function that expects a float.int
value if it is an integer, otherwise returns an error. This enables the type checker to guarantee that the returned value is an integer and can be used in any function that expects an integer.is_array
value’s type is an array.is_boolean
value’s type is a boolean.is_empty
0.is_float
value’s type is a float.is_integer
value’s type is an integer.is_json
is_null
is_nullish
value is nullish. Returns true if the specified value is null, an empty string, a string containing only whitespace, or the string "-". Returns false otherwise.Null detection (blank string)
is_nullish("")trueNull detection (dash string)
is_nullish("-")trueis_object
value’s type is an object.is_regex
value’s type is a regex.is_string
value’s type is a string.is_timestamp
value’s type is a timestamp.Valid timestamp
is_timestamp(t'2021-03-26T16:00:00Z')trueobject
value if it is an object, otherwise returns an error. This enables the type checker to guarantee that the returned value is an object and can be used in any function that expects an object.string
value if it is a string, otherwise returns an error. This enables the type checker to guarantee that the returned value is a string and can be used in any function that expects a string.tag_types_externally
Adds type information to all (nested) scalar values in the provided value.
The type information is added externally, meaning that value has the form of "type": value after this
transformation.
Tag types externally (scalar)
tag_types_externally(123){
"integer": 123
}Tag types externally (object)
tag_types_externally({
"message": "Hello world",
"request": {
"duration_ms": 67.9
}
})
{
"message": {
"string": "Hello world"
},
"request": {
"duration_ms": {
"float": 67.9
}
}
}Tag types externally (array)
tag_types_externally(["foo", "bar"])[{"string":"foo"},{"string":"bar"}]Tag types externally (null)
tag_types_externally(null)timestamp
value if it is a timestamp, otherwise returns an error. This enables the type checker to guarantee that the returned value is a timestamp and can be used in any function that expects a timestamp.type_def
Returns the type definition of an expression at runtime.
This is a debug function that is UNSTABLE. Behavior is NOT guaranteed even though it is technically usable.
return type definition
type_def(42){
"integer": true
}validate_json_schema
value conforms to a JSON Schema definition. This function validates a JSON payload against a JSON Schema definition. It can be used to ensure that the data structure and types in value match the expectations defined in schema_definition.Payload contains a valid email
validate_json_schema!(s'{ "productUser": "valid@email.com" }', "schema_with_email_format.json", false)truePayload contains an invalid email
validate_json_schema!(s'{ "productUser": "invalidEmail" }', "schema_with_email_format.json", false)Payload contains a custom format declaration
validate_json_schema!(s'{ "productUser": "a-custom-formatted-string" }', "schema_with_custom_format.json", false)Payload contains a custom format declaration, with ignore_unknown_formats set to true
validate_json_schema!(s'{ "productUser": "a-custom-formatted-string" }', "schema_with_custom_format.json", true)trueChecksum examples
crc
Calculates a CRC of the value.The CRC algorithm used can be optionally specified.
This function is infallible if either the default algorithm value or a recognized-valid compile-time algorithm string literal is used. Otherwise, it is fallible.
xxhash
value.Calculate a hash using the default (XXH32) algorithm
xxhash("foo")3792637401Calculate a hash using the XXH32 algorithm
xxhash("foo", "XXH32")3792637401Calculate a hash using the XXH64 algorithm
xxhash("foo", "XXH64")3728699739546630700Calculate a hash using the XXH3-64 algorithm
xxhash("foo", "XXH3-64")-6093828362558604000Calculate a hash using the XXH3-128 algorithm
xxhash("foo", "XXH3-128")161745101148472925293886522910304009610