MH.UserActivityLogger 8.0.1

dotnet add package MH.UserActivityLogger --version 8.0.1
                    
NuGet\Install-Package MH.UserActivityLogger -Version 8.0.1
                    
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="MH.UserActivityLogger" Version="8.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MH.UserActivityLogger" Version="8.0.1" />
                    
Directory.Packages.props
<PackageReference Include="MH.UserActivityLogger" />
                    
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 MH.UserActivityLogger --version 8.0.1
                    
#r "nuget: MH.UserActivityLogger, 8.0.1"
                    
#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 MH.UserActivityLogger@8.0.1
                    
#: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=MH.UserActivityLogger&version=8.0.1
                    
Install as a Cake Addin
#tool nuget:?package=MH.UserActivityLogger&version=8.0.1
                    
Install as a Cake Tool

MH.UserActivityLogger

Plug-and-play HTTP user activity logging for ASP.NET Core.

Capture request/response details automatically, buffer them locally for zero-latency impact, and securely flush them to PostgreSQL with blockchain-like tamper detection.


✨ Key Features

  • 🚀 Zero Latency Impact: Requests are buffered to a local SQLite file immediately; database writes happen in the background.
  • 🛡️ Tamper-Proof: Uses SHA-256 hash chaining (blockchain style) to detect if logs in the database have been altered or deleted.
  • 📦 Bulk Processing: Efficiently bulk-inserts logs to PostgreSQL using COPY for high throughput.
  • 🔌 Plug-and-Play: Simple setup with standard ASP.NET Core Dependency Injection and Middleware.
  • 🔍 Granular Control: Log specific endpoints using the [UserActivityLog] attribute.
  • 👤 Extensible Identity: Built-in support for standard claims (sub, name, role) and extensible for custom user models.

🚀 Getting Started

1. Install the Package

via .NET CLI:

dotnet add package MH.UserActivityLogger

via Package Manager:

Install-Package MH.UserActivityLogger

2. Register Services

In your Program.cs:

using MH.UserActivityLogger.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Add the logger services
builder.Services.AddUserActivityLogging(options =>
{
    options.PostgresConnectionString = builder.Configuration.GetConnectionString("DefaultConnection");
    // options.SchemaName = "public"; // Default
    // options.TableName = "user_activity_logs"; // Default
});

4. Enable Middleware

Add the middleware after authentication/authorization but before your controllers.

var app = builder.Build();

// ... UseAuthentication();
// ... UseAuthorization();

await app.UseUserActivityLoggingAsync(); // Initialize the logger

app.MapControllers();
app.Run();

🛠 Usage

Basic Logging

Decorate any controller action you want to track using the [UserActivityLog] attribute. This attribute allows you to categorize and describe the activity for reporting purposes.

using MH.UserActivityLogger.Filters;
using MH.UserActivityLogger.Models;

[HttpPost("create")]
[UserActivityLog(action: "InvoiceCreation", actionType: "Write", criticality: CriticalityLevel.High, description: "User requested to create a new invoice.")]
public IActionResult CreateInvoice([FromBody] InvoiceDto dto)
{
    return Ok();
}
Parameter Type Description
action string Name of the activity. Grouping key for reports (e.g., "Login", "ExportReport").
actionType string Category of the operation. (e.g., "Read", "Write", "Delete", "System").
criticality CriticalityLevel Importance level (enum). Allowed values: High, Medium, Low. Defaults to Low.
description string Human-readable detail. A static description of what this endpoint does.

Advanced: Custom User Details

By default, the logger captures standard user info (User ID, Name, etc.). If you want to log custom fields (like TenantId, Department, or SubscriptionLevel) into the user_details JSON column, follow these steps:

Step 1: Define Your Custom Model

Create a class that represents the extra data you want to log.

public class UserDetailsModel
{
    public string TenantId { get; set; }
    public string Department { get; set; }
    public string SubscriptionLevel { get; set; }
}
Step 2: Implement the Data Provider

Create a class that implements IUserDetailsProvider<UserDetailsModel>. This logic extracts the data from the current user (ClaimsPrincipal).

using System.Security.Claims;
using MH.UserActivityLogger.Abstractions;

public class UserDetailsModelProvider : IUserDetailsProvider<UserDetailsModel>
{
    // This method is called for every request to populate your custom model
    public UserDetailsModel ExtractUserDetails(ClaimsPrincipal user)
    {
        return new UserDetailsModel
        {
            // Extract values from claims (or any other source)
            TenantId = user.FindFirst("tenant_id")?.Value ?? "Default-Tenant",
            Department = user.FindFirst("department")?.Value ?? "General",
            SubscriptionLevel = user.FindFirst("subscription")?.Value ?? "Free"
        };
    }

    // Required: How to get the unique User ID
    public string? GetUserId(ClaimsPrincipal user) => user.FindFirst(ClaimTypes.NameIdentifier)?.Value;

    // Optional: customized Session ID logic (default is null)
    public string? GetSessionId(ClaimsPrincipal user) => user.FindFirst("session_id")?.Value;
}
Step 3: Register in Program.cs

Use the generic AddUserActivityLogging method to register your custom provider.

// 1. Add your custom context and provider as generic arguments
builder.Services.AddUserActivityLogging<UserDetailsModel, UserDetailsModelProvider>(options =>
{
    options.PostgresConnectionString = builder.Configuration.GetConnectionString("DefaultConnection");
});

Now, every log entry in the database will have your UserDetailsModel serialized inside the user_details JSON column!


⚙️ Configuration Options

Option Type Default Description
PostgresConnectionString string Required Connection string for the target PostgreSQL database.
SqlitePath string "activity_logs.db" Path to the local SQLite buffer file. High-throughput local storage.
GroupSize int 2000 Number of logs to accumulate in buffer before pushing to PostgreSQL.
FallbackFlushMinutes int 5 Maximum time to wait before forcing a flush of the buffer, even if GroupSize isn't met.
FlushBatchSize int 20 Number of records to insert per SQL command during bulk flush (optimizes network roundtrips).
TableName string "user_activity_logs" Name of the table in PostgreSQL.
SchemaName string "public" Schema name in PostgreSQL.
EnableHashChaining bool true Enables SHA-256 blockchain-style linking of log entries for tamper detection.
MaxRequestBodySize int 4096 Max characters to capture from the request body. Larger bodies are truncated.
MaxResponseSize int 4096 Max characters to capture from the response body. Larger responses are truncated.
EnableCompression bool false Compresses request_data and response JSON using GZip (Base64 encoded) before storing.
CompressionThreshold int 1024 Minimum string length to trigger compression (if enabled).

🏗 Architecture

  1. Incoming Request: Filter captures data.
  2. Local Buffer: Data is written to SQLite (fast, reliable).
  3. Background Flush: Service wakes up when buffer is full or time elapses.
  4. Secure Push: Logs are hashed (chained to previous log) and bulk-inserted into PostgreSQL.
Product 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 was computed.  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.