AHSW.EventLog
1.9.2
dotnet add package AHSW.EventLog --version 1.9.2
NuGet\Install-Package AHSW.EventLog -Version 1.9.2
<PackageReference Include="AHSW.EventLog" Version="1.9.2" />
<PackageVersion Include="AHSW.EventLog" Version="1.9.2" />
<PackageReference Include="AHSW.EventLog" />
paket add AHSW.EventLog --version 1.9.2
#r "nuget: AHSW.EventLog, 1.9.2"
#:package AHSW.EventLog@1.9.2
#addin nuget:?package=AHSW.EventLog&version=1.9.2
#tool nuget:?package=AHSW.EventLog&version=1.9.2
<a href="https://github.com/cat-begemot/event-log/tree/master/src/EventLog"> <img width="111" height="111" src="https://github.com/cat-begemot/event-log/blob/master/images/logo.png"/> </a>
Event Log
EventLog is a library that identifies application events, records diagnostic and statistical information about them, and stores them in a relational database for further analysis. Within the scope of an application event, it has the ability to track the state of application domain models.
The concept behind using EventLog is to gather information about application activity and domain model mutations for various purposes. Some possible examples of its use include:
- Monitoring the health state of a long-running application
- Identifying performance issues
- Being aware of user activity in the system, tracking who is responsible for changing any property of domain models
- Keeping a history of domain model changes
- Collecting statistics on user controls and application features to improve the UI
- Analyzing what happens in the application through API invocation and data changes for internal investigations
Table of Contents
- Event Log
- Table of Contents
- Usage Example in Code
- Database Result Output
- Sample Project
- How to use
- Use SQL queries for log investigation
- Use log tables in any way in code for extend application functionality
1. Usage Example in Code
As an example, imagine the following code is an API endpoint that creates a domain model, Book, and saves it in storage.
As a wrapper, EventLog records the AddBooksOnShelf
event, adds some detailed information to the EventLogEntry
, executes the initial repository method while simultaneously adding an EntityLogEntry
related to the EventLogEntry
, and records the Book
property value states.
var book = GetBookEntity();
// Create event scope. For example, it can be API endpoint
await services.EventLog.CreateEventScopeAndRun(
// Define event type
EventType.AddBooksOnShelf,
async eventLogScope =>
{
// Addtional usefule data can be added to the event log record
eventLogScope.EventLogEntry.CreatedBy = userId;
eventLogScope.EventLogEntry.Details = "Adding a book";
// Trackable object is changed
book.Title = "Book Title - Rev1";
// Gathering object delta changing and save object and then event
// IMPORTANT: data modification must be completed before this invocation
await eventLogScope.SaveAndLogEntitiesAsync(
// Invoke object saving by EF data context
() => services.BookRepository.AddOrUpdateAsync(book),
options => options
// Define tracked objects and define tracked properties
.AddEntityLogging(
new[] { book },
PropertyType.BookTitle,
PropertyType.BookLikeCount));
});
2. Database Result Output
As a result, EventLog table data can be viewed and analysed using SQL queries. Expand below text to see the examples.
<details> <summary>2.1. Analyse all recorded application events</summary>
ShowAllEvents.sql
| Id | Initiator | EventType | Status | CreatedAt | DurationInMs | Details | FailureDetails | |---|---|---|---|---|---|---|---| | 8 | 3 | Update books | Successful | 2025-04-05 13:22:59.2916081 | 2 | No one observable property is not changed | | | 7 | 3 | Update books | Successful | 2025-04-05 13:22:59.2836144 | 5 | Observable property is changed | | | 6 | 3 | Add books | Successful | 2025-04-05 13:22:59.2754546 | 7 | Adding a book | | | 5 | 3 | Add books | Successful | 2025-04-05 13:22:59.2566239 | 16 | Adding a shelf and 2 books | | | 4 | 3 | Add books | Successful | 2025-04-05 13:22:59.2509625 | 3 | Adding a book | | | 3 | 3 | Add books | Successful | 2025-04-05 13:22:59.1869002 | 63 | Adding a book | | | 2 | 3 | Add shelf | Successful | 2025-04-05 13:22:59.0944167 | 91 | Adding a shelf | | | 1 | 3 | Add books | Successful | 2025-04-05 13:22:58.9072985 | 185 | Adding a shelf and 2 books | | </details>
<details> <summary>2.2. Analyse application event statistics</summary>
ShowAllEvents.sql
| EventType | TotalCount | ErrorCount | MedianInMs | MeanInMs | |---|---|---|---|---| | Add books | 7 | 2 | 63 | 81 | | Add shelf | 1 | 0 | 92 | 92 | | Update books | 2 | 0 | 4 | 4 | </details>
<details> <summary>2.3. Track application domain model properties changing</summary>
ShowAllEvents.sql
| CreatedAt | Action | EntityId | Entity | Property | Value | ValueType | InitiatorId | Event | |---|---|---|---|---|---|---|---|---| | 2025-04-05 13:22:59 | Create | 8 | Book | Title | EventLog Manual - 43 Edition | String | 3 | Add books | | 2025-04-05 13:22:59 | Create | 8 | Book | Published | 2025-04-05 13:22:59.2968132 | DateTime | 3 | Add books | | 2025-04-05 13:22:59 | Create | 8 | Book | IsAvailable | 1 | Bool | 3 | Add books | | 2025-04-05 13:22:59 | Create | 8 | Book | Condition | 1 | Int32 | 3 | Add books | | 2025-04-05 13:22:59 | Create | 8 | Book | Labels | 3 | Int32 | 3 | Add books | | 2025-04-05 13:22:59 | Create | 8 | Book | LikeCount | 96 | Int32 | 3 | Add books | | 2025-04-05 13:22:59 | Create | 8 | Book | Price | 43.0 | Double | 3 | Add books | | 2025-04-05 13:22:59 | Update | 7 | Book | Title | EventLog Manual - 63 Edition - Revision_1 | String | 3 | Update books | | 2025-04-05 13:22:59 | Update | 7 | Book | Published | 2025-04-05 13:22:59.2832816 | DateTime | 3 | Update books | | 2025-04-05 13:22:59 | Update | 7 | Book | FirstSale | 2025-04-06 13:22:59.2832817 | DateTime | 3 | Update books | </details>
3. Sample Project
Bookstore is a sample console application to demonstrate the way of configuring EventLog and the most common use cases.
4. How to use
4.1. Define TEventType, TEntityType, and TPropertyType empty enums
These enums will be filled later, when required event and property logging is added to the code. It is desirable to follow the next suggestions.
- 4.1.1. Explicitly numerate enum members to avoid damaging the log in the future
// Preferable to use the short underlying type to keep EventLog data compact
internal enum EventType : short
{
// Books = 1000
AddBooksOnShelf = 1001, // Explicit number is assigned to each enum member
UpdateBooksOnShelf = 1002,
// Shelves = 2000
AddShelf = 2001,
DeleteShelf = 2002,
}
- 4.1.2. Group enum members to simplify further maintenance and extends types
// Preferable to use the short underlying type to keep EventLog data compact
internal enum PropertyType : short
{
// Book = 1000 - All properties grouped by entity
BookTitle = 1001,
BookPublished = 1002,
BookIsAvailable = 1003,
BookLikeCount = 1004,
BookPrice = 1005,
BookFirstSale = 1006,
BookCondition = 1007,
BookLabels = 1008,
// Shelf = 2000
ShelfHeight = 2001
- 4.1.3. Make consistency numeration between TEntityType and TPropertyType
// Preferable to use the short underlying type to keep EventLog data compact
internal enum EntityType ; short
{
Book = 1000, // PropertyType has Book entity group that starts with 1000 as well
Shelf = 2000
}
4.2. Embed EventLog tables to the application database context
- 4.2.1. Add
modelBuilder.ApplyEventLogConfigurations<EventType, EntityType, PropertyType>();
to the overriden OnModelCreating method in the application database context class. Make sure it goes first in the settings in roder to apply all database schemes correctly
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyEventLogConfigurations<EventType, EntityType, PropertyType>(); // Must be first
modelBuilder.ApplyConfigurationsFromAssembly(typeof(BookstoreDbContext).Assembly);
}
- 4.2.2. Create and apply the new migration with EventLog convfigurations
4.3. Add ObservableProperties static class (optional)
Predefine methods with observable property collections to enable convenient and consistent usage across the application.
internal static class ObservableProperties
{
public static PropertyType[] GetForBookEntity() =>
new []
{
PropertyType.BookTitle,
PropertyType.BookCondition,
};
public static PropertyType[] GetForShelfEntity() =>
new []
{
PropertyType.ShelfHeight
};
}
4.4. Register EventLog service
services.AddEventLog<BookstoreDbContext, EventType, EntityType, PropertyType>();
4.5. Configure EventLog service on the application startup
Setting up enum member custom names is a convenient way to make look of SQL query results more user-friendly.
All observable properties and appropriate entities must be resigtered in the service configuration.
See more detail example in the Program.cs.
EventLogService<EventType, EntityType, PropertyType>.Configure(
configurationBuilder => configurationBuilder
// Optional customization
.UseCustomTypeDescriptions(context,
options => options
// Customize event type descriptions
.AddEventTypeDescription(EventType.AddBooksOnShelf, "Add books on a shelf")
.AddEventTypeDescription(EventType.UpdateBooksOnShelf, "Update books on a shelf")
// Customize entity type descriptions
.AddEntityTypeDescription(EntityType.Book, "Book")
.AddEntityTypeDescription(EntityType.Shelf, "Shelf")
// Customize ptoperty type descriptions
.AddPropertyTypeDescription(PropertyType.BookTitle, "Title")
.AddPropertyTypeDescription(PropertyType.ShelfHeight, "Height")
)
.RegisterEntity<BookEntity>(EntityType.Book, x => ((BookEntity)x).Id,
options => options
.RegisterProperty(PropertyType.BookTitle,
x => x.Title, nameof(BookEntity.Title))
)
.RegisterEntity<ShelfEntity>(EntityType.Shelf, x => ((ShelfEntity)x).Id,
options => options
.RegisterProperty(PropertyType.ShelfHeight,
x => x.Height, nameof(ShelfEntity.Height))
)
);
});
4.6. Add EventLog recording
All entity changes must be made before SaveAndLogEntitiesAsync() invocation. Inside this method entities must be only updated in repository and saves.
See more examples in the Program.cs.
var book = CreateBookEntity();
await services.EventLog.CreateEventScopeAndRun(
// Specify event logging level here
EventType.AddBooksOnShelf,
async eventLogScope =>
{
eventLogScope.EventLogEntry.CreatedBy = userId;
eventLogScope.EventLogEntry.Details = "Adding a book";
await eventLogScope.SaveAndLogEntitiesAsync(
// All entity changes must be made before SaveAndLogEntitiesAsync() invocation
() => services.BookRepository.AddOrUpdateAsync(book),
options => options
// Specify entity level logging here
.AddEntityLogging(
// Specify property level logging here
new[] { book }, ObservableProperties.GetForBookEntity)
);
}
);
5. Use SQL queries for log investigation
All samples of SQL queries can be found here:
6. Use log tables in any way in code for extend application functionality
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. |
-
net7.0
- Microsoft.EntityFrameworkCore.Relational (>= 7.0.20)
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.9.2 | 137 | 6/30/2025 |
1.9.1 | 85 | 4/5/2025 |
1.9.0 | 91 | 4/5/2025 |
1.8.2 | 96 | 4/5/2025 |
1.8.1 | 94 | 4/5/2025 |
1.8.0 | 160 | 4/2/2025 |
1.7.1 | 154 | 4/1/2025 |
1.7.0 | 152 | 4/1/2025 |
1.6.1 | 150 | 3/31/2025 |
1.6.0 | 155 | 3/31/2025 |
1.5.3 | 471 | 3/25/2025 |
1.5.2 | 162 | 3/22/2025 |
1.5.1 | 159 | 3/22/2025 |
1.5.0 | 158 | 3/22/2025 |
1.4.2 | 113 | 3/1/2025 |
1.4.1 | 115 | 2/25/2025 |
1.4.0 | 103 | 2/25/2025 |
1.3.1 | 101 | 2/24/2025 |
1.3.0 | 116 | 2/24/2025 |
1.2.4 | 131 | 2/23/2025 |
1.2.3 | 113 | 2/22/2025 |
1.2.2 | 109 | 2/21/2025 |
1.2.1 | 108 | 2/21/2025 |