A high-performance Serilog sink that writes log events to MongoDB. This sink provides efficient batching, flexible configuration, and support for MongoDB-specific features like TTL indexes and capped collections.
- Batched Writes - Efficient batch processing of log events
- Automatic Expiration - TTL index support for automatic log rotation
- Capped Collections - Size and document count limited collections
- Flexible Configuration - Code-based and configuration file support
- Customizable Document Format - Extensible document factory pattern
- High Performance - Asynchronous writes with configurable buffering
Install via NuGet:
dotnet add package Serilog.Sinks.MongoOr using Package Manager Console:
Install-Package Serilog.Sinks.Mongousing Serilog;
Log.Logger = new LoggerConfiguration()
.WriteTo.MongoDB(
connectionString: "mongodb://localhost:27017",
databaseName: "serilog",
collectionName: "logs"
)
.CreateLogger();
Log.Information("Hello, MongoDB!");
Log.CloseAndFlush();Log.Logger = new LoggerConfiguration()
.WriteTo.MongoDB(
connectionString: "mongodb://localhost:27017",
databaseName: "serilog",
collectionName: "logs",
expireAfter: TimeSpan.FromDays(30) // Logs expire after 30 days
)
.CreateLogger();Log.Logger = new LoggerConfiguration()
.WriteTo.MongoDB(
connectionString: "mongodb://localhost:27017",
databaseName: "serilog",
collectionName: "logs",
maxDocuments: 10000, // Maximum 10,000 documents
maxSize: 10485760 // Maximum 10 MB
)
.CreateLogger();Log.Logger = new LoggerConfiguration()
.WriteTo.MongoDB(
connectionString: "mongodb://localhost:27017",
databaseName: "serilog",
collectionName: "logs",
minimumLevel: LogEventLevel.Information,
expireAfter: TimeSpan.FromDays(7),
batchSizeLimit: 100,
bufferingTimeLimit: TimeSpan.FromSeconds(2)
)
.CreateLogger();var mongoUrl = new MongoUrl("mongodb://localhost:27017");
Log.Logger = new LoggerConfiguration()
.WriteTo.MongoDB(
mongoUrl: mongoUrl,
databaseName: "serilog",
collectionName: "logs"
)
.CreateLogger();Log.Logger = new LoggerConfiguration()
.WriteTo.MongoDB(options =>
{
options.ConnectionString = "mongodb://localhost:27017";
options.DatabaseName = "serilog";
options.CollectionName = "logs";
options.MinimumLevel = LogEventLevel.Debug;
options.ExpireAfter = TimeSpan.FromDays(30);
options.BatchSizeLimit = 100;
options.BufferingTimeLimit = TimeSpan.FromSeconds(5);
// Capped collection options
options.CollectionOptions = new CreateCollectionOptions
{
Capped = true,
MaxSize = 5242880, // 5 MB
MaxDocuments = 1000
};
// Custom properties to promote to top-level
options.Properties = new HashSet<string>
{
"SourceContext",
"RequestId",
"UserId"
};
})
.CreateLogger();{
"Serilog": {
"Using": ["Serilog.Sinks.Mongo", "Serilog.Sinks.Console"],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "MongoDB",
"Args": {
"connectionString": "mongodb://localhost:27017",
"databaseName": "serilog",
"collectionName": "logs",
"expireAfter": "30.00:00:00"
}
}
],
"Enrich": ["FromLogContext"]
}
}Then in your code:
using Serilog;
using Microsoft.Extensions.Configuration;
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();| Property | Default | Description |
|---|---|---|
ConnectionString |
- | MongoDB connection string |
MongoUrl |
- | Alternative to ConnectionString |
DatabaseName |
"serilog" |
Database name |
CollectionName |
"logs" |
Collection name |
MinimumLevel |
Verbose |
Minimum log level to write |
ExpireAfter |
- | TTL for automatic document expiration |
BatchSizeLimit |
100 |
Maximum batch size |
BufferingTimeLimit |
00:00:02 |
Maximum time to wait before writing a batch |
CollectionOptions |
- | MongoDB collection creation options |
Properties |
{"SourceContext"} |
Properties to promote to top-level |
DocumentFactory |
- | Custom document factory |
MongoFactory |
- | Custom MongoDB factory |
By default, log events are stored with the following structure:
{
"_id": ObjectId("..."),
"Timestamp": ISODate("2025-11-27T10:30:00.000Z"),
"Level": "Information",
"Message": "User logged in successfully",
"TraceId": "00-abc123...",
"SpanId": "def456...",
"SourceContext": "MyApp.Controllers.AuthController",
"Properties": {
"UserId": "12345",
"Username": "john.doe",
"IPAddress": "192.168.1.1"
},
"Exception": {
"Message": "...",
"Type": "System.Exception",
"Text": "...",
"HResult": -2146233088
}
}Properties can be promoted from the Properties object to the top level of the document:
options.Properties = new HashSet<string>
{
"SourceContext",
"RequestId",
"UserId",
"MachineName"
};This results in:
{
"_id": ObjectId("..."),
"Timestamp": ISODate("2025-11-27T10:30:00.000Z"),
"Level": "Information",
"Message": "Processing request",
"SourceContext": "MyApp.Services.ProcessingService",
"RequestId": "req-789",
"UserId": "12345",
"MachineName": "WEB-SERVER-01",
"Properties": {
// Other properties...
}
}Implement IDocumentFactory to customize the document structure:
public class CustomDocumentFactory : DocumentFactory
{
public override BsonDocument? CreateDocument(LogEvent logEvent, MongoSinkOptions options)
{
var document = base.CreateDocument(logEvent, options);
if (document != null)
{
// Add custom fields
document["Application"] = "MyApp";
document["Environment"] = "Production";
// Custom transformations
if (logEvent.Properties.TryGetValue("RequestPath", out var path))
{
document["Path"] = path.ToString();
}
}
return document;
}
}
// Use the custom factory
Log.Logger = new LoggerConfiguration()
.WriteTo.MongoDB(options =>
{
options.ConnectionString = "mongodb://localhost:27017";
options.DatabaseName = "serilog";
options.CollectionName = "logs";
options.DocumentFactory = new CustomDocumentFactory();
})
.CreateLogger();Log.Logger = new LoggerConfiguration()
.WriteTo.MongoDB(
connectionString: "mongodb://localhost:27017",
databaseName: "serilog",
collectionName: "errors",
minimumLevel: LogEventLevel.Error
)
.WriteTo.MongoDB(
connectionString: "mongodb://localhost:27017",
databaseName: "serilog",
collectionName: "all-logs",
minimumLevel: LogEventLevel.Information,
expireAfter: TimeSpan.FromDays(7)
)
.CreateLogger();using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSerilog(loggerConfiguration =>
{
loggerConfiguration
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.MongoDB(
connectionString: "mongodb://localhost:27017",
databaseName: "serilog",
collectionName: "logs",
expireAfter: TimeSpan.FromDays(30)
);
});
var host = builder.Build();
await host.RunAsync();Adjust batching settings based on your throughput requirements:
options.BatchSizeLimit = 500; // Larger batches for high throughput
options.BufferingTimeLimit = TimeSpan.FromSeconds(10); // Longer wait for batch fillBest for applications that need automatic log cleanup:
.WriteTo.MongoDB(
connectionString: "mongodb://localhost:27017",
databaseName: "serilog",
collectionName: "logs",
expireAfter: TimeSpan.FromDays(30)
)A TTL index is automatically created on the Timestamp field to removes expired documents.
Best for fixed-size log storage:
.WriteTo.MongoDB(
connectionString: "mongodb://localhost:27017",
databaseName: "serilog",
collectionName: "logs",
maxDocuments: 100000, // Keep latest 100k documents
maxSize: 104857600 // Or 100 MB, whichever is hit first
)Oldest documents are automatically removed when limits are reached.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.