Skip to content

Navigation Menu

Sign in
Sign up

Repository files navigation

StructLog

NuGet Publish to NuGet License: MIT GitHub Sponsors Changelog

A modern structured logging library for .NET with support for custom enrichers, JSON output, and full Dependency Injection integration.

Why StructLog? Standard ILogger<T> lets you log anything, but doesn't enforce a consistent structure. StructLog requires every log entry to carry an EventCode β€” a short, queryable identifier that makes filtering and alerting in production trivial.


✨ Features

  • πŸ”§ Structured JSON output β€” every log entry is a consistent, queryable JSON object
  • 🏷️ EventCode β€” mandatory code + description on every entry, great for monitoring and alerting
  • ⚑ Custom Enrichers β€” inject contextual data (machine name, request ID, tenant, ...) via ILogEnricher
  • 🌐 DI-ready β€” works with ILogger<T> and IOptions<StructLogOptions> out of the box
  • πŸ“ Configurable via appsettings.json
  • πŸ–₯️ Multi-host β€” Console, Worker Service, and ASP.NET Core apps

πŸ“‹ Requirements

Requirement Minimum version
.NET 9.0+

πŸš€ Installation

dotnet add package StructLog

🎯 Quick Start

1. Configure appsettings.json

{
 "StructLog": {
 "EnableEnrichers": true
 }
}

2. Register services

// With appsettings.json
builder.Services.AddStructLog(builder.Configuration);
 
// Without appsettings (uses defaults)
builder.Services.AddStructLog();

3. Inject and use

[ApiController]
public class UsersController : ControllerBase
{
 private readonly IStructLog<UsersController> _logger;
 
 public UsersController(IStructLog<UsersController> logger)
 {
 _logger = logger;
 }
 
 [HttpGet("{id}")]
 public async Task<IActionResult> GetUser(int id)
 {
 var user = await GetUserFromDb(id);
 
 if (user is null)
 {
 _logger.Warning(
 "User not found",
 new EventCode("USR_001", "Get user"),
 new { UserId = id });
 
 return NotFound();
 }
 
 _logger.Info(
 "User retrieved successfully",
 new EventCode("USR_002", "Get user"),
 user);
 
 return Ok(user);
 }
}

4. Example log output

{
 "EventCode": "USR_002",
 "EventDescription": "Get user",
 "Message": "User retrieved successfully",
 "Context": {
 "MachineName": "server-01"
 },
 "Data": {
 "Id": 1,
 "Name": "Simone",
 "Surname": "Rossi",
 "Birthday": "1993εΉ΄05月12ζ—₯T00:00:00"
 }
}

πŸ“š API Reference

Log levels

All methods accept an IEventCode and an optional data object.

_logger.Trace("Entering method", eventCode);
_logger.Debug("Cache miss", eventCode, new { Key = "users:1" });
_logger.Info("User created", eventCode, user);
_logger.Warning("Retry attempt", eventCode, new { Attempt = 3 });
_logger.Error("Payment failed", eventCode, exception, new { OrderId = 42 });
_logger.Critical("DB unreachable", eventCode, exception);

Logging scope

Use BeginScope to attach contextual data to all logs within a block:

using (_logger.BeginScope(new Dictionary<string, object>
{
 ["RequestId"] = HttpContext.TraceIdentifier,
 ["UserId"] = currentUserId
}))
{
 _logger.Info("Processing request", new EventCode("REQ_001", "Request"));
}

πŸ”‘ EventCode

EventCode is the core of StructLog. Every log entry must carry one, which makes your logs immediately searchable and alertable in tools like Kibana, Grafana, or Azure Monitor.

// Simple inline usage
var code = new EventCode("PAY_003", "Payment processing");
 
// Recommended: define codes as constants in a dedicated class
public static class LogEvents
{
 public static readonly EventCode UserCreated = new("USR_001", "User lifecycle");
 public static readonly EventCode UserDeleted = new("USR_002", "User lifecycle");
 public static readonly EventCode PaymentFailed = new("PAY_001", "Payment processing");
}
 
// Usage
_logger.Error("Payment declined", LogEvents.PaymentFailed, exception, new { OrderId = 99 });

🌐 Custom Enrichers

Enrichers automatically attach contextual data to every log entry. Implement ILogEnricher and register it with DI:

// 1. Implement the interface
public class MachineNameEnricher : ILogEnricher
{
 public void Enrich(IDictionary<string, object> context)
 {
 context["MachineName"] = Environment.MachineName;
 }
}
 
// 2. Register β€” all ILogEnricher implementations are picked up automatically
builder.Services.AddSingleton<ILogEnricher, MachineNameEnricher>();
 
// 3. Enable in appsettings.json
// "StructLog": { "EnableEnrichers": true }

You can register as many enrichers as you need. Common use cases: machine name, environment, request ID, tenant ID, application version.


βš™οΈ Configuration options

Option Type Default Description
EnableEnrichers bool true Whether enrichers are invoked for each log entry

🧩 Part of the ASP.NET Core Kit ecosystem

StructLog is part of a cohesive set of lightweight, DI-ready toolkits for ASP.NET Core:

Package Description
AspNetCoreAuthKit JWT, API Key, Refresh Tokens with rotation & dynamic claim policies
AspNetCoreResponseKit Standardized ApiResponse<T>, global exception handling & smart factories
AspNetCoreHttpKit Typed HTTP client with result pattern & StructLog integration
AspNetCoreCacheKit Group-based caching with per-entry & per-group duration
StructLog Structured logging with EventCode support & custom enrichers

Each package works independently β€” use one or all five.


❀️ Support

If you find StructLog useful, consider sponsoring its development on GitHub Sponsors. Even a small contribution helps keep the project maintained and growing.

Sponsor simoneM93


πŸ“„ License

MIT β€” see LICENSE for details.

About

Lightweight structured logging library for .NET 9+ with enrichers, JSON output and DI-ready design.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /