Search Expression Syntax
Seq supports a friendly and powerful syntax for finding events based on text and structured properties.
Read the primer?
If you're new to Seq's query language, start with Searching and Analyzing Logs - it's a complete syntax primer for the busy developer.
The Seq filter bar can be used find log events containing certain text, or having properties with particular values.
If you're just getting started with Seq, you will find that a combination of text searching (simply type what you're looking for) and filtering with the tick and cross icons next to event properties will cover most of what you need, as well as show you how the basics of the filter syntax works.
When you're ready to learn more, this page will introduce you to the complete syntax so you can gain the full power of Seq's filtering capabilities. It's loosely organized around a few high-level topics:
- Text - finding strings within messages
- Properties and Operators - comparisons useful with structured event data
- Event Types
- Working with Dates and Times
- Collections - matching items within collection-valued properties
An additional reference describes the built-in properties and functions that can be used in filters.
Text
The simplest text queries in Seq are text fragments typed directly into the filter bar:
When Seq determines that the filter isn't a valid expression, it searches log messages for the complete string of text.
A small gray
Text
icon is shown beneath the filter to indicate this has happened, and if you were expecting your filter to be a valid expression, you can click on the icon to find out why it was invalid.
To force Seq to search for text, even if that text happens to be a valid filter expression, enclose it in "double quotes"
:
"logged on as contact AUTO-3af7-dadc93"
Double-quoted text fragments use the same backslash-based \
escape sequences as C# and JavaScript do.
Single vs double-quoted strings
While text fragments are
"double-quoted"
, Seq filters and SQL-style queries use SQL-style'single-quoted'
string literals, for example in the expressionEnvironment = 'Test'
.
Searches based on text fragments are case-insensitive.
and
, or
, not
and
, or
, not
Seq provides familiar Boolean operators including and
(logical and), or
(logical or) and not
(logical negation/not). These can be applied directly to text expressions to form more complex queries:
"logged on" and ("HIS-e531-5eb5e3" or "AUTO-3af7-dadc93")
Regular Expressions
Full regular expression searching is supported. Regular expressions are delimited with forward-slashes. To match "hello, world" and "hold":
/h.*d/
Back-slashes can be used to escape an embedded forward-slash:
/https:\/\/datalust\.co/
Don't forget...
If a query isn't selecting the events you expect, look for the
Text
icon and click it to get syntax help.
Properties and Operators
Structured events usually come with a rich set of properties that can be used for filtering. Expanding an event will show the available properties, and clicking the green tick beside the property name provides some basic filtering options:
This is a useful way to become acquainted with the operators that can be applied to event properties. Find will generate a filter expression like:
ProductId = 'product-32'
The comparison performed here is case-sensitive. Use like
instead of =
to perform a case-insensitive match.
Anywhere you see string literals in Seq, a regular expression can also be used - so
Application = /P.*l/
works as expected here, too.
Listing Available Properties
The built-in Available Properties SQL query, accessible in the lower-right portion of the signal bar, will list the available properties on all events matched by the current filter.
Basic Comparisons
Seq supports the typical set of comparison operators: =
, <>
, <
, <=
, >
, >=
have the meanings equal, not equal, less than, less than or equal, greater than and greater than or equal.
Strings can also be compared using the SQL like
operator; the wildcards %
(any number of characters) and _
(one character) are used:
Application like 'P%'
Comparisons including =
and like
are case-sensitive. For case-insensitive matching, append the ci
modifier:
Application like 'P%' ci
The ci
modifier works everywhere in Seq, for example, Application = 'Test'
is case-sensitive, while Application = 'test' ci
will match TEST
, test
, TeSt
and so on.
Seq also recognizes function-style operators, called as Name(arg0, arg1, ...)
. On string-valued properties for example, StartsWith()
, EndsWith()
and Contains()
are useful:
StartsWith(Application, 'P')
A full list of built-in functions appears in the Built-in Properties and Functions reference.
Nested Properties
Seq uses dot .
syntax to allow nested properties on complex objects to be queried. For example Cart.Total
references the Total
property of the object in the Cart
property.
IN
expressions
IN
expressionsA property value can be matched against several alternatives using IN
:
Application in ['Web', 'API']
Conditionals
Seq supports conditional expressions using if
/then
/else
syntax:
if Quantity = 0 then 'None' else 'Plenty'
Conditionals can be chained:
if Quantity = 0 then 'None' else if Quantity < 20 'Some' else 'Plenty'
Event Types
Perhaps the most useful, but seldom-noticed benefit of a structured log is having the first-class notion of an event type.
When analyzing a traditional text-based log, there’s no concrete relationship between the messages:
Pre-discount tax total calculated at $0.14
Pre-discount tax total calculated at $5.20
Customer paid using CreditCard
From a tooling perspective, each might as well be a unique block of arbitrary text.
In a structured log from Serilog, the message template passed to the logging function is preserved along with the event. Since the first two come from the template:
"Pre-discount tax total calculated at {TaxAmount}"
While the third comes from:
"Customer paid using {PaymentMethod}"
We can use this information to unambiguously find or exclude either kind of event. Working with message templates is verbose though, so Seq produces a 32-bit hash of the message template and makes this available in the @EventType
built-in property.
For example "Pre-discount tax total calculated at {TaxAmount}"
→ 0xA26D9943
, while "Customer paid using {PaymentMethod}"
→ 0x4A310040
.
The type of an event can be viewed by clicking an event to expand it. The Type drop-down menu displays the event type.
To find all of the events with a specific type is easy:
@EventType = 0x4A310040
Working with Dates and Times
To select events in a given date range, clicking the "Show or hide the histogram" button just below the search box provides quick and easy time-based navigation:
For more complex time-based operations, the built in @Timestamp
property and DateTime()
functions can be used.
In a query you might write:
@Timestamp > DateTime('2014-01-03')
This compares the event's @Timestamp
against a UTC literal. To specify a timezone use +
/-
syntax:
@Timestamp > DateTime('2014-01-03 +10')
The DateTime()
function can construct correct date/time objects from ISO 8601 and various other formatted properties on events:
DateTime(FinishedAt) > DateTime(ExipresAt)
Durations formatted in d.HH:mm:ss.fff
syntax can be manipulated in queries using the TotalMilliseconds()
conversion function:
TotalMilliseconds(Elapsed) > 3000
For a full description of Seq's date and time manipulation functions, see Working with Dates and Times.
Collections
It’s not uncommon for structured events to carry properties that are collections. For example we might log events like:
Log.Information("Updated {ProductId} with categories {Categories}", "product-32", new[] { "drinks", "coffees" });
Resulting in events like:
In this example each event carries a collection of zero-or-more strings in the Categories
property.
Numeric Indexing
As you would expect, numeric indexing is supported:
Categories[0] = 'drinks'
Wildcard Filters
To find events with a specific element in the Categories
collection, write a filter as though testing a single item, using a wildcard in place of the index that would normally appear:
Categories[?] = 'drinks'
The question mark wildcard ?
matches any element in the collection, while an asterisk *
wildcard only matches if all elements satisfy the condition.
Wildcards work in any comparison where one side is a property path (including indexers and dotted sub-properties). Multiple wildcards along the path are supported.
You can write the following expression to find questions where all answers are 'Yes!'
:
Answers[*].Content = 'Yes!'
Cheat Sheet
Need a handy reference to keep beside your desk? We've put together a cheat sheet with filtering basics. Download the PDF here.
Updated about 3 years ago