Serilog is a good logging framework and it is built with the structured log data in mind. It is a kind of serializer. Serilog determines the right representation when the properties are specified in log events. To use Serilog logging feature with ASP.NET core 2.0, we need to add the dependency of "Serilog.AspNetCore". Serilog provides a variety of
sinks such as a file, MSSQL, Log4net, PostgreSQL, etc.
In this article, I will explain about Serilog File sink and MS SQL sink with Asp.net core 2.0. After adding a respective package of Serilog, we need to add UseSerilog() to the web host builder in BuildWebHost().
- public static IWebHost BuildWebHost(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
- .UseStartup<Startup>()
- .UseSerilog()
- .Build();
Using Serilog File Sink
To write log data into the file, we need to use "Serilog.Sinks.File" dependency. It writes Serilog event to one or more file based on configurations. We can add these sinks by using either NuGet package manager or .NET CLI
Using Package Manager,
- PM> Install-Package Serilog.Sinks.File
Using .NET CLI,
- > dotnet add package Serilog.Sinks.File
To configure the sink in c# code, we need to call WriteTo.File method during logger configuration. The logger configuration needs to write in a program.Main
- Log.Logger = new LoggerConfiguration()
- .MinimumLevel.Information()
- .MinimumLevel.Override("SerilogDemo", LogEventLevel.Information)
- .WriteTo.File("Logs/Example.txt")
- .CreateLogger();
By default, log file size lime is 1GB but it can be increased or removed using the fileSizeLimitBytes parameter of WriteTo.File method.
- .WriteTo.File("Logs/Example.txt", fileSizeLimitBytes: null)
We can also create log file by year, month, day, hour, or minute by specify rollingInterval parameter to WriteTo.File method. In the following example, I have defined rollingInterval to RollingInterval.Day so it will create a new log file every day.
- .WriteTo.File("Logs/Example.txt", rollingInterval: RollingInterval.Day)
Serilog retained the most recent 31 files by default for some reason. We can change or remove this limit using retainedFileCountLimit parameter. In the following example, I have assigned this parameter to null, so it removes the limitation of 31 log files.
- .WriteTo.File("Logs/Example.txt", rollingInterval: RollingInterval.Day, retainedFileCountLimit: null)
Controlling Text file formatting
The File sink creates events in specific fix format by default. Following is the fixed format.
The file format uses outputTemplate parameter to WriteTo.File method. Following is the default format of output template.
- .WriteTo.File("Logs/Example.txt",
- outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
Example
I have made small changes in timestamp formatting to "dd-MMM-yyyy HH:mm: ss.fff zzz", it will show date time format accordingly in the log file
Shared log files
Only one process may be written to the log file at a time by default. Serilog sinks enable us to multi-process shared log files by setting shared parameter of WriteTo.File to true.
- .WriteTo.File("Logs/Example.txt", shared: true)
We can also do the same configuration using JSON configuration. To use JSON configuration, we need to add/install package "Serilog.Settings.Configuration".
Instead of configuring the logger in code, we can read from JSON configuration file by calling ReadFrom.Configuration() method.
In our application, we can do configuration in appsettings.json file. Here, we need to specify the file sink assembly and required path format under the "Serilog" node.
The parameters which can be set through the Serilog-WriteTo-File keys are the method parameters accepted by the WriteTo.File() configuration method. In the following example, I have created appSetting.json file that contains Serilog file sink configuration. In file configuration, the text file is created under logs folder with customized output template.
appsettings.json
- {
- "Serilog": {
- "Using": [ "Serilog.Sinks.File" ],
- "MinimumLevel": "Information",
- "WriteTo": [
- {
- "Name": "File",
- "Args": {
- "path": "Logs\\Example.txt",
- "rollingInterval": "Day",
- "outputTemplate": "{Timestamp:dd-MMM-yyyy HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
- }
- }
- ]
- }
- }
Before creating logger, we need to add this configuration file to ConfigurationBuilder object and The ConfigurationBuilder object is need to pass to ReadFrom.Configuration method of LoggerConfiguration.
- var configuration = new ConfigurationBuilder()
- .AddJsonFile("appsettings.json")
- .Build();
-
- Log.Logger = new LoggerConfiguration()
- .ReadFrom.Configuration(configuration)
- .CreateLogger();
Using Serilog MSSQL Sink
Serilog provides sink that writes events to the MS SQL Server. Currently, NoSQL is very famous due to providing more flexibility to store the different kinds of properties but sometimes it is easier to use existing MS SQL Server to log the events. The sink "Serilog.Sinks.MSSQLServer" will write the events data to SQL table. This sink will work with .NET framework 4.5 and .NET Standard 2.0. We can add these sinks by using either NuGet package manager or .NET CLI using Package Manager.
- PM> Install-Package Serilog.Sinks.MSSqlServer
Using .NET CLI:
- > dotnet add package Serilog.Sinks.MSSqlServer
To configure this sink in C# code, we need to call WriteTo.MSSQLServer method during logger configuration. The logger configuration needs to be written in a program.Main method. There are two minimum configuration requirements:
- var connectionString = @"Data Source=(local); Initial Catalog=Test;User ID=sa;Password=Passwd@12;";
- var tableName = "Logs";
-
- var columnOption = new ColumnOptions();
- columnOption.Store.Remove(StandardColumn.MessageTemplate);
-
- Log.Logger = new LoggerConfiguration()
- .MinimumLevel.Information()
- .MinimumLevel.Override("SerilogDemo", LogEventLevel.Information)
- .WriteTo.MSSqlServer(connectionString, tableName, columnOptions: columnOption)
- .CreateLogger();
Following is table definition:
- CREATE TABLE [dbo].[Logs](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [Message] [nvarchar](max) NULL,
- [MessageTemplate] [nvarchar](max) NULL,
- [Level] [nvarchar](128) NULL,
- [TimeStamp] [datetimeoffset](7) NOT NULL,
- [Exception] [nvarchar](max) NULL,
- [Properties] [xml] NULL,
- [LogEvent] [nvarchar](max) 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] TEXTIMAGE_ON [PRIMARY]
Following are the columns that can be used by this sink. We can modify the column name of database table using columnOptions.
- StandardColumn.Message
- StandardColumn.MessageTemplate
- StandardColumn.Level
- StandardColumn.TimeStamp
- StandardColumn.Exception
- StandardColumn.Properties
By default all the columns are inserted when this sink performs log operation. We can change this list by adding or removing the columns using columnOptions.
-
- columnOptions.Store.Remove(StandardColumn.Properties);
-
-
- columnOptions.Store.Add(StandardColumn.Exception);
We can also add our own log event properties in logs table.They can be added by using AdditionalDataColumns property of columnOption. For example, I have added "OtherData" property to the logs table and also added to AdditionalDataColumns property.
By using following SQL query, we can add a column to logs table.
- Alter table logs add OtherData Varchar(50);
By using the following code, we can added column to AdditionalDataColumns property.
- columnOption.AdditionalDataColumns = new Collection<DataColumn>
- {
- new DataColumn {DataType = typeof (string), ColumnName = "OtherData"},
- };
-
-
- Log.Logger = new LoggerConfiguration()
- .MinimumLevel.Information()
- .MinimumLevel.Override("SerilogDemo", LogEventLevel.Information)
- .WriteTo.MSSqlServer(connectionString, tableName,
- columnOptions: columnOption
-
- )
- .CreateLogger();
The log event property OtherData will be added to the corresponding column upon logging. The property name must match a column name in logs table.
The value of an additional property can be set by using ForContext property of ILogger class. Following the example, I have to assign OtherData property to "Test Data".
- using Microsoft.AspNetCore.Mvc;
- using Serilog;
-
- namespace SerilogDemo.Controllers
- {
- public class HomeController : Controller
- {
- public IActionResult Index()
- {
- Log.Logger.ForContext("OtherData", "Test Data").Information("Index method called!!!");
- return View();
- }
- }
- }
We can do the same configuration using JSON file. In the following example, I have passed connection string and table name to appsetting.json file under "Serilog" node.
appSettings.json
- {
- "Serilog": {
- "Using": [ "Serilog.Sinks.MSSqlServer" ],
- "MinimumLevel": "Information",
- "WriteTo": [
- {
- "Name": "MSSqlServer",
- "Args": {
- "connectionString": "Data Source=(local); Initial Catalog=Test;User ID=sa;Password=Passwd@12;",
- "tableName": "logs"
- }
- }
- ]
- }
- }
Using LoggerConfiguration.ReadFrom.Configuration method, we can read our configuration file and our logger is working according to our configuration.
- var configuration = new ConfigurationBuilder()
- .AddJsonFile("appsettings.json")
- .Build();
-
- Log.Logger = new LoggerConfiguration()
- .ReadFrom.Configuration(configuration)
- .CreateLogger();
Summary
Serilog is a logging framework that has many built-in sinks available for structured log data. In this article, I have explained about Serilog File sink and MS SQL sink with ASP.NET Core 2.0.
You can view or download the source code from the following GitHub link:
Serilog file Sink And
Serilog MS SQL sink.