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 - finding strings within messages
- Properties and Operators - comparisons useful with structured data
- Event Types
- Working with Dates and Times
- Collections - matching items within collection-valued properties
- Built-in Properties and Functions - a reference covering the built-ins that Seq provides
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 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:
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:
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:
Property | Definition | Example Contents | Usage |
---|---|---|---|
@Arrived | An integer indicating the order in which the event arrived at the Seq server | 12344 | @Arrived <= Arrived("event-d8ce...0000") |
@Document | The full JSON document representing the event, as a string | { "Timestamp": ... } | Contains(@Document, "coffee") |
@Exception | The exception associated with the event if any, as a string | System.InvalidOp... | Contains(@Exception, "zero") |
@Id | The event's unique id in Seq | event-d8ce...0000 | @Id == "event-d8ce...0000" |
@Level | The logging level of the event, as a string | Warning | @Level != "Warning" |
@RenderedMessage | The text message associated with the event | Failed to open file... | StartsWith(@RenderedMessage, "Failed") |
@Timestamp | The UTC timestamp associated with the event | 2015-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.
Updated less than a minute ago