Fleak Eval Expression Language (FEEL) Reference
Introduction
Fleak Eval Expression Language is a flexible expression language designed for data transformation and evaluation. It provides various operations for manipulating dictionaries, arrays, strings, and timestamps, with a focus on data processing efficiency.
Basic Syntax and Types
Data Types
Numbers
- Integers:
0
or any sequence of digits not starting with 0 (e.g.,42
,123
) - Floating-point numbers: Numbers with decimal points (e.g.,
-1.5
,.5
,10.0
) - Negative numbers are supported for both integer and floating-point values
Strings
- Can be enclosed in either single quotes (
'hello'
) or double quotes ("world"
) - Support escape sequences:
\'
- Single quote in single-quoted strings\"
- Double quote in double-quoted strings\\
- Backslash
- Examples:
"This is a 'string'"
'This is a "string"'
"String with \"quotes\""
'String with \'quotes\''
"Path with \\backslashes\\"
Booleans
- Two possible values:
true
orfalse
- Used in conditional expressions and comparisons
Null
- Represented by the keyword:
null
- Used to represent missing or undefined values
Path Selection
The language provides flexible path selection syntax for accessing nested data structures:
$
: References the root event/document.fieldName
: Accesses a field in a dictionary using dot notation (field name must be a valid identifier)[index]
: Accesses an array element by numeric index (zero-based)["fieldName"]
: Alternative syntax for accessing dictionary fields, required when:- Field names contain special characters or spaces
- Field names are reserved words
- Field names need to be computed dynamically
Examples:
// Basic field access
$.user.name // Access 'name' field in user object
$["user"]["name"] // Same access using bracket notation
// Array access
$.items[0] // Access first element of items array
$.users[1].address // Combine array and field access
// Special character handling
$["special.field"] // Access field containing a dot
$["user name"] // Access field containing a space
// Nested combinations
$.users[0]["address.line1"] // Mix of array access and special fields
Operators and Precedence
Operators
Listed in order of precedence (highest to lowest):
-
Unary Operations (highest)
- Unary minus (
-
) - Logical NOT (
not
)
- Unary minus (
-
Multiplicative Operations
- Multiplication (
*
) - Division (
/
) - Modulo (
%
)
- Multiplication (
-
Additive Operations
- Addition (
+
) - Subtraction (
-
)
- Addition (
-
Relational Operations
- Less than (
<
) - Greater than (
>
) - Less than or equal (
<=
) - Greater than or equal (
>=
)
- Less than (
-
Equality Operations
- Equal (
==
) - Not equal (
!=
)
- Equal (
-
Logical AND (
and
) -
Logical OR (
or
) (lowest)
Examples:
// Unary has highest precedence
-3 * 4 // Evaluates as (-3) * 4 = -12
not true and false // Evaluates as (not true) and false = false
// Multiplication before addition
2 + 3 * 4 // Evaluates as 2 + (3 * 4) = 14
// Comparison before logical operations
x > 5 and y < 10 // Evaluates as (x > 5) and (y < 10)
// AND before OR
a or b and c // Evaluates as a or (b and c)
Use parentheses to override default precedence:
(2 + 3) * 4 // Evaluates as 5 * 4 = 20
a and (b or c) // Evaluates AND after OR
Control Flow
Case Expressions
Provides conditional logic with pattern matching syntax. The first matching condition's expression is evaluated and returned.
case(
condition_1 => expression_1,
condition_2 => expression_2,
...
_ => default_expression
)
Examples:
// Simple status mapping
case(
$.status == "active" => "Current",
$.status == "pending" => "In Progress",
_ => "Unknown"
)
// Data transformation
case(
size_of($.items) == 0 => dict(status="empty", count=0),
size_of($.items) > 10 => dict(
status="full",
count=size_of($.items),
firstItem=$.items[0]
),
_ => dict(status="partial", items=$.items)
)
// Type-based handling
case(
$.value == null => "missing",
str_contains(to_str($.value), "error") => "error",
$.value > 100 => "high",
_ => "normal"
)
Built-in Functions
Utility Functions
size_of()
Returns the size of the argument based on its type.
Syntax: size_of(expression)
Input Types:
- Array: Returns number of elements
- Dictionary/Object: Returns number of key-value pairs
- String: Returns string length
Returns: Integer
Examples:
// Array size
size_of($.items) // Returns number of elements
size_of(array(1, 2, 3)) // Returns 3
// Dictionary size
size_of(dict(a=1, b=2)) // Returns 2
size_of($.user.properties) // Returns number of properties
// String size
size_of("hello") // Returns 5
size_of($.message) // Returns string length
Dictionary Operations
dict()
Creates a dictionary with specified key-value pairs.
Syntax: dict(key1=expression1, key2=expression2, ...)
Keys must be valid identifiers:
- Start with letter or underscore
- Contain only letters, numbers, and underscores
- Case-sensitive
Returns: Dictionary
Examples:
dict(
city=$.address.city,
state=$.address.state,
details=dict(
zip=$.address.zip,
country=$.address.country
)
)
dict_merge()
Merges multiple dictionaries into one. Later dictionaries override earlier ones for duplicate keys.
Syntax: dict_merge(dict1, dict2, ...)
Input: Two or more dictionaries Returns: Dictionary
Example:
dict_merge(
$,
dict(newField="value"),
grok($.__raw__, "%{PATTERN}")
)
Array Operations
array()
Creates an array from the provided arguments. Arguments can be of any type and can be mixed.
Syntax: array([expression1, expression2, ...])
Returns: Array
Example:
array($.field1, $.field2, "constant", 42)
arr_foreach()
Applies an expression to each element of an array.
Syntax: arr_foreach(arrayExpression, elementVariable, transformExpression)
Parameters:
- arrayExpression: Expression that evaluates to an array. If it points to an object, treat that object as a single element array.
- elementVariable: Variable name to represent each array element
- transformExpression: Expression to apply to each element
Returns: Array of transformed elements
Example:
arr_foreach(
$.users,
user,
dict(
name=user.name,
age=user.age,
type=$.userType
)
)
arr_flatten()
Flattens an array of arrays by one level.
Syntax: arr_flatten(arrayOfArrays)
Input: An array containing other arrays Returns: A flattened array with one level of nesting removed
Example:
// Given:
// $.nested = [[1, 2], [3, 4], [5, [6, 7]]]
arr_flatten($.nested)
// Results: [1, 2, 3, 4, 5, [6, 7]]
Note: This performs a shallow flatten operation, not a deep recursive flatten. Deeper nested arrays remain intact.
String Operations
str_split()
Splits a string into an array of substrings based on a delimiter.
Syntax: str_split(string, delimiter)
Input:
- String to split
- Delimiter string
Returns: Array of strings
Example:
str_split("a,b,c", ",") // Returns ["a", "b", "c"]
to_str()
Converts a value to string.
Syntax: to_str(expression)
Input: Any value Returns: String, or null if input is null
Example:
to_str($.numericField) // Converts number to string
to_str(null) // Returns null
upper()
Converts a string to uppercase.
Syntax: upper(expression)
Input: String Returns: String Throws: Error if input is not a string
Example:
upper($.name) // "john" -> "JOHN"
lower()
Converts a string to lowercase.
Syntax: lower(expression)
Input: String Returns: String Throws: Error if input is not a string
Example:
lower($.name) // "JOHN" -> "john"
str_contains()
Tests if a string contains a substring.
Syntax: str_contains(string, substring)
Input: Two strings (string to search, substring to find) Returns: Boolean Throws: Error if either input is not a string
Examples:
// Basic usage
str_contains($.message, "error") // Returns true if found
// In case expressions
case(
str_contains($.level, "ERROR") => "critical",
str_contains($.level, "WARN") => "warning",
_ => "info"
)
// With other functions
str_contains(lower($.text), $.searchTerm)
grok()
Applies a Grok pattern to extract structured data from a string.
Syntax: grok(string, pattern)
Input:
- String to parse
- Grok pattern string
Returns: Dictionary of extracted fields Throws: Error if pattern is invalid
Example:
grok($.rawLog, "%{TIMESTAMP:timestamp} %{WORD:level}: %{GREEDYDATA:message}")
Time and Date Operations
ts_str_to_epoch()
Converts a timestamp string to epoch milliseconds.
Syntax: ts_str_to_epoch(timestampString, formatPattern)
Input:
- Timestamp string
- Java SimpleDateFormat pattern
Returns: Integer (epoch milliseconds) Throws: Error if timestamp doesn't match pattern
Example:
ts_str_to_epoch($.timestamp, "yyyy-MM-dd HH:mm:ss")
epoch_to_ts_str()
Converts epoch milliseconds to formatted timestamp string.
Syntax: epoch_to_ts_str(epochMillis, formatPattern)
Input:
- Epoch milliseconds (integer)
- Java SimpleDateFormat pattern
Returns: String Throws: Error if timestamp is invalid
Example:
epoch_to_ts_str($.epochTime, "yyyy-MM-dd HH:mm:ss")
duration_str_to_mills()
Converts a duration string to milliseconds.
Syntax: duration_str_to_mills(durationString)
Input: Duration string in "HH:mm:ss" format Returns: Integer (milliseconds) Throws: Error if duration format is invalid
Example:
duration_str_to_mills("01:30:00") // Returns 5400000 (1.5 hours in milliseconds)
Number Operations
parse_int()
Parses a string into a long integer (equivalent to Java's Long.parseLong()).
Syntax: parse_int(string)
Input: String containing an integer Returns: Long integer Throws: Error if string is not a valid integer
Example:
parse_int("42") // Returns 42
parse_float()
Parses a string into a floating-point number (equivalent to Java's Double.parseDouble()).
Syntax: parse_float(string)
Input: String that represents a number Returns: Double Throws: Error if string is not a valid number
Example:
parse_float("3.14") // Returns 3.14
parse_float("-1.5") // Returns -1.5
parse_float("42") // Returns 42.0
Error Handling
Null Safety
- Operations on null values generally propagate null
- Function-specific null handling is documented in each function
- Use case expressions for explicit null handling:
case(
$.field == null => "missing",
_ => to_str($.field)
)
Type Safety
- Type mismatches in operations throw errors
- Explicit type conversion functions available:
- to_str() for string conversion
- parse_int() for integer conversion
- parse_float() for floating-point conversion
Common Error Conditions
-
Type Mismatches
// These will throw errors:
"string" * 5 // Can't multiply string
upper(42) // upper() requires string
size_of(true) // size_of() not valid for boolean -
Field Access
// These return null:
$.nonexistent.field // Missing field
$.array[999] // Index out of bounds
// These throw errors:
$.string[0] // Array access on non-array
$[true] // Invalid field access -
Function Arguments
// These throw errors:
size_of() // Missing argument
str_contains("a") // Missing second argument
upper(42) // Wrong argument type
Best Practices
-
Check for null values:
case(
$.amount != null => $.amount * 100,
_ => 0
) -
Provide default values:
dict(
name=case($.name != null => $.name, _ => "unknown"),
value=case($.value != null => $.value, _ => 0)
) -
Validate data structure:
case(
not array($.data) => dict(error="data must be array"),
_ => arr_foreach($.data, item, process(item))
)