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

Filter Syntax

Seq supports a C#-like syntax for filtering events based on 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, and show you how the basics of the query 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 organised around a few high-level topics:

Text

The simplest text queries in Seq are text fragments typed directly into the filter bar:

1720

When Seq determines that the filter isn't a valid expression, it searches log messages for the complete string of text.

A small gray question mark ? 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 HIS-e531-5eb5e3"

Text expressions support the same backslash-based \ escape sequences as C# and JavaScript do.

By default, text matching is case-insensitive. Case-sensitive matching can be forced by prepending an 'at' sign @:

@"logged on as contact HIS-e531-5eb5e3"

And, or, not

Seq provides familiar Boolean operators including && (logical and), || (logical or) and ! (logical negation/not). These can be applied directly to text expressions to form more complex queries:

"logged on" && ("HIS-e531-5eb5e3" || "HIS-5395-eb5887")

Regular Expressions

Full regular expression searching is supported. Regular expressions are delimited with forward-slashes. To match "hello, world" and "herd":

/h.*d/

Back-slashes can be used to escape an embedded forward-slash:

/http:\/\/getseq\.net/

👍

Don't forget...

If a query isn't selecting the events you expect, look for the ? 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:

1715

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:

Application == "Patient Portal"

The property name Application is self-explanatory. The value "Patient Portal" is a text expression and so it supports the same case-sensitivity (@) rules as described in that section.

📘

Anywhere you see a text expression in Seq, a regular expression can also be used - so Application == /P.*l/ would work here, too.

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.

Seq also supports function-style operators, called as Name(arg0, arg1, ...). On string-valued properties for example, StartsWith(), EndsWith() and Contains() are useful:

Contains(Application, "Patient")

A full list of built-in functions appears in the section on built-ins.

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.

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 that can be referred to using hex literals, for example "Pre-discount tax total calculated at {TaxAmount}"$A26D9943, while "Customer paid using {PaymentMethod}"$4A310040.

To select all events with a particular event type, just specify the hex literal:

$4A310040

(To find this value in the first place, use the Type drop-down menu that's shown on expanded events.)

Event types can be combined into more complex expressions:

$4A310040 && TaxAmount > 100

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 .NET DateTime as well as DateTimeOffset properties on events:

DateTime(FinishedAt) > DateTime(ExipresAt)

Collections

It’s not uncommon for structured events to carry properties that are collections. For example we might log events on a Q&A site like:

Log.Information("User {Username} posted a question tagged {Tags}", username, tags);

Resulting in events like:

1228

Instead of being marked with a single tag, each event carries a collection of zero-or-more.

Numeric Indexing

As you would expect, numeric indexing is supported:

Tags[0] == "twitter"

Wildcard Filters

To find events with a specific element in the Tags collection, write a filter as though testing a single item, using a wildcard in place of the index that would normally appear:

Tags[?] == "seq"

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!"

Built-in Properties and Functions

All Seq events expose a set of built-in properties that are distinguished by the @ symbol in their name:

PropertyDefinitionExample ContentsUsage
@ArrivedAn integer indicating the order in which the event arrived at the Seq server12344@Arrived <= Arrived("event-d8ce...0000")
@DocumentThe full JSON document representing the event, as a string{ "Timestamp": ... }Contains(@Document, "coffee")
@ExceptionThe exception associated with the event if any, as a stringSystem.InvalidOp...Contains(@Exception, "zero")
@IdThe event's unique id in Seqevent-d8ce...0000@Id == "event-d8ce...0000"
@LevelThe logging level of the event, as a stringWarning@Level != "Warning"
@RenderedMessageThe text message associated with the eventFailed to open file...StartsWith(@RenderedMessage, "Failed")
@TimestampThe UTC timestamp associated with the event2015-02-28T13:56:20.293@Timestamp > DateTime("2015-01-13 06:00Z")

A set of built-in functions provide more sophisticated operations on structured data.

General Functions

Has(property)

Evaluates to true if the supplied expression can be bound, otherwise, false. Example:

Has(OrderId)

This will select all events that have an OrderId, regardless of its value.

TypeOf(structure)

Given a structured property tagged with its original type ($typeTag or _typeTag added by Serilog), return the original type as a string.

TypeOf(Message) == "PlaceOrderCommand"

Text Functions

Contains(text, pattern)

Searches within a text value for a pattern. Example:

Contains(CustomerName, "a")

This will match events with a customer name like "Sam" but not "Bob".

StartsWith(text, pattern)

Searches for a pattern at the start of a text value. Example:

StartsWith(CustomerName, @"Al")

This will match events with a customer name like "Alice", but not "alice" because in this case the operand uses @ to specify a case-sensitive match.

EndsWith(text, pattern)

Like StartsWith, but searches the end of the string. Example:

EndsWith(CustomerName, /[ea]/)

This example uses a regular expression, so it will match "Alice" and "Flora" but not "Michael".

IndexOf(text, pattern)

Searches within text, returning the zero-based index of the first occurrence. Example:

IndexOf(CustomerName, "al") == 0

For the customer name "Alice" this will be true, for "Bob" the result will be false. If the text expression is defined, but the pattern does not appear, the result is -1.

Length(text)

Returns the length of a piece of text. Example:

Length(CustomerName) == 5

This evaluates to true for "Alice", false for "Bob".

Temporal Functions

DateTime(value)

Interprets the supplied text value as a date-time object. Example:

Order.Placed == DateTime("2016-03-31 14:00:00 -7")
TotalMilliseconds(timespan)

Given a property in .NET TimeSpan format (e.g. "00:12:33.880"), return the total number of milliseconds represented:

TotalMilliseconds(Elapsed) > 100
Arrived(id)

Given an event id, evaluates to that event's arrival order. Used in conjunction with the @Arrived built-in property.

@Arrived <= Arrived("event-78f6229870b208d2096c030000000000")

👍

Quick filter shortcuts

Many queries listed here are provided as one-click shortcuts via the row of blue links beneath the message text in an expanded log event - Id, Level, Type and so-on.