In the last post we looked at how to find log events based on text that they contain.

Searching for some text is often the first step in a log analysis session, but when it comes to navigating logs, structured data is far easier to work with.

In Seq, events have fully-structured, typed properties that can be used in queries. If you search for an event and expand it like the one below, you’ll see them:

Properties

This event was produced with a Serilog statement like:

log.Information("{CustomerName} removing [email protected]} from cart", name, item);

You might have noticed that Seq highlights elements of the log message like the customer’s name and cart item object in this example. This shows that the highlighted part of the message is actually structured data that can be queried on; hovering over one of these will show the property name that holds the value.

In this case we can see that the customer’s name is stored in a property called CustomerName. Clicking the green tick beside the property name allows you to move on to find all events with that property value:

Equality

This is an easy way to get acquainted with Seq’s query syntax; you now see how a property name can be compared with a value using the == operator.

Text properties like CustomerName support ==, !=, as well as the Contains() function, case-sensitive comparisons and regular expression matching we talked about in the last post.

If your events contain numeric data, you get a few more operators: >, >=, <, <=, +, -, *, / and %, to be exact!

I’ll spare you the exhaustive list of Boolean operators, but they’re pretty much what you expect.

The CartItem property in this event appears as JSON in the log view. The original object passed in to the log method looked like:

class CartItem
{
    public string Description { get; set; }
    public decimal Total { get; set; }
} 

(The example, in case you’re wondering, is from an old load-testing harness, so there are no points to be won for realism.)

It is natural to expect to query on these nested properties too, and in fact you can in the obvious way with the dot operator:

CartItem.Description == "Toothpaste"

Numeric property names

There’s one last thing to know when you’re working with properties in Seq. If you’re using the classic .NET format string placeholders 0, 1 and so on, either with Serilog:

Log.Information("New customer {0} logging on", _name);

Or, with NLog (which Seq now supports rather well) you can refer to the property by escaping the numeric index with an @, like:

"logging on" && @0 == "Nick”

(It’s often necessary to scope down a query like this with a fragment of text like "logging on" is used above, since the same numeric property names have wildly different meanings on each different event type.)

Properties are one of the central reasons Seq feels so different from text-based log handling tools; I hope you’ll give them a try and agree!