Seq 1.4 preview is out!

The features planned for Seq 1.4 are starting to come together. There’s a new preview available to download on the Seq website (direct download).

While 1.4 is still a little way off “done”, many of the improvements we’ve made are usable today; here’s a run through what you can expect from the new version.

What’s Seq? Seq is the fastest way for .NET teams to improve visibility using structured application logs. If you’re using Serilog, you’ll find Seq is the perfect partner – trivially easy to set up, and built for structured log events so querying them is simple from “day 1” of a project. You already use CI and automated deployment: Seq is the next piece of the puzzle, closing the loop to show your team what’s happening in development, testing and production.


New in 1.4:


Charts show the count of matching events in a time period. You can view the last day (by hour), last week (by day), last month (by day) or last year (by week). It’s a simple feature that I’m sure we’ll expand on, but already a great way to keep a “finger on the pulse”.

To add a chart, filter the “events” view to show just what you want to chart, then drop down the “refresh” button and select “Add to dash”. By default, queries are shown on the dash as counters; to toggle between the counter and chart display, there’s a little icon in the top left that appears on hover.


(If you’re already using counters with Seq 1.3, you’ll need to recreate them before historical data will be indexed by the 1.4 preview.)

Quick(er) switching between views

A much-requested improvement: when no view is selected, the first 10 views will be shown in a list (saving a few clicks when switching between views).


Extended text operators

A bunch of work has gone into better string comparison functions in this version. Seq queries now support:

  • Contains(text, pattern)
  • StartsWith(text, pattern) and EndsWith(text, pattern)
  • IndexOf(text, pattern), and
  • Length(text)

In each of these, “pattern” can be case-insensitive, case-sensitive, or a regular expression. There’s some more information and examples in the documentation.

Date functions and @Timestamp

Events in Seq now carry a queryable @Timestamp property, and we’ve added a DateTime() function that can be used with it. Check out the documentation for some examples here.

Keep the feedback coming!

Download the preview, try it out, and let us know what you think! You know where to find me :) – and there’s also a Seq discussion group we’d love you to join, and a Seq Twitter account if you’d like to keep in the loop.

Serilog gets a mention at NDC Oslo 2014

It was really cool to see this session from NDC about Elasticsearch/Logstash/Kibana featuring Serilog from just after 16:00.

Monitoring your app with Logstash and Elasticsearch from NDC Conferences on Vimeo.

It’s fun watching Serilog presented by people who obviously “get it”. And, compared with the alternatives shown earlier in the session, it’s great to see just how easy Serilog is for generating quality structured logs.

(If you’re not using Serilog and interested in the demo code, it’s on GitHub, but please check out this tiny PR if it hasn’t made it through yet.)

Serilog output template formatting changes

The latest Serilog version 1.3.7 fixes some long-standing text formatting quirks.

Serilog has a bit of an idiosyncratic take on formatting text. You could probably say the same about its designer: before Serilog, I used to write a lot of log statements like this:

Log.Information("Could not find documents matching '{0}'", searchTerm);

If you look carefully you’ll note an extra couple of single quotes (') in there around the the {0} token that will be replaced with the search term being logged. I got into this habit because when reading logs I find it less jarring to see random string data quoted, so that my brain doesn’t try to join the whole lot up in a single bewildering sentence:

Could not find any documents matching my pants


Could not find any documents matching 'my pants'

String formatting in Serilog message templates

When I started writing Serilog I thought I’d save a few characters, and encourage consistency, by making this little idiom part of its string formatting engine:

Log.Information("Could not find documents matching {Term}", searchTerm);


Could not find any documents matching "my pants"

I’m sure there are plenty of people who’d rather a different default, but so far no one’s raised it as particularly problematic. If you need to match a specific output format you can use a special “formatting” specifier to turn this off – just append :l (yes, a lowercase letter L) to the token:

Log.Information("Could not find documents matching {Term:l}", searchTerm);


Could not find any documents matching my pants

Reusing message templates for output

The formatting above is applied when rendering log messages into text. A bit later in the design process, I think some time around when Serilog became a public project, we needed another formatting mechanism, this time to control how the different parts of the log event including the message get laid out e.g. for display at the console.

Log.Logger = new LoggerConfiguration()
  .WriteTo.Console("{Timestamp:G} [{Level}] {Message}{NewLine:l}{Exception:l}")

You’ll notice the same style of format string appears in there. The engine used to write the text is the same; there were (and are) a lot of advantages to reusing this code for “output templates” like this.

Unfortunately, some of the decisions that work well when rendering a structured message, get in the way when presenting text like this. You’ll see above one of the oddities – the pre-defined NewLine and Exception properties are represented as strings under the hood, so the :l literal specifier has to appear in there to avoid unsightly quotation marks appearing in the output. Not a big deal really, but too much to have to grasp as a new user.

The other issue is that in message templates, i.e. when calling Log.Information() and friends, it’s an error to provide less arguments than the number of tokens that appear in the string. Serilog helpfully prints out the whole token as text – {Token} so that these issues are obvious when reading the rendered message.

In output templates this isn’t so desirable. Using {HttpRequestId} in the format string should just be ignored if the event doesn’t have such a property attached.

Serilog 1.3.7 changes

I almost versioned this one “1.4”, given there’s quite a change being made, but since the API is binary-identical this one’s out as a patch.

Put simply, Serilog now has slightly different handling of message templates vs. output templates. Message templates keep their current behaviour – quotation marks and all. When used to configure a sink as an output template however:

  • The :l specifier is now “on by default”
  • Missing tokens will simply be ignored

The default output templates all used :l formatting anyway, and so will almost all custom ones, so for 99% of current users I’d say this change will go unnoticed. If you define your own output templates though you can now clean up a bit of clutter and remove the literal specifier from fields like {Exception} and {NewLine}.

If you’re coming to Serilog as a new user, hopefully these changes give you one less reason to go looking for explanatory posts like this one!

Logging and locked files

Serilog 1.3.5 includes some important improvements to the rolling file sink.

No doubt the least pleasant aspect of dealing with log files is concurrency. When multiple processes write to the same log file, either:

  1. They need to coordinate writes using system-wide mutual exclusion (unreliable)
  2. They need to wait for the file to become “free” and close it immediately after writing (slow)
  3. One of them must fail (inconvenient)

Serilog takes a bit of a stand on this and chooses option 3), requiring that each process uses its own log file, or set of rolling files.

This has the advantages of predictability and performance, and I’m happy with the choice.

But, there’s a catch, and it is a nasty one.

IIS and overlapped application pool recycling

When an IIS app pool is “recycled” (shut down and re-started to clean up any leaky resources) the IIS pipeline’s pretty smart about it. Rather than leave a site offline between unloading the old worker process and loading the new one, IIS starts the new process first and only unloads the old one once the new one is serving requests.

Unfortunately, this means the new app pool needs to open a log file still locked by the outgoing process. No logs for you!

Disabling overlapped recycling

For typical intranet sites, or web-facing sites behind a load balancer, disabling overlapped recycling isn’t a huge issue. To date this has been the solution for using Serilog with IIS. But, it isn’t an option for some, and happily those “some” were loud and determined enough to get a better solution into Serilog 1.3.5.

The old rolling scheme

Serilog still doesn’t handle locked single-file logs. Generally these kinds of logs aren’t used in e.g. IIS sites, so the old caveats of a file-per-process still apply if you use WriteTo.File().

Rolling files however already provide a model that maps quite naturally to the “rolling over” of IIS worker processes.

A sequence of files written by the rolling file sink might look like:


As the days pass a new file is created, and eventually the old one is removed.

The fix: rolling when a file is locked

Now, assuming that it’s the third of May, if the IIS app pool is recycled you’ll see a sequence like:


The _001 file will be used by the new worker process, while the old one hangs on to the non-prefixed file.

Some guarantees

What happens when the new process, using the suffixed file, is recycled?

Well, the simplistic response would be for the replacement to open the non-suffixed file, since that is now in all likelihood unlocked. But this would make reading the files a pretty awful experience, as date/time ranges jumped around between them.

Instead, the new process will create:


Important notes

The only caveat to note here is that the implementation is robust to the scenarios that commonly occur when restarting/recycling processes. It doesn’t address long-lived concurrent processes, for that you’ll need to decide on an alternative scheme (or use a more concurrency-friendly sink than what the file sinks can provide).

You should also be aware that the retained file count provided by the rolling file sink is per-file, not per-day, so if you expect frequent overlapped log file recycling, you should allow a few more retained files to ensure you keep the required date range. We’ll probably implement a retained-days count in the future.

Is this the long-term plan?

This is the long-term solution to locked files in Serilog, at least as far as any current plans cover. How does it work for you? Serilog’s a community project and always open to constructive feedback and good ideas.


Seq 1.3 – what’s new?

Seq 1.3 is now available at Since version 1.2 we’ve introduced the ‘dash’ – a hub for your most-used queries and bookmarked events – and made refinements to many other parts of the app.


Seq is designed for keeping tabs on your running applications. For the really important events, you’ll probably use email alerts to be notified when something needs attention, but if you’re like me you’ll have your finger on the pulse of quite a few things, not all of them critical.

For that, Seq 1.3 introduces watches – a saved view over the event stream that Seq will monitor for new events. When an event matches a watch, after a short delay you’ll see that on the shiny new dash:

Dash 1.3

Clicking through to view the matching events will reset the watch counter to zero.

To start watching a view, query, filter or combination of those things, drop down the Refresh button and select Add watch.



Alongside watches on the dash you’ll also find bookmarks. A bookmark is just a link to an individual event, but for as long as the event is bookmarked it won’t be cleaned up by any retention policies you might have set.

Bookmarks are added from the new Pin menu that appears on the detail view of each event.



You can also bookmark an event for another member of your team by choosing the Assign to another user item under Pin.


This is called an assignment and will show up, with some notes if you include them, on the other person’s dash.


If you need to link an event to send it by email etc. you can still create a permalink – these are what they imply, and now also save the event from any applicable retention policy.

Causal ordering

Hiding away in Seq 1.3 is a new killer feature: the “arrival ordering” queries in Seq 1.3 make debugging causality easier and more fun.

Let’s say we’ve hit on an interesting event: a crash or something out of the ordinary that we need to investigate.


In the event details, the new Id drop-down includes Find with predecessors. This will restrict the event stream so that the event we’re viewing is at the top.

Now, by requiring this filter in the query (press Require) we can slice the predecessors of the event along whatever axes we like. What was happening on the machine before this event?


Whatever filter we add, the results will be shown up to and including the event we chose. We can find the last error logged anywhere before this one; the last event logged for the same customer; the last events in the same web request…

Tedious questions to try to answer with a flat log file, but now an absolute breeze with Seq.

Offline compaction

A side effect of the current storage engine Seq uses is that sometimes fragmentation may cause the event store to take more space on disk than it needs. We’re digging deeply into the storage subsystem in coming releases and will ideally provide full online compaction, but in the interim if you find your event store is disproportionately large, you can run:

seq.exe stop
seq.exe compact
seq.exe start

…to reclaim some space.

Virtual directory support

Seq has always allowed listen URLs with deep paths, however in past versions some bugs in the UI meant these didn’t fully work.

In Seq 1.3 you can now set up multiple instances on the same server at nested paths, e.g.


To find out more about setting up instances see the documentation.

Help has moved

We’re putting all of our documentation efforts into improving so it feels only right that help in the application will take you there.

But there’s more!

  • Boolean queries and comparisons with null now match their documented behaviour
  • The installer handles reconfiguring service paths
  • The filter ‘clear’ button is now clickable even with focus on the input field
  • IE ‘compatibility mode’ is now avoided when Seq is run as an intranet site
  • @Id can now be used in filters
  • The ‘single event view’ now correctly supports further filtering on properties of the displayed event
  • Filter history is auto-completed within a session
  • JSON formatting is improved

Actually, it’s hard to capture just how much has changed in the last short month of development. Give Seq 1.3 a try – we think you’ll enjoy the improvements!

Download Seq 1.3 from the project site. The very handy Developer edition is free, and you can request a 30-day trial of Seq Enterprise if you would like to try out multi-user support.

One year of Serilog

I just pushed the first build of Serilog 1.3 to NuGet. This one includes a more flexible JsonFormatter and support for width specifiers in format strings. Not huge changes, but both called for obsoleting some existing methods, and with 1.2 at the venerable age of “.53″ it was time to rev and get back to the nice simple version “1.3.1”.

It occurred to me that we’ve now hit the one year mark in the Serilog project. Version 0.1 was announced on March 29th, 2013 actually!

If there was any doubt back then of the viability of “yet another logger” in the .NET ecosystem, it’s been well and truly dispelled in my mind. Sixteen of us have now contributed to the project, and what’s most exciting to me is that the developers extending, using and discussing Serilog are some of the best and brightest I know. It’s the kind of momentum that makes me confident we’ll see more use and growth in the next year.

For those who follow it, the mention of structured logging as a technology to “trial” in the January 2014 ThoughtWorks Technology Radar is also a good indicator that Serilog is aligned with the facilities .NET developers will come to expect and use widely.

Our 1.0 came only six months ago, so these are still early days, but there are now 38 packages tagged “serilog” on NuGet, and despite the more-than-occasional glitches in the counter ;) the core Serilog package has over 7,400 downloads.

Visits to are also looking healthy:


April’s been a visibly good month, with a lot of interest stirred up by a discussion on .NET Rocks! where I did my best to “get the word out” about how Serilog has totally transformed my thinking about logging.

If you’re using Serilog it would be great to hear more about how it has worked for you, and where you think the project should be aiming next – get in touch here or on our discussion list!

XML configuration for Serilog

Some issues hang on! Serilog’s #3 — XML configuration support — was still grimacing at us from the backlog alongside issues with three digits, until it was unceremoniously closed a few minutes ago.

If you’ve spent any time with Serilog you’ll have noticed the absence of built-in XML configuration support. Something about the project just wanted – and wants – to be a code-centric thing. I guess it is part of lifting the status of logging a bit – ORMs for example moved on from XML configuration to code-first/fluent configuration many moons ago. Instrumenting your app with an event stream is an important thing that deserves a modern configuration API.

XML’s not at all bad though. File paths change, servers have different addresses in different environments, logging levels go up and down. XML’s a great fit for this and we’ve known that all along with Serilog; we’ve just chosen to keep it in its place and write code like:

var logFile = ConfigurationManager.AppSettings["LogFilePath"];

var logger = new LoggerConfiguration()

Over time this gets boring and repetitive I admit. Thats why we’ve now got the Serilog.Extras.AppSettings package.

XML configuration with a twist

As I said – we like XML configuration in its place, but that’s a pretty small place. When I open up App.config or Web.config in a modern .NET project the amount of gunk in there can be pretty confronting.

Most XML config implementations provide their own <configurationSection>s, and those need to be declared, and then the XML syntax used within them generally gets copied from a long list of arcana like the one in the log4net documentation that I’ve visited for years on end.

Serilog’s “app settings” support is different; we use a technique I first saw suggested for Autofac module configuration several years ago.

This revolves around the <appSettings> collection, an element that’s present in almost every .NET configuration file. Here’s an example to illustrate what we’re doing:

  <add key="serilog:minimum-level" value="Verbose" />

Instead of our own custom <serilog> element, we cheat a bit and just look for <appSettings> elements that match a certain pattern (their names start with serilog:). Simple idea, but effective: I’m going to write this whole article without checking the documentation or sample code even once! Remembering a setting name or pattern is much easier for me than remembering a whole pile of custom XML syntax.

Going a bit further, here’s the configuation for two sinks, the console and a log file:

  <add key="serilog:write-to:ColoredConsole" />
  <add key="serilog:write-to:File.path" value="C:\Logs\myapp.txt" />

(Notice you don’t actually have to provide a value for an app setting? I didn’t until recently, but works nicely!)

Where do the magic names ColoredConsole and File.path come from? They’re just encodings of the following method calls:

  .WriteTo.File(path: @"C:\Logs\myapp.txt")

The name of the path parameter obviously wouldn’t be specified in normal usage, but you can see how the XML and code-based configuration match up 1:1.

The extension methods are looked up dynamically using reflection, so you can configure your own sinks this way. You can include multiple parameters for the same sink using multiple keys – for both features check out the wiki page linked below.

Enabling the package

Two steps: 1. Install the Serilog.Extas.AppSettings package from NuGet; 2. add a call to ReadAppSettings() when you’re configuring your logger:

var logger = new LoggerConfiguration()
  ... // Other configuration here, then

You can mix and match app settings with code-driven config, but for each sink you need to use one or the other.

There’s much more detailed documentation here, on the wiki.

But isn’t this super-limited?

I’m happy to trade configuation power for something I can actually remember how to use. Someday we might have a more sophisiticated XML configuration option than this, but unless you can write the PR – I’m served pretty well by this one and not in a hurry.

But this is totally not my style!

That’s fine; it’s an ‘extra’, meaning we ship it separately from Serilog’s core and you’re free to install it if you like it and ignore it otherwise.

Still, I’ll be happy to hear if you do find it useful!

What’s to love about Seq 1.2?

The latest version of Seq is now ready to download from the site. It’s the best one yet, with a much smoother navigation experience and a bunch of small refinements that you’ll appreciate if you spend a lot of time with Seq each day.


Digging into a lump of log data involves a lot of filtering – changing, adding and removing little search expressions to get a different cut of the events.

In Seq 1.0 we were at a bit of an impasse as to how this tied in with the browser’s history stack, so (I’m a bit ashamed to say!) we left it alone.

With the new version we’ve nailed this, I think.

First, filters typed into the filter box are included in browser history, so searching for “Alice”, then searching for “Bob”, then pressing back will again leave you at “Alice”. Simple win!


Furthermore, if you change views, this also is included in history. If you’re searching for an error message in Production and then switch to look for the same message in QA, pressing back will land you at Production again.
The final piece of the puzzle is the query, which remains as a saveable scratch area for filters that stay active regardless of browser navigation.


In Seq 1.0 the initial result set returned for each query was 30 events regardless of your monitor size, and you had to click to see each additional page of 30 events.

No more in 1.2! The new version makes better use of the available space by filling the browser window with events.
Once you’ve requested more events with the “Older” button, Seq will start “infinitely scrolling” so events appear as you go further down the page.

The new version is ready and waiting at

Logging “levels” in a structured world

Every logging framework I’ve ever used has a notion of “levels” like “information”, “warning” and “error” that assign importance to events.

This is necessary because logging produces a lot of data – most of which is less exciting than trimming your dog’s toenails.

Except… when things go wrong, and suddenly that mundane note about successfully starting up saves months of debugging pain.

So, the essential idea of levels is to make it possible to turn “up” and “down” the amount of information being written to a log.

Serilog defines the following levels:

        // Anything and everything you might want to know about
        // a running block of code.

        // Internal system events that aren't necessarily
        // observable from the outside.

        // "Things happen."

        // Service is degraded or endangered.

        // Functionality is unavailable, invariants are broken
        // or data is lost.

        // If you have a pager, it goes off when one of these
        // occurs.

Many logging frameworks have quite complex support for custom levels, and add on other features like categories and keywords so that control over logging output can be controlled at a finer grain.

In Serilog the levels are fixed – internally they’re represented in an enum, and there are no other built-in notions of categorization. Why is that?

You can create your own

Serilog events can carry any key/value property data that you like. If you want to introduce additional logging categories, you can just add those properties to loggers in your app, and do whatever you like with the data.

Let’s say in our architecture we’re interested in “subsystems” and want to categorize events that way:

var log = Log.ForContext("Subsystem", "Ordering");
log.Information("Checking status of {OrderNumber}…", num);
// More logging via ‘log’

This code sets up a logger that will tag all events with a value of "Ordering" for the Subsystem property.

Depending on your log store, you should be able to write a filter like this one to include (or exclude) events from the ordering subsystem:

Subsystem == "Ordering"

The nice thing about this approach is that you can create as many kinds of catgory as you need – subsystems, regions, organizational departments, whatever you like – and use all of them together.

Structured events make tighter control possible

Look at a verbose log. What do you see? Well, most of the verbosity will come from low-level events, but more than that: most of the verbosity will be due to a handful of events.

Classic text logging doesn’t deal well with this; since events are just blobs of text, there’s a lot of effort involved in turning off just one or two.

Serilog doesn’t have this issue. Each event has a MessageTemplate that uniquely identifies the event. Turning off a single event is just a matter of filtering out those with a specific template. Of course, you need a structured log store to make this work (Seq’s Event Types provide this for example) but it’s natural that if you’re using a structured logger you’ll be using one of the many storage options that maintain this ability.

With the most verbose offenders out of the way, even low-level logs can be quite pleasant to browse.

So what’s the point here?

Categorizing events up-front is less important when writing structured logs, and if you’re going to bother with anything finer that than the simple Information, Warning, Error and so-on provided out of the box by Serilog, you’ll be better served with a categorization system (or systems) of your own, than anything Serilog could define for you.

Seq is ready for prime-time

Last December I took the lid off of Seq, a log server for .NET that is built with first-class support for structured events. Well, in a great example of agile planning, the “Release Seq 1.0” ticket came in a long way ahead of “Announce Seq 1.0” so here, three weeks after our official release, is the post to let you know it has happened.

2014-03-23 11_23_35-Seq - .NET Structured Event Server

What does this mean?

It’s now safe to say that Seq is “going to fly” – we’ve had enough feedback to be confident that Seq is ready for use in anger, and commercially we’ve had enough interest, enquiries and sales to know that it is worth our while to keep driving the product forward.

What’s Seq and where’s it going?

Fundamentally, Seq helps you, your team and your stakeholders gain visibility into your applications – even when they’re distributed across multiple machines or locations.

Releasing our preview started a lot of conversations that ultimately shape how we see Seq going forward. This is the picture today:

  • Seq is driven by structured data – structured logging is an opportunity to get the visbility benefits of techniques like messaging or event sourcing, but without the deep architectural commitment. The time for structured logging is here, with better tools available than ever before, and Seq is going to be the #1 complement to those tools in the .NET world.
  • Seq is for development and operations – while there are great opportunities to use structured log data for analytics and data mining, Seq is primarily about removing friction when developing and operating systems. Integration points like Seq apps, email and tabular export make analytics and BI easy, when you need to surface data to other stakeholders.
  • Seq is on-premises – vendors love to provide cloud services, because recurring revenue and customer data retention make for a nice stable business model. This works well for many things, but when it comes to log data developers and the companies they work for value choice, and the right choice is often to store data on-premises or in fully-owned data centres. We feel so strongly about this that we’ve adopted it as a tag-line: “Visibility, your way.”
  • Seq is quick to set up – the foundations of good instrumentation are laid when the very first line of code in an app is written. At that point in the development cycle, YAGNI reigns supreme, so Seq comes with an MSI installer, a client on NuGet, and fits in to development with no more overhead than writing to traditional log files. 0-to-go in literally 5 minutes, and we’ll stay that way.
  • Seq is .NET – one of the great things about the diversity of software available these days is that there’s usually a solution that works well with your chosen tools. If you use .NET, Seq will be transparent, friendly and unsurprising for you.

These are going to be our guiding principles as Seq evolves, but we’re not limited by them. Seq already supports NLog and log4net as clients, despite neither of them having the deep structured logging support provided by Serilog. Similarly, we want to keep setup and maintenance of Seq simple, but an elastic storage/archival subsystem is definitely on the cards for a future release.

Who are “we”?

Continuous IT is a “micro ISV” based in Brisbane, Australia. Our team of two comprises me, covering product/technology, while Suzi (formerly an animation producer, and in all things manager extraordinaire) covers business development and keeps the wheels turning.

We’re in no small part influenced by the “sustainable start-up” model epitomised for me by Octopus Deploy where I spend most days. (Octopus’s founder Paul is a source of inspiration without which Seq may never have seen the light of day – thanks, Paul!) Our focus is on building a great product that we support wholeheartedly, rather than clocking up numbers the way many start-ups seem prone to doing.

Want to know more?

You can’t have a 1.0 without a Twitter stream, and as of last week we have this one. Head on over and follow us to stay in the loop! If you visit the home page you can find a few more contact options, including an email newsletter that we’ll send out as new features land.

We’ve been busy – the “Release Seq 1.1” ticket has been and gone, and a preview of Seq 1.2 is already on the site; there are some strong usability improvements in there – make sure you check it out!