Context
We are implementing a custom audit system based on ABP Framework's Audit Logging module. We have successfully implemented an AuditLogsAppService that allows us to query audit logs from the AbpAuditLogs and AbpAuditLogActions tables.
Implemented Functionality ✅
Currently we can:
- Query audit logs with filters (date, user, URL, HTTP method, etc.)
- Get complete details of each log including executed actions
- Calculate audit statistics and metrics
Additional Requirements ❓
We have two additional requirements to enrich audit information:
1. Customize Endpoint Names in ExtraProperties
Goal: Store custom descriptive names for actions instead of only using technical method names.
Current Situation: When an audit action is logged, we get technical information like:
ServiceName: "Entity1CrudAppService"MethodName: "CreateAsync"
What We Need:
We want to add a descriptive name in the ExtraProperties of AuditLogActionInfo, for example:
ExtraProperties["ActionDisplayName"]= "Create Entity1"ExtraProperties["ActionCategory"]= "CRUD Operations"ExtraProperties["MyCustomValue"]= "MyCustomValue From Method XXX"
Usage Example:
public class Entity1CrudAppService : ApplicationService
{
// When executing this method, we want it to be logged as:
// ServiceName: "Entity1CrudAppService"
// MethodName: "CreateAsync"
// ExtraProperties["ActionDisplayName"] = "Create Entity1"
public async Task<EntityDto> CreateAsync(CreateEntityDto input)
{
// ... method logic
}
}
Question 1:
What is the recommended way to add these custom properties to AuditLogActionInfo?
We have considered:
Option A: Use a custom attribute on methods
[AuditActionName("Create Entity1", Category = "CRUD")] public async Task<EntityDto> CreateAsync(CreateEntityDto input)Option B: Use a custom
AuditLogContributorpublic class CustomActionNameContributor : AuditLogContributor { public override void PostContribute(AuditLogContributionContext context) { // How do we access current method information to add properties? } }Option C: Another approach you recommend
2. Add Additional Information from a Specific Method
Goal: From within an AppService method, be able to add custom information to the current audit log.
Scenario: In a specific method, we want to record additional business information that is relevant for auditing.
Use Case Example:
public class ProjectsAppService : ApplicationService
{
public async Task<ProjectDto> CreateAsync(CreateProjectDto input)
{
// Create the project
var project = new Project(input.Name, input.Budget);
await _repository.InsertAsync(project);
// HERE: We want to add additional information to the current audit log
// For example:
// - Created project budget
// - Project category
// - Approver user if exists
// ❓ How do we add this information to the current AuditLog?
return ObjectMapper.Map<Project, ProjectDto>(project);
}
public async Task ApproveProjectAsync(Guid projectId)
{
var project = await _repository.GetAsync(projectId);
project.Approve(CurrentUser.Id);
// HERE: We want to record specific approval information
// - Previous project state
// - Approved amount
// - Approval comments
// ❓ How do we add this information to the current AuditLog?
await _repository.UpdateAsync(project);
}
}
What We Know:
According to ABP documentation, we can access the current audit scope:
public class MyService : ITransientDependency
{
private readonly IAuditingManager _auditingManager;
public MyService(IAuditingManager auditingManager)
{
_auditingManager = auditingManager;
}
public async Task DoItAsync()
{
var currentAuditLogScope = _auditingManager.Current;
if (currentAuditLogScope != null)
{
currentAuditLogScope.Log.Comments.Add("Custom comment");
currentAuditLogScope.Log.SetProperty("MyCustomProperty", 42);
}
}
}
Question 2:
- Is this the correct way to add information from an AppService method?
- Can we add properties to the specific
AuditLogActionInfoof the current method, or only to the generalAuditLogInfo? - Is there a recommended best practice or pattern for this?
Examples of Data We Want to Record
For Case 1 (Descriptive Names)
When querying logs, we want to see:
{
"auditLogId": "guid",
"executionTime": "2026-01-21T10:30:00",
"actions": [
{
"serviceName": "ProjectsAppService",
"methodName": "CreateAsync",
"executionDuration": 250,
"extraProperties": {
"ActionDisplayName": "Create Project",
"ActionCategory": "Project Management",
"EntityType": "Project"
}
}
]
}
For Case 2 (Additional Business Information)
{
"auditLogId": "guid",
"executionTime": "2026-01-21T10:30:00",
"actions": [
{
"serviceName": "ProjectsAppService",
"methodName": "CreateAsync",
"executionDuration": 250,
"extraProperties": {
"ProjectBudget": 50000,
"ProjectCategory": "Infrastructure",
"ApprovalRequired": true
}
}
],
"extraProperties": {
"BusinessOperation": "ProjectCreation",
"Department": "Engineering"
}
}
Constraints and Considerations
- Performance: The solution should not significantly impact performance
- Compatibility: Must be compatible with ABP Framework 8.x/9.x/10.x
- Maintainability: We prefer a solution that is easy to maintain and doesn't require modifying ABP internals
- Code Cleanliness: We prefer attributes or declarative configuration over imperative code in each method
Additional Information
- ABP Version: [Specify version, e.g.: 8.3, 9.0, 10.0]
- Database: SQL Server / PostgreSQL / MySQL
- Used Modules:
- Volo.Abp.AuditLogging
- Volo.Abp.AuditLogging.EntityFrameworkCore
Specific Questions for the Forum
What is the recommended way in ABP to add custom properties to
AuditLogActionInfo?Is there any attribute or interceptor mechanism to add metadata to audit actions?
How can we access the current action (
AuditLogActionInfo) from within an AppService method to add specific properties?Are there examples or documentation about similar use cases?
Is it possible to extend the audit system without modifying ABP source code?
Complete Example Code
Desired Implementation with Attribute (Case 1)
public class ProjectsAppService : ApplicationService, IProjectsAppService
{
private readonly IRepository<Project> _repository;
public ProjectsAppService(IRepository<Project> repository)
{
_repository = repository;
}
[AuditActionName("Create Project", Category = "Project Management")]
public async Task<ProjectDto> CreateAsync(CreateProjectDto input)
{
var project = new Project(input.Name, input.Budget);
await _repository.InsertAsync(project);
return ObjectMapper.Map<Project, ProjectDto>(project);
}
[AuditActionName("Update Project", Category = "Project Management")]
public async Task<ProjectDto> UpdateAsync(Guid id, UpdateProjectDto input)
{
var project = await _repository.GetAsync(id);
project.Update(input.Name, input.Budget);
await _repository.UpdateAsync(project);
return ObjectMapper.Map<Project, ProjectDto>(project);
}
}
Desired Implementation with IAuditingManager (Case 2)
public class ProjectsAppService : ApplicationService, IProjectsAppService
{
private readonly IRepository<Project> _repository;
private readonly IAuditingManager _auditingManager;
public ProjectsAppService(
IRepository<Project> repository,
IAuditingManager auditingManager)
{
_repository = repository;
_auditingManager = auditingManager;
}
public async Task<ProjectDto> CreateAsync(CreateProjectDto input)
{
var project = new Project(input.Name, input.Budget);
await _repository.InsertAsync(project);
// Add business information to audit log
var auditScope = _auditingManager.Current;
if (auditScope != null)
{
// ❓ How do we add properties to the CURRENT ACTION, not just the general log?
// This works but adds to general AuditLogInfo:
auditScope.Log.SetProperty("ProjectBudget", input.Budget);
// ❓ How do we do this for AuditLogActionInfo?
// auditScope.CurrentAction?.SetProperty("ProjectBudget", input.Budget);
}
return ObjectMapper.Map<Project, ProjectDto>(project);
}
}
Alternative Solutions Considered
1. Using Comments
auditScope.Log.Comments.Add($"Project created with budget: {input.Budget}");
Problem: Comments are plain text, not structured. We prefer typed properties.
2. Serializing in Parameters
Problem: Parameters already contain method input information. We don't want to mix with calculated or business information.
3. Creating a Parallel Audit System
Problem: Would duplicate functionality and wouldn't leverage ABP's system.
Expected Result
A solution that allows us to:
- Declare descriptive names for audit actions in a simple way
- Add structured business information from within methods
- Query this information easily from our
AuditLogsAppService - Keep the code clean and maintainable
We appreciate any guidance, code examples, or documentation references that help us achieve these goals.
5 Answer(s)
-
0
hi
We want to add a descriptive name in the ExtraProperties of AuditLogActionInfo
Option B: Use a custom AuditLogContributor is the best choice.
Is this the correct way to add information from an AppService method?
Audit log contributors, was explained above, is a global way of manipulating the audit log object. It is good if you can get a value from a service.
Injecting
IAuditingManagerservice will be good.Thanks,
-
0
[maliming] said: hi
We want to add a descriptive name in the ExtraProperties of AuditLogActionInfo
Option B: Use a custom AuditLogContributor is the best choice.
Is this the correct way to add information from an AppService method?
Audit log contributors, was explained above, is a global way of manipulating the audit log object. It is good if you can get a value from a service.
Injecting
IAuditingManagerservice will be good.Thanks,
Hello, after running debugging tests, I have observed the following:

It is a method in my app service. When I inject
IAuditingManager, I see that it does not have the current action. I only see the possibility of adding information as extra properties in the log.My idea was to do it in the action of that app service method, since in the logging module documentation, an
AuditLogInfocan have manyAuditLogActionInfo. After reviewing my database, I see that only 1AuditLogActionInfois recorded for eachAuditLogInfo.Why is this relationship like this? How can more than one
AuditLogActionInfobe recorded? Any suggestions for saving customised information in the event action?https://abp.io/docs/latest/framework/infrastructure/audit-logging
-
0
hi
The
Actionswill be populated after the method is executed.You can create a new Action in your method. Then merge them in your
AuditLogContributorThanks.
-
0
[maliming] said: hi
The
Actionswill be populated after the method is executed.You can create a new Action in your method. Then merge them in your
AuditLogContributorThanks.
What about the rest of the questions? How can more than one
AuditLogActionInfobe recorded? -
0
hi
There will be only one**
AuditLogInfoobject per HTTP request, per the current design.Thanks.