Introduction
Logging is an approach to record information about a program's execution for debugging and tracing purposes. Logging usually involves writing text messages to log files or sending data to monitoring applications. The logged information gives you a good understanding about processed data, warnings, errors and more. In practice, logging enables developers and testers to identify software problems, monitor live systems and verify outputs.
In .NET platform, there are multiple matured logging frameworks such as:
They are designed for simplifying developers' work regarding processing logs. All the logging frameworks work basically the same: you include one of the libraries into your programs and add logging statements to your code. If you start your application and logging is enabled, logging information is sent to the configured logging destination like a log file, console or database.
Serilog is an excellent logging framework and has been active for years. Unlike other logging libraries for .NET, Serilog is built with structured log data in mind. This framework is built around the idea that log messages should be more than a collection of string
s. Log messages are preserved as structured data(JSON) that can be written in document form to a variety of output providers.
Structure of serilog
Features
- Simple API and easy to extend
- Structured data to preserve your data’s semantics
- Log to any a variety of targets
Overview
Before we get started, let's have a quick overview at how easy it is to apply Serilog into your project. Please see the below examples:
- Basic logger:
using Serilog;
namespace SerilogTutorial
{
public class HelloSerilog
{
public static void Main(string[] args)
{
var logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
logger.Information("Hello, Serilog!");
}
}
}
This example writes a line like the following to Console.
2015-10-19 15:39:06 [Information] Hello, Serilog!
- Pass parameters to loggers:
var logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
logger.Information("Processed {Number} records in {Time} ms", 500, 120);
It writes a line as follows:
2015-10-19 22:24:09 [Information] Processed 500 records in 120 ms
- Create Template loggers:
var logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
var order = new {Id = 12, Total = 128.50, CustomerId = 72};
var customer = new {Id = 72, Name = "John Smith"};
logger.Information("New orders {OrderId} by {Customer}", order.Id, customer);
It prints logs as follows:
2015-10-19 22:32:43 [Information] New orders 12 by "{ Id = 72, Name = John Smith }"
As we can see, the power of Serilog is it supports process message parameters and structured data. While traditional logging libraries render messages into string
s, Serilog defers rendering and captures the parameters separately from the message template.
Using the Code
Now let's go deep into how to apply Serilog into your projects. Here are the basic steps:
- Preparation
- Install serilog
- Create a logger
- Configure logger
- Add sinks
- Write log messages
- Customize logger
- Define log output template
- Specify minimal level
- Install database sink
Preparation
Of course, you need to have Visual Studio installed and have a project ready. For simplify purpose, you just need to create a console application.
Install serilog
Typically, there are two ways to install nuget packages.
Way 1 - via Nuget Package Manager
Right click your project > Manage nuget packages > search serilog
Way 2 - via Project Manager Console
Goto Menu > Tools > NuGet PackageManager > Project Manager Console
PM> Install-Package Serilog
Create a Logger
Logger is the fundamental of writing logs and it is used to output log messages. To create a logger, you need to specify two settings.
Configure Logger
You need to create a LoggerConfiguration
object
Add Sinks
Sink is a place or destination to process logs. Sink could be console, file or data store. Sink is configured using WriteTo()
method.
Now, you can build a logger to write events to Console
:
var logger = = new LoggerConfiguration()
.WriteTo.ColoredConsole()
.CreateLogger();
Multiple additional sinks can be added through chaining WriteTo
methods:
var logger = new LoggerConfiguration()
.WriteTo.ColoredConsole()
.WriteTo.RollingFile(@"C:\Log-{Date}.txt")
.CreateLogger();
Write Log Messages
Now the logger is ready to use. You can simply write logs as follows:
log.Debug("Debugging message");
log.Information("Information message");
log.Warning("Warning message");
log.Error("Error message");
log.Fatal("Fatal message");
Customize Logger
In order to modify logger to fit your needs, you need to tune the logger.
Define Log Output Template
Log message template controls how the sink renders events. Message templates are a superset of standard .NET format strings and compatible with string.Format()
method. Moreover, it supports JSON objects or regular C# objects(with @
symbol) as parameters.
var position = new { Latitude = 25, Longitude = 134 };
var elapsedMs = 34;
log.Information("Processed {@Position} in {Elapsed} ms.", position, elapsedMs);
It prints logs like the following:
09:14:22 [Information] Processed { Latitude: 25, Longitude: 134 } in 34 ms.
Specify Minimal Level
There are five levels of logs:
Level |
Usage |
Verbose |
Tracing information and debugging minutiae; generally only switched on in unusual situations |
Debug |
Internal control flow and diagnostic state dumps to facilitate pinpointing of recognized problems |
Information |
Events of interest or that have relevance to outside observers; the default enabled minimum logging level |
Warning |
Indicators of possible issues or service/functionality degradation |
Error |
Indicating a failure within the application or connected system |
Fatal |
Critical errors causing complete failure of the application |
Serilog writes the logs with minimal level as well as higher and ignore lower levels. For instance, specify minimal level as Debug will output logs except Verbose.
var logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.ColoredConsole()
.CreateLogger();
You can also override minimal level. For instance, we want to display all logs higher than Debug in the console but save all error logs to databases. In order to meet this requirement, you can specify global level as Debug and set database sink with Warning level.
var logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.ColoredConsole()
.WriteTo.MongoDB("mongo://myserver/logs", minimumLevel: LogEventLevel.Warning)
.CreateLogger();
logger.Information("I am an information log"); log.Error("I am an error log");
Write error-level logs events to File:
var logger = new LoggerConfiguration()
.WriteTo.File("log.txt", LogEventLevel.Error)
.CreateLogger();
logger.Information("I am an information log"); logger.Error("I am an error log");
If no MinimumLevel
is specified, Serilog will use Information level events as default - Information and higher levels will be processed.
Install Database Sink
Serilog supports build-in sinks include Console, File (single/rolling) and TextWriter
. In order to enable serilog export logs to different destinations, additional sinks need to be installed.
A typical case is to write logs to database, you need to install additional sinks. For instance, using SQL Server database as destination needs to install SQL Server sink.
PM> Install-Package Serilog.Sinks.MSSqlServer
Create database LogEvents
and table Logs
using SQL script:
if not exists(select * from sys.databases where name='LogEvents')
create database LogEvents;
Go
Use LogEvents;
Go
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [Logs](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Message] [nvarchar](max) NULL,
[MessageTemplate] [nvarchar](max) NULL,
[Level] [nvarchar](128) NULL,
[TimeStamp] [datetime] NOT NULL,
[Exception] [nvarchar](max) NULL,
[Properties] [xml] NULL,
CONSTRAINT [PK_Logs] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, _
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]
GO
The script will create LogEvents
database and Logs
table:
Write to SQL Server database sink:
var logger = new LoggerConfiguration()
.WriteTo.MSSqlServer(@"Server=.;Database=LogEvents;
Trusted_Connection=True;", "Logs")
.CreateLogger();
logger.Information("I am an information log");
logger.Error("Hello, I am an error log");
You will get:
More
This article only covers essential conceptions of Serilog. More advanced features can be available here. Advance topics include:
- Add dynamic properties through Enrichers
- Add log filters to filter out noisy events and select particular logs
- Add sub loggers to process complex logging requirements
- More sinks such as MongoDB, Seq, RavenDB, Email and Azure DocumentDB. The complete list can be found here.
History
- October 20, 2015: First version posted
- October 20, 2015: Fix format