Documentation
DocumentationDiscussions
Documentation
These docs are for v2020.1. Click to read the latest docs for v2024.3.

Search Expression Syntax

Seq supports a friendly and powerful syntax for finding events based on text and structured properties.

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:

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:

1280

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 expression Environment = 'Test'.

Searches based on text fragments are case-insensitive.

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:

1280

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.

1280

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

A 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 Seq's All time tab to activate the timeline view is most effective.

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 .NET +/- syntax:

@Timestamp > DateTime('2014-01-03 +10')

The DateTime() function can construct correct date/time objects from ISO 8601 and .NET-formatted DateTime as well as DateTimeOffset properties on events:

DateTime(FinishedAt) > DateTime(ExipresAt)

.NET-formatted TimeSpans can be manipulated in queries using the TotalMilliseconds() conversion function:

TotalMilliseconds(Elapsed) > 3000

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:

1310

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.

1298