AnnotationLogger 1.0.0

dotnet add package AnnotationLogger --version 1.0.0
                    
NuGet\Install-Package AnnotationLogger -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AnnotationLogger" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AnnotationLogger" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="AnnotationLogger" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add AnnotationLogger --version 1.0.0
                    
#r "nuget: AnnotationLogger, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package AnnotationLogger@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=AnnotationLogger&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=AnnotationLogger&version=1.0.0
                    
Install as a Cake Tool

AnnotationLogger

A high-performance, attributes-based .NET logging framework that brings clean code and aspect-oriented programming principles to your application logging.

License: MIT

Table of Contents

Overview

AnnotationLogger is a comprehensive logging framework for .NET applications that provides attribute-based method logging, performance tracking, data change monitoring, and more. The framework is designed to be both simple to use and highly configurable, supporting a variety of logging destinations and formats.

Key Features

  • Attributes-Based Logging: Simply annotate methods with [LogDebug], [LogInfo], [LogWarning], etc.
  • Expression-Based Method Interception: Uses expression trees for powerful method introspection
  • Automatic Parameter Logging: Captures method parameters automatically
  • Return Value Logging: Records method outputs for complete invocation tracking
  • Exception Tracking: Automatically captures and logs exceptions with stack traces
  • Execution Time Measurement: Built-in performance tracking via Stopwatch integration
  • Async Support: Full support for async/await methods via Task-based interfaces
  • Extensible Output: Console, file, database, and composite loggers with structured output options
  • Environment-Aware: Configure different logging behaviors for development vs. production
  • Distributed Tracing: Built-in correlation ID management for trace context propagation
  • Thread-Safe: Implements proper synchronization for multi-threaded environments
  • Data Change Tracking: Track changes to objects across method calls
  • Progress Monitoring: Log progress for long-running operations
  • Log Throttling: Control log volume in high-frequency methods
  • Advanced Routing: Direct logs to different destinations based on content

Why AnnotationLogger?

Feature AnnotationLogger Serilog NLog log4net
Aspect-Oriented Logging
Clean Business Logic
Automatic Parameter Capture
Fluent Configuration
Structured Logging
Performance Tracking
Data Change Tracking
Progress Logging
Performance High High Medium Medium
Learning Curve Medium Low Medium High

Benefits Over Traditional Loggers

1. Separation of Concerns

Unlike traditional logging frameworks that require you to inject logging code throughout your business logic, AnnotationLogger cleanly separates your application code from your logging concerns. This leads to more maintainable, readable code.

2. Reduced Boilerplate

Traditional logging approaches may require 5-10 lines of code per method for proper entry/exit logging. With AnnotationLogger, it's just one line - the attribute declaration:

[LogInfo]
public Customer GetCustomerById(int customerId)
{
    // Your business logic here, no logging code!
    return _repository.FindById(customerId);
}

3. Consistent Logging Standard

AnnotationLogger ensures all methods are logged consistently following the same pattern and level of detail. This prevents developer-by-developer inconsistencies that plague many codebases.

4. Better for AOP

True aspect-oriented programming for logging, separating cross-cutting concerns from your business logic in a clean, maintainable way.

5. Automatic Parameter Handling

Parameter values are automatically captured and formatted intelligently based on their type, with special handling for collections, dictionaries, and complex objects.

Getting Started

Installation

Add AnnotationLogger to your project using your preferred method:

dotnet add package AnnotationLogger

Basic Setup

Set up AnnotationLogger in your application startup code:

using AnnotationLogger;

// Configure logger in Program.cs or Startup.cs
LogManager.Configure(config => 
{
    config.Logger = new ConsoleLogger();
    config.Environment = EnvironmentType.Development;
});

// Optional: Configure data change tracking
LogManager.ConfigureDataLogging(config => 
{
    config.EnableDataChangeTracking = true;
    config.MaxComparisonDepth = 3;
});

First Log

Create a class with logged methods and then call them using LoggedMethodCaller:

// Define a class with logging attributes
public class UserService
{
    [LogInfo]
    public User GetUser(int userId)
    {
        // Business logic here
        return new User { Id = userId, Name = "John" };
    }
}

// Use LoggedMethodCaller to invoke the method with logging
var userService = new UserService();
User user = LoggedMethodCaller.Call(() => userService.GetUser(123));

Core Components

LogManager

The central static class that manages all logging configurations and operations.

// Configure general logging
LogManager.Configure(config => 
{
    config.Logger = new ConsoleLogger();
    config.Environment = EnvironmentType.Development;
});

// Direct logging methods
LogManager.Info("Application started");
LogManager.Warning("Unusual condition detected");
LogManager.Error("Operation failed", new Dictionary<string, object> { 
    { "ErrorCode", 500 }, 
    { "Details", "Connection timeout" } 
});

// Add context information
LogManager.AddContext("TraceId", Guid.NewGuid().ToString());
LogManager.AddContext("SessionId", sessionId);

LoggedMethodCaller

The main API for automatic method interception and logging.

// For methods that return a value
int result = LoggedMethodCaller.Call(() => calculator.Add(5, 3));

// For methods that don't return a value
LoggedMethodCaller.Call(() => dataService.ProcessRecord(record));

// For async methods
User user = await LoggedMethodCaller.CallAsync(() => userService.GetUserAsync(123));
await LoggedMethodCaller.CallAsync(() => notificationService.SendNotificationsAsync());

CorrelationManager

Manages correlation IDs for tracking related log entries across multiple components.

// Start a new logical operation
CorrelationManager.StartNewCorrelation();

// Get the current correlation ID
string correlationId = CorrelationManager.CurrentCorrelationId;

// Pass to other systems
httpClient.DefaultRequestHeaders.Add("X-Correlation-ID", correlationId);

Logging Attributes

Basic Attributes Usage

// Different logging levels
[LogTrace]
public void HighDetailDiagnostics() { }

[LogDebug]
public List<string> GetDebugInfo() { }

[LogInfo]
public User CreateUser(UserRequest request) { }

[LogWarning]
public bool ValidateInput(string input) { }

[LogError]
public void ProcessPayment(Payment payment) { }

[LogCritical]
public void UpdateSystemConfig(SystemConfig config) { }

// Logs in all environments, including production
[LogProd]
public void BusinessCriticalOperation() { }

Customizing Attributes

// Control what gets logged
[LogInfo(
    IncludeParameters = true,       // Log method parameters
    IncludeReturnValue = true,      // Log return value
    IncludeExecutionTime = true     // Log execution time
)]
public Report GenerateReport(ReportRequest request) { }

// With progress logging for long operations
[LogInfo]
[WithProgressLogging(intervalMs: 1000)]  // Log progress every second
public async Task ImportLargeDatasetAsync() { }

Advanced Features

Data Change Tracking

Track changes to objects across method calls:

[TrackDataChanges(
    IncludeOriginalState = true,     // Include original state in logs
    IncludeUpdatedState = true,      // Include updated state in logs
    OperationType = "UserUpdate"     // Custom operation name
)]
public User UpdateUser([BeforeChange] User user, UserUpdateRequest request)
{
    // Update user properties
    user.Name = request.Name;
    user.Email = request.Email;
    
    return user;
}

Performance Monitoring

// Performance tracking happens automatically for logged methods
[LogInfo]
public void PerformanceIntensiveOperation() { }

// Get performance statistics after running your application
var stats = LogManager.GetPerformanceTracker().GetStats();
foreach (var stat in stats)
{
    Console.WriteLine($"Method: {stat.Value.MethodName}");
    Console.WriteLine($"  Calls: {stat.Value.CallCount}");
    Console.WriteLine($"  Avg Time: {stat.Value.AverageTime:F2}ms");
}

Progress Logging

// Automatic progress logging for long operations
[LogInfo]
[WithProgressLogging(intervalMs: 1000)]
public async Task ProcessBatchesAsync(IEnumerable<DataBatch> batches)
{
    foreach (var batch in batches)
    {
        await Task.Delay(500); // Simulate work
        // Process batch...
    }
}

// Manual progress logging
using (var progressLogger = new ProgressLogger("Import Operation", 2000))
{
    // Long-running operation...
}

Log Throttling

// Prevent log flooding in high-frequency operations
[LogDebug]
[ThrottleLogging(MaxLogsPerSecond = 5)]
public double CalculateValue(double input)
{
    // High-frequency operation
    return Math.Pow(input, 2);
}

Sensitive Data Protection

public class User
{
    public string Username { get; set; }
    
    [MaskInLogs(ShowFirstChars = true, FirstCharsCount = 1)]
    public string Password { get; set; }  // "p***"
    
    [MaskInLogs(ShowFirstChars = true, FirstCharsCount = 3, 
                ShowLastChars = true, LastCharsCount = 4)]
    public string Email { get; set; }  // "joh***ple.com"
    
    [RedactContents(ReplacementText = "[CREDIT CARD REDACTED]")]
    public string CreditCardNumber { get; set; }
    
    [ExcludeFromLogs]
    public string ApiKey { get; set; }  // Excluded completely
}

Log Routing

// Create a router with custom routing rules
var router = new LogRouter(new ConsoleLogger())
    // Send all errors to an error log file
    .AddRoute(entry => entry.Level >= LogLevel.Error, 
              new FileLogger(LogLevel.Error, "errors.log"))
    
    // Send debug logs to a debug file
    .AddRoute(entry => entry.Level == LogLevel.Debug,
              new FileLogger(LogLevel.Debug, "debug.log"))
    
    // Send security-related logs to a secure log
    .AddRoute(entry => entry.Message.Contains("security"),
              new FileLogger(LogLevel.Info, "security.log"))
    
    // Send data changes to a database
    .AddRoute(entry => entry.HasDataChanges,
              new DatabaseLogger(LogLevel.Info, "Data Source=audit.db"));

LogManager.Configure(config => 
{
    config.Logger = router;
});

Database Logging

// Configure logging to a SQLite database
string dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs/logs.db");
var dbLogger = new DatabaseLogger(LogLevel.Info, $"Data Source={dbPath}");

LogManager.Configure(config => 
{
    config.Logger = new CompositeLogger(new[] {
        new ConsoleLogger(),
        dbLogger
    });
});

Configuration Options

Configure AnnotationLogger with various options:

LogManager.Configure(config => 
{
    // Logger and environment
    config.Logger = new CompositeLogger(new[] {
        new ConsoleLogger(),
        new FileLogger("app.log")
    });
    config.Environment = EnvironmentType.Development;
    
    // What to include in logs
    config.EnableMethodEntryExit = true;
    config.EnableParameterLogging = true;
    config.EnableReturnValueLogging = true;
    config.EnableExecutionTimeLogging = true;
    
    // Output format
    config.UseStructuredOutput = false;  // Set to true for JSON
    
    // Advanced settings
    config.MaxStringLength = 10000;      // Truncate long strings
    config.MaxCollectionItems = 100;     // Limit collection items
    config.IncludeStackTraces = true;
    config.MaxObjectDepth = 3;           // Nested object depth
    config.EnablePerformanceTracking = true;
});

// Configure data logging features
LogManager.ConfigureDataLogging(config => 
{
    config.EnableDataChangeTracking = true;
    config.MaxComparisonDepth = 3;
    config.IncludeSensitivePropertiesInChanges = false;
    config.LogBeforeState = false;
    config.LogAfterState = false;
    config.DataChangeLogLevel = LogLevel.Info;
});

Implementation Details

AnnotationLogger uses several advanced C# features:

  • Expression Trees: For method interception and parameter extraction
  • Reflection: For attribute discovery and parameter information
  • AsyncLocal<T>: For correlation ID propagation across async contexts
  • Stopwatch: For precise execution time measurement
  • ReaderWriterLockSlim: For thread-safe file logging
  • ConcurrentDictionary/ConcurrentBag: For thread-safe performance tracking

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
1.0.0 182 3/22/2025