Indice.Features.ActivityLogs
8.43.1
dotnet add package Indice.Features.ActivityLogs --version 8.43.1
NuGet\Install-Package Indice.Features.ActivityLogs -Version 8.43.1
<PackageReference Include="Indice.Features.ActivityLogs" Version="8.43.1" />
<PackageVersion Include="Indice.Features.ActivityLogs" Version="8.43.1" />
<PackageReference Include="Indice.Features.ActivityLogs" />
paket add Indice.Features.ActivityLogs --version 8.43.1
#r "nuget: Indice.Features.ActivityLogs, 8.43.1"
#:package Indice.Features.ActivityLogs@8.43.1
#addin nuget:?package=Indice.Features.ActivityLogs&version=8.43.1
#tool nuget:?package=Indice.Features.ActivityLogs&version=8.43.1
Indice.Features.ActivityLogs
A comprehensive .NET library for tracking and managing user activity logs in ASP.NET Core applications. This feature provides detailed audit trails of user actions, including enriched context data such as device information, geolocation, request details, and more.
Features
- User Activity Tracking: Capture and persist detailed records of user actions within your application
- Asynchronous Processing: Queue-based processing with background persistence for minimal performance impact
- Enriched Logging: Automatically augment logs with contextual information (device, location, user info, application info, request details)
- Flexible Storage: Entity Framework Core integration for database persistence with support for customizable cleanup policies
- Anonymization: Optional automatic anonymization of personal data (IP addresses, etc.)
- Extensible Architecture: Custom enrichers, filters, and event converters for tailored logging behavior
- Automatic Cleanup: Configurable retention policies with background cleanup service
- Event Integration: Convert and adapt domain events into activity log entries
- Multi-Target Support: Compatible with .NET 8, .NET 9, and .NET 10
Installation
Add the NuGet package to your project:
dotnet add package Indice.Features.ActivityLogs
Quick Start
1. Register the Activity Logs Feature
In your Program.cs file, add the activity logs service:
services
.AddActivityLogs(configuration)
.UseEntityFrameworkCoreStore(optionsBuilder =>
{
optionsBuilder.UseSqlServer(connectionString);
});
2. Configure Options (Optional)
You can customize the activity logs behavior by providing configuration:
services
.AddActivityLogs(configuration, options =>
{
options.Enable = true;
options.AnonymizePersonalData = false;
options.QueueChannelCapacity = 100;
options.DequeueBatchSize = 10;
options.DequeueTimeoutInMilliseconds = 1000;
options.Categories.Add("Authentication");
options.Categories.Add("Authorization");
options.Cleanup.Enable = true;
options.Cleanup.RetentionDays = 90;
options.Cleanup.IntervalSeconds = 3600; // 1 hour
options.Cleanup.BatchSize = 4000;
})
.UseEntityFrameworkCoreStore(optionsBuilder =>
{
optionsBuilder.UseSqlServer(connectionString);
});
Note: If you add categories, only log entries matching those categories will be published; all others will be filtered out.
3. Publish Activity Logs
Inject IActivityLogPublisher and publish log entries:
public class MyService
{
private readonly IActivityLogPublisher _activityLogPublisher;
public MyService(IActivityLogPublisher activityLogPublisher)
{
_activityLogPublisher = activityLogPublisher;
}
public async Task DoSomethingAsync()
{
var logEntry = new ActivityLogEntry
{
ActionName = "UpdateProfile",
EventType = "UserAction",
Category = "UserManagement",
ApplicationId = "my-app",
ApplicationName = "My Application",
SubjectId = "user-123",
SubjectName = "john.doe@example.com",
ResourceId = "profile-456",
ResourceType = "UserProfile",
Description = "User updated their profile information",
Succeeded = true
};
await _activityLogPublisher.PublishAsync(logEntry);
}
}
Note: Many of these fields are automatically populated by the default enrichers.
Configuration Options
ActivityLogOptions
| Option | Type | Default | Description |
|---|---|---|---|
Enable |
bool |
true |
Determines whether activity logging is enabled |
AnonymizePersonalData |
bool |
false |
Anonymizes personal data (IP addresses) when persisted |
QueueChannelCapacity |
int |
100 |
Maximum number of items the internal queue can store |
DequeueBatchSize |
int |
10 |
Number of items processed in each batch |
DequeueTimeoutInMilliseconds |
long |
1000 |
Timeout in milliseconds for the queue to reach batch size |
ApiPrefix |
PathString |
/api |
Prefix for API endpoints |
DatabaseSchema |
string |
auth |
Schema name for the database (relational providers) |
Categories |
HashSet<string> |
Empty | Set of activity log categories |
ExcludedEnrichers |
List<Type> |
Empty | List of default enrichers to exclude |
Cleanup |
LogCleanupOptions |
- | Configuration for automatic log cleanup |
LogCleanupOptions
| Option | Type | Default | Description |
|---|---|---|---|
Enable |
bool |
false |
Determines whether automatic cleanup is enabled |
RetentionDays |
ushort |
90 |
Number of days to retain log entries |
IntervalSeconds |
ushort |
3600 |
Seconds between cleanup executions (1 hour) |
BatchSize |
ushort |
4000 |
Number of items to delete in each cleanup iteration |
Core Services
IActivityLogPublisher
The main interface for publishing activity log entries.
public interface IActivityLogPublisher
{
Task PublishAsync(ActivityLogEntry entry);
}
IActivityLogStore
Interface for persisting and retrieving activity log entries.
public interface IActivityLogStore
{
Task Cleanup(ActivityLogEntryFilter filter, CancellationToken cancellationToken = default);
Task CreateAsync(ActivityLogEntry entry, CancellationToken cancellationToken = default);
Task CreateManyAsync(IEnumerable<ActivityLogEntry> entries, CancellationToken cancellationToken = default);
Task<ResultSet<ActivityLogEntry>> ListAsync(ActivityLogEntryFilter filter, CancellationToken cancellationToken = default);
Task UpdateAsync(ActivityLogEntry entry, CancellationToken cancellationToken = default);
}
Activity Log Entry Model
ActivityLogEntry
Represents a single user activity log entry:
public class ActivityLogEntry
{
public Guid Id { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public string? ActionName { get; set; }
public string EventType { get; set; } = "Base";
public string? Category { get; set; }
public string? ApplicationId { get; set; }
public string? ApplicationName { get; set; }
public string? Source { get; set; }
public string? SubjectId { get; set; }
public string? SubjectName { get; set; }
public bool SubjectUnknown { get; set; }
public string? ResourceId { get; set; } = null!;
public string? ResourceType { get; set; }
public string? Description { get; set; }
public bool Succeeded { get; set; }
public string? IpAddress { get; set; }
public string? RequestId { get; set; }
public string? Location { get; set; }
public string? SessionId { get; set; }
public bool Review { get; set; }
public string? CountryIsoCode { get; set; }
public string? DeviceId { get; set; }
public GeoPoint? Coordinates { get; set; }
public ActivityLogEntryExtraData? ExtraData { get; set; }
}
Enrichers
The library includes several built-in enrichers that automatically augment log entries with additional context:
Default Enrichers
ApplicationInfoEnricher: Adds application identification informationUserInfoEnricher: Enriches with user/subject informationRequestInfoEnricher: Captures HTTP request details (IP address, session ID)DeviceEnricher: Adds device information from request headersDeviceIdEnricher: Extracts device identifierLocationEnricher: Adds geolocation data based on IP addressAnonymizationEnricher: Anonymizes personal data when configuredCategoryFilter: Filters logs based on configured categories
Excluding Default Enrichers
To exclude specific enrichers:
services.AddActivityLogs(configuration, options =>
{
options.ExcludedEnrichers.Add(typeof(LocationEnricher));
options.ExcludedEnrichers.Add(typeof(AnonymizationEnricher));
})
Creating Custom Enrichers
Implement IActivityLogEntryEnricher to create custom enrichers:
public class CustomEnricher : IActivityLogEntryEnricher
{
public int Order => 0;
public ActivityLogEnricherRunType RunType => ActivityLogEnricherRunType.Synchronous;
public async Task EnrichAsync(ActivityLogEntry entry, ActivityLogEnricherRunType runType)
{
if (runType == ActivityLogEnricherRunType.Synchronous)
{
entry.Description += " [Custom Info]";
}
await Task.CompletedTask;
}
}
Register the custom enricher:
services
.AddActivityLogs(configuration)
.AddEnricher<CustomEnricher>()
.UseEntityFrameworkCoreStore(optionsBuilder =>
{
optionsBuilder.UseSqlServer(connectionString);
});
Event Conversion
Convert domain events into activity log entries using IActivityLogFromEventConverter:
public interface IActivityLogFromEventConverter
{
bool CanConvert(DomainEvent domainEvent);
ActivityLogEntry Convert(DomainEvent domainEvent);
}
The default implementation (DefaultActivityLogFromEventConverter) can be customized via the ActivityLogAdapterEventHandler.
Hosted Services
PersistLogsHostedService
Background service that processes queued log entries and persists them to the configured store. Operates in batches for efficient database operations.
LogCleanupHostedService
When enabled, automatically removes log entries that exceed the configured retention period. Operates on a configurable interval with configurable batch sizes to avoid table locks.
Using Entity Framework Core
The library provides built-in Entity Framework Core integration:
services
.AddActivityLogs(configuration)
.UseEntityFrameworkCoreStore((serviceProvider, options) =>
{
var connectionString = serviceProvider
.GetRequiredService<IConfiguration>()
.GetConnectionString("DefaultConnection");
options.UseSqlServer(connectionString, sqlOptions =>
{
sqlOptions.MigrationsAssembly("YourMigrationsAssembly");
});
});
Database Context
The library uses ActivityLogDbContext which includes:
DbSet<DbActivityLogEntry> ActivityLogs { get; }- Configured mappings via
DbActivityLogEntryMap
Filtering Activity Logs
Query activity logs using ActivityLogEntryFilter:
var filter = new ActivityLogEntryFilter
{
Subject = "user-123",
Category = "Authentication",
From = DateTime.Now.AddDays(-7),
To = DateTime.Now,
Succeeded = true
};
var entries = await store.ListAsync(new ListOptions(), filter);
Disabling Activity Logs
For scenarios where you want to disable logging without changing code:
services.AddActivityLogs(configuration, options =>
{
options.Enable = false;
});
Note: When options.Enable = false, AddActivityLogs returns early and does NOT register
Performance Considerations
- Asynchronous Processing: Log entries are queued and processed asynchronously to minimize impact on request handling
- Batch Processing: Logs are persisted in configurable batches to optimize database operations
- Queue Capacity: Configure
QueueChannelCapacitybased on your application's load - Cleanup Operations: Stagger cleanup with appropriate
IntervalSecondsto avoid peak hour lock contention
Examples
Log Authentication Events
var passwordChangedLog = new ActivityLogEntry
{
ActionName = "PasswordChanged",
Category = "Authentication",
EventType = "SecurityEvent",
SubjectId = user.Id,
SubjectName = user.Email,
Succeeded = passwordChangeSuccessful,
Description = passwordChangeSuccessful ? "User changed their password" : "Password change failed"
};
await _activityLogPublisher.PublishAsync(passwordChangedLog);
Log Resource Changes
var resourceLog = new ActivityLogEntry
{
ActionName = "UpdateResource",
Category = "ResourceManagement",
EventType = "DataModification",
SubjectId = currentUser.Id,
ResourceId = resource.Id,
ResourceType = "Document",
Description = $"Resource '{resource.Name}' was updated",
Succeeded = true
};
await _activityLogPublisher.PublishAsync(resourceLog);
Architecture
The activity logs feature follows a clean architecture with several key components:
- Publisher: Main entry point for creating log entries
- Enricher Pipeline: Sequential enrichment of log entries with additional context
- Queue: Buffering layer for asynchronous processing
- Persistence Layer: Abstracted store interface with Entity Framework Core implementation
- Cleanup Service: Background worker for retention policy enforcement
- Event Adapter: Integration point for domain event conversion
Troubleshooting
Logs Not Being Persisted
- Verify
Enableis set totruein options - Check that
PersistLogsHostedServiceis running - Verify database connectivity and migrations have been applied
- Check
QueueChannelCapacityisn't being exceeded
High Memory Usage
- Reduce
QueueChannelCapacityto limit buffered entries - Decrease
DequeueTimeoutInMillisecondsfor faster processing - Increase
DequeueBatchSizefor fewer, larger batches
Performance Impact
- Consider excluding unnecessary enrichers
- Increase batch sizes for persistence operations
- Implement filtering to log only important events
- Enable anonymization to reduce data volume
License
This library is part of the Indice.Platform and is licensed under the applicable open-source license.
| 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
- Indice.AspNetCore (>= 8.43.1)
- Indice.Features.GeoIP (>= 8.43.1)
- Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite (>= 10.0.5)
- Open.ChannelExtensions (>= 9.2.0)
-
net8.0
- Indice.AspNetCore (>= 8.43.1)
- Indice.Features.GeoIP (>= 8.43.1)
- Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite (>= 9.0.14)
- Open.ChannelExtensions (>= 9.2.0)
-
net9.0
- Indice.AspNetCore (>= 8.43.1)
- Indice.Features.GeoIP (>= 8.43.1)
- Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite (>= 9.0.14)
- Open.ChannelExtensions (>= 9.2.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Indice.Features.ActivityLogs:
| Package | Downloads |
|---|---|
|
Indice.Features.Identity.Server
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.