RandomSkunk.StructuredLogging
0.9.0
dotnet add package RandomSkunk.StructuredLogging --version 0.9.0
NuGet\Install-Package RandomSkunk.StructuredLogging -Version 0.9.0
<PackageReference Include="RandomSkunk.StructuredLogging" Version="0.9.0" />
<PackageVersion Include="RandomSkunk.StructuredLogging" Version="0.9.0" />
<PackageReference Include="RandomSkunk.StructuredLogging" />
paket add RandomSkunk.StructuredLogging --version 0.9.0
#r "nuget: RandomSkunk.StructuredLogging, 0.9.0"
#:package RandomSkunk.StructuredLogging@0.9.0
#addin nuget:?package=RandomSkunk.StructuredLogging&version=0.9.0
#tool nuget:?package=RandomSkunk.StructuredLogging&version=0.9.0
RandomSkunk.StructuredLogging
Modern, high-performance structured logging extensions for .NET that cleanly separate human-readable messages from machine-readable attributes. Stop cluttering your message templates with structured data and start writing logs that are easier to read and query.
Why Choose RandomSkunk.StructuredLogging?
Traditional structured logging forces you to embed data into message templates. This often leads to:
- Verbose and Unreadable Messages:
Log("User {UserId} logged in from {IPAddress}", userId, ipAddress) - Performance Overhead: Message template caching can consume memory and CPU.
- Rigid Structure: You can only log what your template allows.
This library takes a different approach by treating messages and attributes as separate concerns, giving you the best of both worlds: clean, readable messages and rich, queryable data.
Features
- ✨ Clean Separation: Keep your log messages for humans and your attributes for machines.
- 🚀 High Performance: A design that avoids message template caching overhead.
- 📝 Powerful Interpolated Strings: Automatically extract attributes from interpolated strings (
$"User {user.Name:<UserName>}") without sacrificing performance. The interpolation only happens if the log level is enabled! - 💪 Flexible & Type-Safe: Pass attributes using tuples, dictionaries, or arrays with a rich set of overloads.
- 🎯 Multi-Targeted: Targets both .NET 8 and .NET 9.
Quick Start
1. Install the Package
dotnet add package RandomSkunk.StructuredLogging
2. Start Logging
Use the extension methods on Microsoft.Extensions.Logging.ILogger.
Basic Logging with Attributes
Pass attributes as a list of (string, object) tuples. The message remains clean and readable.
logger.Information("User logged in successfully",
("UserId", user.Id),
("SessionId", sessionId),
("LoginTime", DateTime.UtcNow));
Output Log (conceptual JSON):
{
"Message": "User logged in successfully",
"UserId": 123,
"SessionId": "xyz-abc",
"LoginTime": "2024-01-01T12:00:00Z"
}
Attribute Extraction from Interpolated Strings
For ultimate convenience, extract attributes directly from an interpolated string. The syntax {value:<AttributeName>} captures the value as an attribute and embeds it in the message.
This is not just a simple string.Format. The library uses a custom interpolated string handler that only evaluates the arguments and formats the string if the log level is enabled.
// The values for username and attemptCount are captured as attributes.
logger.Warning($"Failed login attempt for {username:<Username>}",
("AttemptCount", attemptCount),
("IPAddress", clientIp));
Output Log (conceptual JSON):
{
"Message": "Failed login attempt for brian",
"Username": "brian",
"AttemptCount": 3,
"IPAddress": "127.0.0.1"
}
Performance: Fast and Memory-Efficient
Performance is a core feature. This library is designed to minimize overhead in your application.
Conditional Evaluation
The custom interpolated string handlers are the magic behind the performance. String formatting and method calls inside an interpolated string only occur if the log level is enabled.
// If Debug logging is disabled, CalculateSize() is never called and no string is created.
logger.Debug($"Processing {items.Count:<ItemsCount>} items with total size {CalculateSize(items):<ItemsByteCount>N0} bytes");
No Message Caching
Unlike other libraries, we do not cache message templates. This eliminates memory overhead and performance penalties associated with managing a cache, making it ideal for dynamic log messages.
Advanced Usage
The library is flexible enough to handle any scenario.
Logging with Exceptions and Event IDs
All overloads support standard EventId and Exception arguments.
logger.Error(new EventId(500, "DatabaseError"), exception, "Database connection failed",
("ConnectionString", connectionString),
("RetryCount", retryCount));
Using Dictionaries for Attributes
You can pass attributes in any IReadOnlyCollection<KeyValuePair<string, object?>>, including a Dictionary.
var metadata = new Dictionary<string, object?>
{
["UserId"] = user.Id,
["TenantId"] = tenant.Id,
["CorrelationId"] = correlationId
};
logger.Information("Operation completed", metadata);
How It Works
The library extends ILogger with a new set of extension methods. These methods use custom interpolated string handlers to intercept string formatting.
- The handler checks if the requested
LogLevelis enabled. - If not, it does nothing, and the call is nearly free.
- If enabled, it processes the interpolated string, extracting any attributes defined with the
<Key>syntax. - It then combines all attributes and passes them, along with the formatted message, to the underlying
ILoggerinstance. - The library uses an optimized array-based approach for passing attributes.
Compatibility
- .NET 8.0 and later
- .NET 9.0
- Compatible with all
Microsoft.Extensions.Loggingproviders (Serilog, Console, etc.)
License
This project is licensed under the MIT License.
Copyright (c) 2025-2026 Brian Friesen. All rights reserved.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.3)
-
net8.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.3)
-
net9.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.9.0 | 70 | 2/11/2026 |