abp icon indicating copy to clipboard operation
abp copied to clipboard

Optimize EntityChange logs

Open developerMCSI opened this issue 9 months ago • 2 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

Im trying to log the entity changes only for specific properties of an entity. Following the documentation i have added the data annotation "DisableAuditing" to the entity and added the tag "Audited" to the properties within the entity that i wanted to track changes. When i update an instance of the entity without changing any "audited" properties it still creates a record in the "AbpEntityChanges" table but no records in "AbpEntityPropertyChanges" resulting in an empty record when i look in the "auditing-logs" page: image

Describe the solution you'd like

If there were no changes to the audited property of the entity (no "AbpEntityPropertyChanges" records created) it would be useful if it did not create a record for the "AbpEntityChanges" table.

One implementation of this can be achieved by changing the function SaveLogAsync of the class AuditingStore.cs (https://github.com/abpframework/abp/blob/dev/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditingStore.cs):

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;

namespace Volo.Abp.AuditLogging;

public class AuditingStore : IAuditingStore, ITransientDependency
{
    public ILogger<AuditingStore> Logger { get; set; }
    protected IAuditLogRepository AuditLogRepository { get; }
    protected IUnitOfWorkManager UnitOfWorkManager { get; }
    protected AbpAuditingOptions Options { get; }
    protected IAuditLogInfoToAuditLogConverter Converter { get; }
    public AuditingStore(
        IAuditLogRepository auditLogRepository,
        IUnitOfWorkManager unitOfWorkManager,
        IOptions<AbpAuditingOptions> options,
        IAuditLogInfoToAuditLogConverter converter)
    {
        AuditLogRepository = auditLogRepository;
        UnitOfWorkManager = unitOfWorkManager;
        Converter = converter;
        Options = options.Value;

        Logger = NullLogger<AuditingStore>.Instance;
    }

    public virtual async Task SaveAsync(AuditLogInfo auditInfo)
    {
        if (!Options.HideErrors)
        {
            await SaveLogAsync(auditInfo);
            return;
        }

        try
        {
            await SaveLogAsync(auditInfo);
        }
        catch (Exception ex)
        {
            Logger.LogWarning("Could not save the audit log object: " + Environment.NewLine + auditInfo.ToString());
            Logger.LogException(ex, LogLevel.Error);
        }
    }

    // CHANGES HERE
    protected virtual async Task SaveLogAsync(AuditLogInfo auditInfo)
    {
        using (var uow = UnitOfWorkManager.Begin(true))
        {
            var auditLog = await Converter.ConvertAsync(auditInfo);

            //Remove all EntityChanges without PropertyChanges
            auditLog.EntityChanges.RemoveAll(x => x.PropertyChanges.Count == 0);

            await AuditLogRepository.InsertAsync(auditLog);
            await uow.CompleteAsync();
        }
    }
}

Additional context

No response

developerMCSI avatar May 24 '24 09:05 developerMCSI