To log into SQL Server using Serilog and store logs in your custom logs table, follow these steps:
Ensure you have the necessary Serilog packages installed via NuGet:
Install-Package Serilog
Install-Package Serilog.Sinks.MSSqlServer
Install-Package Serilog.Settings.Configuration
Modify appsettings.json
to configure Serilog:
{
"Serilog": {
"Using": ["Serilog.Sinks.MSSqlServer"],
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=YOUR_SERVER;Database=YOUR_DB;User Id=YOUR_USER;Password=YOUR_PASSWORD;",
"tableName": "CustomLogs",
"autoCreateSqlTable": false,
"restrictedToMinimumLevel": "Information",
"columnOptionsSection": {
"message": { "columnName": "Message", "dataType": "nvarchar(max)" },
"level": { "columnName": "LogLevel", "dataType": "nvarchar(50)" },
"timestamp": { "columnName": "LogTime", "dataType": "datetime2" }
}
}
}
]
}
}
Make sure autoCreateSqlTable
is false
if you have a pre-existing custom logs table.
Ensure your database has a table for logging:
CREATE TABLE CustomLogs (
Id INT IDENTITY(1,1) PRIMARY KEY,
LogTime DATETIME2 NOT NULL,
LogLevel NVARCHAR(50) NOT NULL,
Message NVARCHAR(MAX) NOT NULL,
Exception NVARCHAR(MAX) NULL
);
Modify Program.cs
(for .NET 6+):
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Microsoft.Extensions.Configuration;
var builder = WebApplication.CreateBuilder(args);
// Load Serilog from configuration
builder.Host.UseSerilog((context, config) =>
{
config.ReadFrom.Configuration(context.Configuration);
});
var app = builder.Build();
// Use Serilog for logging
app.UseSerilogRequestLogging();
app.MapGet("/", () => "Hello World!");
app.Run();
Use Serilog in your services, controllers, or any other place in your application:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
[ApiController]
[Route("api/logs")]
public class LogsController : ControllerBase
{
private readonly ILogger<LogsController> _logger;
public LogsController(ILogger<LogsController> logger)
{
_logger = logger;
}
[HttpGet("test")]
public IActionResult TestLogging()
{
_logger.LogInformation("This is an info log.");
_logger.LogWarning("This is a warning log.");
_logger.LogError("This is an error log with exception", new Exception("Test exception"));
return Ok("Logs written to SQL Server!");
}
}
Run the application, access the endpoint /api/logs/test
, and check your CustomLogs
table in SQL Server:
SELECT * FROM CustomLogs ORDER BY LogTime DESC;
- Install
Serilog
andSerilog.Sinks.MSSqlServer
- Configure
Serilog
inappsettings.json
- Create a
CustomLogs
table - Initialize Serilog in
Program.cs
- Use
_logger.LogInformation()
,_logger.LogError()
, etc. - Verify logs in the database
Let me know if you need any modifications! 🚀
===============================
To log additional columns (e.g., Request URI, Query Params, Headers, Status Code) into your custom logs table using Serilog, you need to:
- Modify the SQL Table to include these fields.
- Customize Serilog's Column Mappings using
ColumnOptions
. - Enrich Log Context to capture request details.
Update your CustomLogs
table to include the additional columns:
ALTER TABLE CustomLogs ADD
RequestUri NVARCHAR(2000) NULL,
QueryParams NVARCHAR(MAX) NULL,
RequestHeaders NVARCHAR(MAX) NULL,
StatusCode INT NULL;
Modify your appsettings.json
to include these new columns:
{
"Serilog": {
"Using": ["Serilog.Sinks.MSSqlServer"],
"MinimumLevel": "Information",
"Enrich": ["FromLogContext"],
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=YOUR_SERVER;Database=YOUR_DB;User Id=YOUR_USER;Password=YOUR_PASSWORD;",
"tableName": "CustomLogs",
"autoCreateSqlTable": false,
"restrictedToMinimumLevel": "Information",
"columnOptionsSection": {
"message": { "columnName": "Message", "dataType": "nvarchar(max)" },
"level": { "columnName": "LogLevel", "dataType": "nvarchar(50)" },
"timestamp": { "columnName": "LogTime", "dataType": "datetime2" },
"exception": { "columnName": "Exception", "dataType": "nvarchar(max)" },
"additionalColumns": [
{ "ColumnName": "RequestUri", "DataType": "nvarchar", "DataLength": 2000, "AllowNull": true },
{ "ColumnName": "QueryParams", "DataType": "nvarchar", "DataLength": -1, "AllowNull": true },
{ "ColumnName": "RequestHeaders", "DataType": "nvarchar", "DataLength": -1, "AllowNull": true },
{ "ColumnName": "StatusCode", "DataType": "int", "AllowNull": true }
]
}
}
}
]
}
}
To log request details, create a Serilog middleware to enrich logs:
Create a middleware class:
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Serilog.Context;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
public class SerilogRequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<SerilogRequestLoggingMiddleware> _logger;
public SerilogRequestLoggingMiddleware(RequestDelegate next, ILogger<SerilogRequestLoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
// Capture Request Data
var request = context.Request;
var requestUri = $"{request.Scheme}://{request.Host}{request.Path}";
var queryParams = request.QueryString.ToString();
var headers = string.Join("; ", request.Headers.Select(h => $"{h.Key}: {h.Value}"));
// Add request details to Serilog's LogContext
using (LogContext.PushProperty("RequestUri", requestUri))
using (LogContext.PushProperty("QueryParams", queryParams))
using (LogContext.PushProperty("RequestHeaders", headers))
{
await _next(context);
// Capture Response Status Code
var statusCode = context.Response.StatusCode;
LogContext.PushProperty("StatusCode", statusCode);
_logger.LogInformation("Request completed with status code {StatusCode}", statusCode);
}
}
}
Modify Program.cs
to register Serilog and the request logging middleware:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Microsoft.Extensions.Configuration;
var builder = WebApplication.CreateBuilder(args);
// Load Serilog from configuration
builder.Host.UseSerilog((context, config) =>
{
config.ReadFrom.Configuration(context.Configuration);
});
var app = builder.Build();
// Use custom request logging middleware
app.UseMiddleware<SerilogRequestLoggingMiddleware>();
app.UseSerilogRequestLogging(); // Default Serilog request logging
app.MapGet("/", () => "Hello World!");
app.Run();
Now, when logging in a controller, it will automatically include Request URI, Query Params, Headers, and Status Code:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
[ApiController]
[Route("api/logs")]
public class LogsController : ControllerBase
{
private readonly ILogger<LogsController> _logger;
public LogsController(ILogger<LogsController> logger)
{
_logger = logger;
}
[HttpGet("test")]
public IActionResult TestLogging()
{
_logger.LogInformation("Test log entry with HTTP request details.");
return Ok("Logs written to SQL Server!");
}
}
After hitting /api/logs/test
, check the CustomLogs
table:
SELECT * FROM CustomLogs ORDER BY LogTime DESC;
✅ Added custom columns to store RequestUri
, QueryParams
, Headers
, and StatusCode
.
✅ Configured Serilog to map these columns to SQL Server.
✅ Created a Middleware to capture and enrich logs with HTTP request details.
✅ Registered the Middleware in Program.cs
.
✅ Logged requests dynamically without modifying each controller manually.
This setup ensures structured logging with all HTTP request details in SQL Server! 🚀 Let me know if you need any improvements! 🔥
Different log levels:
Docs:
https://blog.postsharp.net/serilog-log-levels
https://code-maze.com/csharp-different-log-levels-in-serilog/
https://mbarkt3sto.hashnode.dev/logging-with-serilog-and-sql-server