Formula Search Field Expression Plugin
The Formula plugin extracts values from a Log Event by combining functions, much like a formula in Microsoft Excel. Use it when a single plugin isn't enough: to extract and then transform a value, to combine values from the body and the context, to count or sum, or to look up a value in a SQL database.
- ✅ Extract from the message body, context properties, and Log Event fields in one expression
- ✅ Nest functions: the result of one function is the content of the next
- ✅ Convert, alter, test, and calculate on the extracted values
Tip
Start with a dedicated plugin such as XPath or JSON Path when it can do the job; see Choose a plugin. Use Formula when you need to combine or transform.
How a Formula Is Evaluated
A formula is evaluated from the inside out. A source function reads data from the Log Event; every other function takes content (the output of the function inside it) and returns new content. The final result becomes the Search Field values.
Diagram: a formula reads a source from the Log Event, extracts values, optionally transforms or tests them, and returns the Search Field values.
Nesting, Step by Step
Input
<Orders>
<Id>3</Id>
<Id>6</Id>
</Orders>
Formula
count(xPath('/Orders/Id', body))
Evaluation
bodyreturns the whole message body.xPath('/Orders/Id', body)returns two values:3and6.count(...)counts them.
Result
2

The nested formula returns 2, one value counted per matching Id element.
Formula language rules
These rules apply to every function. Function pages link here instead of repeating them.
| Rule | Details | Example |
|---|---|---|
| Content | The data a function works on: a source function (body, context, field) or the result of another function. |
toUpperCase(context('Region')) |
body has no parentheses |
Write body, not body(). |
regex('\d+', body) |
| Strings use single quotes | Every text argument is enclosed in '…'. Numbers are written as is. |
substring(0, 3, body) |
| Escape a single quote by doubling it | A literal ' inside a string is written ''. |
jsonPath('ord''erid', body) |
| Backslashes are written once | Regular expressions use normal .NET syntax; don't double backslashes. | regex('\d+', body) |
# and spaces in regular expressions |
Formula regular expressions ignore unescaped whitespace and treat # as the start of a comment, and matching ignores case. Write a literal # as [#] or \# and a literal space as \s or [ ]. 'Order#.*' silently runs as 'Order'. |
context(regex('Order[#].*')) |
context(regex(...)) must match the whole key |
The text the pattern matches is used as the key to read, so a partial match such as '^Order[#]' finds nothing. End the pattern with .*. |
context(regex('Order[#].*')) |
| Function names are case-insensitive | xpath, xPath, and XPATH all work. The reference tables write them in camelCase; examples show them exactly as typed in their screenshot. |
jsonpath('a[*].b', body) |
| Several values flow through | Extract functions can return several values. The next function handles each value, and Math functions aggregate them. | count(jsonPath('a[*].b', body)) |
| Search Field values are unique | The values stored on a Search Field are unique; duplicates are collapsed. The test bench shows the Number of unique matches. Inside a formula, Math functions still see how often each value occurred; see unique below. |
3 6 6 → 3, 6 |
Logical functions return true or no value |
equal, notEqual, startsWith, and endsWith return true when the condition holds, and no value when it doesn't. When one argument returns several values, one match is enough; add an unquoted true as the last argument to require every value to match. |
startsWith('U', regex('GMT\|UTC', body)) → true |
| XPath ignores namespaces | Element names match without namespace prefixes or declarations. | xPath('Orders/Order/Id', body) on <ns0:Orders …> |
Escaping Single Quotes
Input
{"ord'erid":"123","name":"John Doe"}
Formula
jsonPath('ord''erid', body)
Result
123

The key ord'erid is written ord''erid inside the quoted JSONPath expression.
Function reference
Each function has its own page with parameters, return values, and examples.
Source
Read data from the Log Event.
| Function | Returns |
|---|---|
| body | The whole message body as text |
| context('Key') | The value of one context property |
| context(regex('Key pattern')) | The values of all context properties whose whole key matches the regular expression |
| contextKey(regex('Key pattern')) | The keys (not the values) of the context properties that match |
| field('fieldName') | The value of a Log Event field (case-sensitive name) |
Extract
Pick values out of structured or unstructured content.
| Function | Returns |
|---|---|
| csv(headerRowsToSkip, 'delimiter', columnIndex, 'commentSymbol', content) | The values of one column (zero-based) of delimited text |
| jsonPath('expression', content) | The values that match a JSONPath expression |
| jsonPathKey('expression', content) | The property names (keys) that match a JSONPath expression |
| regex('expression', content) | The whole matches of a regular expression |
| regexGroup('expression', 'groups', content) | The captured groups of a regular expression |
| sqllookup('connectionStringId', 'database', 'table', 'searchColumn', 'resultColumn', content) | A value looked up in a SQL Server table |
| xPath('expression', content) | The values that match an XPath 1.0 expression |
| xPath2('expression', content) | The values that match an XPath 2.0 expression |
Convert
Change the encoding or case of content.
| Function | Returns |
|---|---|
| base64decode(content [, 'source encoding']) | Decoded text from base64 |
| base64encode(content [, 'input encoding']) | Base64 text |
| convert('source encoding', 'target encoding', content) | Content re-encoded from one character encoding to another |
| toLowerCase(content) | Lowercase text |
| toUpperCase(content) | Uppercase text |
Alter
Change text.
| Function | Returns |
|---|---|
| concat(content, ..., content) | All arguments joined into one string |
| removebom(content) | Content without a leading byte order mark (BOM) |
| replace('oldValue', 'newValue', content) | Content with every occurrence of a text replaced |
| replaceregex('pattern', 'newValue', content) | Content with every regular expression match replaced |
| substring(startIndex, length, content) | Part of the text, from a zero-based start index |
Logical
Test content.
| Function | Returns |
|---|---|
| equal('expression', content [, matchAllValues]) | true when content equals the expression |
| notEqual('expression', content [, matchAllValues]) | true when content differs from the expression |
| isnull(content, 'default') | The default when content is null or empty, else the content |
| startsWith('expression', content [, matchAllValues]) | true when content starts with the expression |
| endsWith('expression', content [, matchAllValues]) | true when content ends with the expression |
Math
Aggregate values. The optional unique argument is an unquoted true or false: with false, a value that occurs several times counts every time (two invoice lines of 100 → sum = 200); with true, identical values count once (→ 100). Values are compared as text, so 100 and 100.00 are different. The default differs per function, as shown below; leave it false for totals.
| Function | Returns |
|---|---|
| avg(content [, unique]) | The average of the numeric values; unique defaults to false |
| count(content [, unique]) | The number of values; unique defaults to true |
| length(content [, unique]) | The length in characters of the content; unique defaults to true |
| max(content [, unique]) | The largest numeric value; unique defaults to true |
| min(content [, unique]) | The smallest numeric value; unique defaults to true |
| sum(content [, unique]) | The sum of the numeric values; unique defaults to false |
Performance
- Every formula runs for every matching Log Event during logging and re-index; keep formulas as short as the job allows.
- Use
xPath(XPath 1.0, forward-only reader) for large XML; usexPath2only when you need XPath 2.0 features. sqllookupqueries SQL Server for each evaluation; see sqllookup before using it on high-volume Message Types.