![]() |
VOOZH | about |
dotnet add package LayeredCraft.StructuredLogging --version 1.2.1
NuGet\Install-Package LayeredCraft.StructuredLogging -Version 1.2.1
<PackageReference Include="LayeredCraft.StructuredLogging" Version="1.2.1" />
<PackageVersion Include="LayeredCraft.StructuredLogging" Version="1.2.1" />Directory.Packages.props
<PackageReference Include="LayeredCraft.StructuredLogging" />Project file
paket add LayeredCraft.StructuredLogging --version 1.2.1
#r "nuget: LayeredCraft.StructuredLogging, 1.2.1"
#:package LayeredCraft.StructuredLogging@1.2.1
#addin nuget:?package=LayeredCraft.StructuredLogging&version=1.2.1Install as a Cake Addin
#tool nuget:?package=LayeredCraft.StructuredLogging&version=1.2.1Install as a Cake Tool
๐ Build Status
๐ NuGet
๐ Downloads
Simplified, structured logging for modern .NET apps โ overloads, conditionals, and performance built-in.
TestLogger with assertions and search helpersdotnet add package LayeredCraft.StructuredLogging
using LayeredCraft.StructuredLogging;
using Microsoft.Extensions.Logging;
// Basic logging
logger.Information("User logged in successfully");
logger.Warning("Rate limit exceeded for user {UserId}", userId);
logger.Error(exception, "Failed to process order {OrderId}", orderId);
// Structured logging with multiple parameters
logger.Information("Order processed for user {UserId} with total {Total:C}",
userId, orderTotal);
// Performance monitoring
using (logger.TimeOperation("Database operation"))
{
// Your database code here
} // Automatically logs execution time
// Enriched logging with context
logger.LogWithContext(LogLevel.Information, "Starting order processing", "UserId", userId);
logger.InformationWithUserId(userId, "Order processing started");
All standard log levels are supported with convenient extension methods:
// Debug logging
logger.Debug("Debug information");
logger.Debug("Processing item {ItemId}", itemId);
// Verbose/Trace logging
logger.Verbose("Detailed trace information");
logger.Verbose("Entering method {MethodName}", methodName);
// Information logging
logger.Information("Operation completed successfully");
logger.Information("User {UserId} performed action {Action}", userId, action);
// Warning logging
logger.Warning("Performance threshold exceeded");
logger.Warning("Retry attempt {AttemptNumber} for operation {OperationId}",
attemptNumber, operationId);
// Error logging
logger.Error("Operation failed");
logger.Error(exception, "Failed to save entity {EntityId}", entityId);
// Critical logging
logger.Critical("System is in critical state");
logger.Critical(exception, "Database connection lost");
Create logging scopes for better context tracking:
// Simple scopes
using (logger.BeginScope("UserRegistration"))
{
logger.Information("Starting user registration");
// Registration logic
}
// Structured scopes with properties
using (logger.BeginScope("OrderId", orderId))
{
logger.Information("Processing order");
// Order processing logic
}
// Complex scopes with multiple properties
using (logger.BeginScopeWith(new { UserId = userId, SessionId = sessionId }))
{
logger.Information("User session started");
// Session logic
}
// Caller-aware scopes (adds MemberName/FilePath/LineNumber)
using (logger.BeginCallerScope())
{
logger.Debug("Tracing caller details");
}
// Timed scopes for performance monitoring
using (logger.TimeOperation("DatabaseQuery"))
{
// Database operation
} // Automatically logs execution time
Add contextual information to log entries:
// Context-specific logging methods
logger.LogWithUserId(LogLevel.Information, userId, "User operation completed");
logger.LogWithRequestId(LogLevel.Information, requestId, "Request processed");
logger.LogWithCorrelationId(LogLevel.Information, correlationId, "Service call completed");
// Convenience methods for common log levels
logger.InformationWithUserId(userId, "User profile updated");
logger.WarningWithRequestId(requestId, "Request took longer than expected");
logger.ErrorWithCorrelationId(correlationId, "Service call failed", exception);
// Custom context enrichment
logger.LogWithContext(LogLevel.Information, "Operation completed", "Duration", duration);
logger.LogWithContext(LogLevel.Warning, "Rate limit approaching", "UserId", userId);
// Automatic caller information
logger.LogWithCaller(LogLevel.Debug, "Method execution completed");
logger.InformationWithCaller("Operation finished successfully");
Built-in performance tracking capabilities:
// Timed operations
using (logger.TimeOperation("DatabaseQuery"))
{
// Your database code
} // Logs: "DatabaseQuery completed in 150ms"
// Synchronous timed operations
var result = logger.Time("CalculateSum", () =>
{
return numbers.Sum();
});
// Asynchronous timed operations
await logger.TimeAsync("FetchUserData", async () =>
{
await userService.GetUserAsync(userId);
});
// Method-level timing with caller info
using (logger.TimeMethod())
{
// Current method is automatically timed
}
TestLogger implements ILogger and captures entries in memory so you can assert against what was written. Extension methods help you inspect entries, check for the presence of messages, and perform simple assertions that throw InvalidOperationException when they fail.
[Fact]
public void Should_Log_User_Registration()
{
// Arrange
var testLogger = new TestLogger();
var userService = new UserService(testLogger);
// Act
userService.RegisterUser("john@example.com");
// Assert
testLogger.AssertLogCount(1);
testLogger.AssertLogEntry(LogLevel.Information, "User registered");
var entry = testLogger.GetLastLogEntry();
entry!.FormattedMessage.Should().Contain("john@example.com");
}
[Fact]
public void Should_Handle_Registration_Errors()
{
// Arrange
var testLogger = new TestLogger();
var userService = new UserService(testLogger);
// Act & Assert
Assert.Throws<ValidationException>(() =>
userService.RegisterUser("invalid-email"));
testLogger.AssertLogEntry(LogLevel.Error, "Invalid email format");
testLogger.HasLogEntryWithException<ValidationException>().Should().BeTrue();
}
// Get specific log entries
var lastEntry = testLogger.GetLastLogEntry();
var secondEntry = testLogger.GetLogEntry(1);
var errorEntries = testLogger.GetLogEntries(LogLevel.Error);
var entriesWithException = testLogger.GetLogEntriesWithException<ArgumentException>();
// Search log entries
var userEntries = testLogger.GetLogEntriesContaining("user");
var hasError = testLogger.HasLogEntry(LogLevel.Error, "failed");
var hasArgumentError = testLogger.HasLogEntryWithException<ArgumentException>(LogLevel.Error);
// Assertions
testLogger.AssertLogEntry(LogLevel.Warning, "threshold");
testLogger.AssertLogEntryAt(0, LogLevel.Information, "started");
testLogger.AssertLogCount(5);
testLogger.AssertLogCount(LogLevel.Error, 1);
testLogger.AssertNoLogEntries();
// Clear logs between tests
testLogger.Clear();
// Optional: only record entries at or above this level (defaults to Trace)
testLogger.MinimumLogLevel = LogLevel.Information;
All logging methods include built-in level checks for optimal performance:
// These methods automatically check if the level is enabled
logger.Debug("Expensive debug info: {Data}", ExpensiveOperation());
// ExpensiveOperation() only called if Debug level is enabled
Robust exception logging with context:
try
{
// Risky operation
}
catch (Exception ex)
{
logger.Error(ex, "Operation failed for user {UserId} in context {Context}",
userId, operationContext);
throw;
}
// Program.cs / Startup.cs
services.AddLogging(builder =>
{
builder.AddConsole();
builder.AddSerilog(); // or any other provider
});
// In your services
public class OrderService
{
private readonly ILogger<OrderService> _logger;
public OrderService(ILogger<OrderService> logger)
{
_logger = logger;
}
public async Task ProcessOrderAsync(int orderId)
{
using (_logger.TimeOperation("OrderProcessing"))
{
_logger.Information("Starting order processing for {OrderId}", orderId);
try
{
// Processing logic
_logger.Information("Order {OrderId} processed successfully", orderId);
}
catch (Exception ex)
{
_logger.Error(ex, "Failed to process order {OrderId}", orderId);
throw;
}
}
}
}
The library works with any ILogger implementation and follows standard .NET logging configuration:
// appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"System": "Warning"
}
}
}
We welcome contributions! Please see our for details.
This project is licensed under the MIT License - see the file for details.
See for a detailed history of changes.
Built with โค๏ธ by LayeredCraft
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. net11.0 net11.0 is compatible. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 is compatible. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 5 NuGet packages that depend on LayeredCraft.StructuredLogging:
| Package | Downloads |
|---|---|
|
AWSSecretsManager.Provider
An AWS Secrets Manager-backed configuration provider for .NET applications using Microsoft.Extensions.Configuration. |
|
|
AlexaVoxCraft.MediatR
MediatR support for Alexa skill development, enabling clean request routing and handler composition. |
|
|
AlexaVoxCraft.Lambda
Core Lambda abstractions and serialization for Alexa skills including handler interfaces and JSON serialization with structured logging support. |
|
|
AlexaVoxCraft.Logging
Provides Alexa-specific logging components including an AWS CloudWatch-compatible JSON formatter. Built on LayeredCraft.StructuredLogging. |
|
|
AlexaVoxCraft.Http
Shared HTTP infrastructure for AlexaVoxCraft, including access token providers and authentication handlers for typed HttpClient integrations. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.2.1 | 7,856 | 5/14/2026 |
| 1.2.1-preview.8 | 58 | 5/14/2026 |
| 1.2.1-preview.7 | 60 | 4/18/2026 |
| 1.2.1-preview.6 | 60 | 4/18/2026 |
| 1.2.0 | 6,442 | 4/17/2026 |
| 1.2.0-preview.5 | 74 | 4/18/2026 |
| 1.2.0-preview.3 | 63 | 4/17/2026 |
| 1.1.8.20 | 431 | 4/16/2026 |
| 1.1.7.19 | 124 | 4/16/2026 |
| 1.1.7.18 | 49,380 | 2/11/2026 |
| 1.1.6.17 | 1,755 | 2/9/2026 |
| 1.1.5.15 | 46,119 | 12/10/2025 |
| 1.1.4.12 | 561 | 12/9/2025 |
| 1.1.3.11 | 47,149 | 11/11/2025 |
| 1.1.2.10 | 33,509 | 10/17/2025 |
| 1.1.1.8 | 86,125 | 8/21/2025 |
| 1.1.0.7 | 40,050 | 7/10/2025 |
| 1.0.0.6 | 528 | 6/26/2025 |
| 0.0.1 | 65 | 4/17/2026 |
| 0.0.1-preview.2 | 64 | 4/17/2026 |
Initial release of LayeredCraft.StructuredLogging with comprehensive logging extensions, scope management, enrichment capabilities, performance monitoring, and testing framework support.