Use RemoteServiceErrorInfo as the exception info in the AuditLog.

Resolve #9101
pull/9116/head
maliming 4 years ago
parent 9ebb57adee
commit 2491c8c488

@ -26,8 +26,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
protected IJsonSerializer JsonSerializer { get; }
protected AbpAuditingOptions Options { get; }
protected IAuditingHelper AuditingHelper { get; }
private readonly IClock _clock;
protected IClock Clock{ get; }
public EntityHistoryHelper(
IAuditingStore auditingStore,
@ -36,7 +35,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
IJsonSerializer jsonSerializer,
IAuditingHelper auditingHelper)
{
_clock = clock;
Clock = clock;
AuditingStore = auditingStore;
JsonSerializer = jsonSerializer;
AuditingHelper = auditingHelper;
@ -69,7 +68,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
}
[CanBeNull]
private EntityChangeInfo CreateEntityChangeOrNull(EntityEntry entityEntry)
protected virtual EntityChangeInfo CreateEntityChangeOrNull(EntityEntry entityEntry)
{
var entity = entityEntry.Entity;
@ -121,23 +120,23 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
return multiTenantEntity.TenantId;
}
private DateTime GetChangeTime(EntityChangeInfo entityChange)
protected virtual DateTime GetChangeTime(EntityChangeInfo entityChange)
{
var entity = entityChange.EntityEntry.As<EntityEntry>().Entity;
switch (entityChange.ChangeType)
{
case EntityChangeType.Created:
return (entity as IHasCreationTime)?.CreationTime ?? _clock.Now;
return (entity as IHasCreationTime)?.CreationTime ?? Clock.Now;
case EntityChangeType.Deleted:
return (entity as IHasDeletionTime)?.DeletionTime ?? _clock.Now;
return (entity as IHasDeletionTime)?.DeletionTime ?? Clock.Now;
case EntityChangeType.Updated:
return (entity as IHasModificationTime)?.LastModificationTime ?? _clock.Now;
return (entity as IHasModificationTime)?.LastModificationTime ?? Clock.Now;
default:
throw new AbpException($"Unknown {nameof(EntityChangeInfo)}: {entityChange}");
}
}
private string GetEntityId(object entityAsObj)
protected virtual string GetEntityId(object entityAsObj)
{
if (!(entityAsObj is IEntity entity))
{
@ -156,7 +155,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
/// <summary>
/// Gets the property changes for this entry.
/// </summary>
private List<EntityPropertyChangeInfo> GetPropertyChanges(EntityEntry entityEntry)
protected virtual List<EntityPropertyChangeInfo> GetPropertyChanges(EntityEntry entityEntry)
{
var propertyChanges = new List<EntityPropertyChangeInfo>();
var properties = entityEntry.Metadata.GetProperties();
@ -181,12 +180,12 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
return propertyChanges;
}
private bool IsCreated(EntityEntry entityEntry)
protected virtual bool IsCreated(EntityEntry entityEntry)
{
return entityEntry.State == EntityState.Added;
}
private bool IsDeleted(EntityEntry entityEntry)
protected virtual bool IsDeleted(EntityEntry entityEntry)
{
if (entityEntry.State == EntityState.Deleted)
{
@ -197,7 +196,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
return entity is ISoftDelete && entity.As<ISoftDelete>().IsDeleted;
}
private bool ShouldSaveEntityHistory(EntityEntry entityEntry, bool defaultValue = false)
protected virtual bool ShouldSaveEntityHistory(EntityEntry entityEntry, bool defaultValue = false)
{
if (entityEntry.State == EntityState.Detached ||
entityEntry.State == EntityState.Unchanged)
@ -220,7 +219,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
return defaultValue;
}
private bool ShouldSavePropertyHistory(PropertyEntry propertyEntry, bool defaultValue)
protected virtual bool ShouldSavePropertyHistory(PropertyEntry propertyEntry, bool defaultValue)
{
if (propertyEntry.Metadata.Name == "Id")
{
@ -256,7 +255,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
return defaultValue;
}
private bool IsBaseAuditProperty(PropertyInfo propertyInfo, Type entityType)
protected virtual bool IsBaseAuditProperty(PropertyInfo propertyInfo, Type entityType)
{
if (entityType.IsAssignableTo<IHasCreationTime>()
&& propertyInfo.Name == nameof(IHasCreationTime.CreationTime))
@ -308,11 +307,11 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
return false;
}
/// <summary>
/// Updates change time, entity id and foreign keys after SaveChanges is called.
/// </summary>
public void UpdateChangeList(List<EntityChangeInfo> entityChanges)
public virtual void UpdateChangeList(List<EntityChangeInfo> entityChanges)
{
foreach (var entityChange in entityChanges)
{
@ -372,4 +371,4 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
}
}
}
}
}

@ -1,5 +1,7 @@
using Volo.Abp.Auditing;
using Volo.Abp.Domain;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.Json;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
@ -10,13 +12,15 @@ namespace Volo.Abp.AuditLogging
[DependsOn(typeof(AbpAuditingModule))]
[DependsOn(typeof(AbpDddDomainModule))]
[DependsOn(typeof(AbpAuditLoggingDomainSharedModule))]
[DependsOn(typeof(AbpExceptionHandlingModule))]
[DependsOn(typeof(AbpJsonModule))]
public class AbpAuditLoggingDomainModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void PostConfigureServices(ServiceConfigurationContext context)
{
OneTimeRunner.Run(() =>
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
AuditLoggingModuleExtensionConsts.ModuleName,

@ -59,57 +59,55 @@ namespace Volo.Abp.AuditLogging
}
public AuditLog(IGuidGenerator guidGenerator, AuditLogInfo auditInfo)
: base(guidGenerator.Create())
public AuditLog(
Guid id,
string applicationName,
Guid? tenantId,
string tenantName,
Guid? userId,
string userName,
DateTime executionTime,
int executionDuration,
string clientIpAddress,
string clientName,
string clientId,
string correlationId,
string browserInfo,
string httpMethod,
string url,
int? httpStatusCode,
Guid? impersonatorUserId,
Guid? impersonatorTenantId,
ExtraPropertyDictionary extraPropertyDictionary,
List<EntityChange> entityChanges,
List<AuditLogAction> actions,
string exceptions,
string comments)
: base(id)
{
ApplicationName = auditInfo.ApplicationName.Truncate(AuditLogConsts.MaxApplicationNameLength);
TenantId = auditInfo.TenantId;
TenantName = auditInfo.TenantName.Truncate(AuditLogConsts.MaxTenantNameLength);
UserId = auditInfo.UserId;
UserName = auditInfo.UserName.Truncate(AuditLogConsts.MaxUserNameLength);
ExecutionTime = auditInfo.ExecutionTime;
ExecutionDuration = auditInfo.ExecutionDuration;
ClientIpAddress = auditInfo.ClientIpAddress.Truncate(AuditLogConsts.MaxClientIpAddressLength);
ClientName = auditInfo.ClientName.Truncate(AuditLogConsts.MaxClientNameLength);
ClientId = auditInfo.ClientId.Truncate(AuditLogConsts.MaxClientIdLength);
CorrelationId = auditInfo.CorrelationId.Truncate(AuditLogConsts.MaxCorrelationIdLength);
BrowserInfo = auditInfo.BrowserInfo.Truncate(AuditLogConsts.MaxBrowserInfoLength);
HttpMethod = auditInfo.HttpMethod.Truncate(AuditLogConsts.MaxHttpMethodLength);
Url = auditInfo.Url.Truncate(AuditLogConsts.MaxUrlLength);
HttpStatusCode = auditInfo.HttpStatusCode;
ImpersonatorUserId = auditInfo.ImpersonatorUserId;
ImpersonatorTenantId = auditInfo.ImpersonatorTenantId;
ExtraProperties = new ExtraPropertyDictionary();
if (auditInfo.ExtraProperties != null)
{
foreach (var pair in auditInfo.ExtraProperties)
{
ExtraProperties.Add(pair.Key, pair.Value);
}
}
EntityChanges = auditInfo
.EntityChanges?
.Select(entityChangeInfo => new EntityChange(guidGenerator, Id, entityChangeInfo, tenantId: auditInfo.TenantId))
.ToList()
?? new List<EntityChange>();
Actions = auditInfo
.Actions?
.Select(auditLogActionInfo => new AuditLogAction(guidGenerator.Create(), Id, auditLogActionInfo, tenantId: auditInfo.TenantId))
.ToList()
?? new List<AuditLogAction>();
Exceptions = auditInfo
.Exceptions?
.JoinAsString(Environment.NewLine)
.Truncate(AuditLogConsts.MaxExceptionsLengthValue);
Comments = auditInfo
.Comments?
.JoinAsString(Environment.NewLine)
.Truncate(AuditLogConsts.MaxCommentsLength);
ApplicationName = applicationName.Truncate(AuditLogConsts.MaxApplicationNameLength);
TenantId = tenantId;
TenantName = tenantName.Truncate(AuditLogConsts.MaxTenantNameLength);
UserId = userId;
UserName = userName.Truncate(AuditLogConsts.MaxUserNameLength);
ExecutionTime = executionTime;
ExecutionDuration = executionDuration;
ClientIpAddress = clientIpAddress.Truncate(AuditLogConsts.MaxClientIpAddressLength);
ClientName = clientName.Truncate(AuditLogConsts.MaxClientNameLength);
ClientId = clientId.Truncate(AuditLogConsts.MaxClientIdLength);
CorrelationId = correlationId.Truncate(AuditLogConsts.MaxCorrelationIdLength);
BrowserInfo = browserInfo.Truncate(AuditLogConsts.MaxBrowserInfoLength);
HttpMethod = httpMethod.Truncate(AuditLogConsts.MaxHttpMethodLength);
Url = url.Truncate(AuditLogConsts.MaxUrlLength);
HttpStatusCode = httpStatusCode;
ImpersonatorUserId = impersonatorUserId;
ImpersonatorTenantId = impersonatorTenantId;
ExtraProperties = extraPropertyDictionary;
EntityChanges = entityChanges;
Actions = actions;
Exceptions = exceptions.Truncate(AuditLogConsts.MaxExceptionsLengthValue);
Comments = comments.Truncate(AuditLogConsts.MaxCommentsLength);
}
}
}

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Http;
using Volo.Abp.Json;
namespace Volo.Abp.AuditLogging
{
public class AuditLogInfoToAuditLogConverter : IAuditLogInfoToAuditLogConverter, ITransientDependency
{
protected IGuidGenerator GuidGenerator { get; }
protected IExceptionToErrorInfoConverter ExceptionToErrorInfoConverter { get; }
protected IJsonSerializer JsonSerializer { get; }
public AuditLogInfoToAuditLogConverter(IGuidGenerator guidGenerator, IExceptionToErrorInfoConverter exceptionToErrorInfoConverter, IJsonSerializer jsonSerializer)
{
GuidGenerator = guidGenerator;
ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter;
JsonSerializer = jsonSerializer;
}
public virtual Task<AuditLog> ConvertAsync(AuditLogInfo auditLogInfo)
{
var auditLogId = GuidGenerator.Create();
var extraProperties = new ExtraPropertyDictionary();
if (auditLogInfo.ExtraProperties != null)
{
foreach (var pair in auditLogInfo.ExtraProperties)
{
extraProperties.Add(pair.Key, pair.Value);
}
}
var entityChanges = auditLogInfo
.EntityChanges?
.Select(entityChangeInfo => new EntityChange(GuidGenerator, auditLogId, entityChangeInfo, tenantId: auditLogInfo.TenantId))
.ToList()
?? new List<EntityChange>();
var actions = auditLogInfo
.Actions?
.Select(auditLogActionInfo => new AuditLogAction(GuidGenerator.Create(), auditLogId, auditLogActionInfo, tenantId: auditLogInfo.TenantId))
.ToList()
?? new List<AuditLogAction>();
var remoteServiceErrorInfos = auditLogInfo.Exceptions?.Select(exception => ExceptionToErrorInfoConverter.Convert(exception, true))
?? new List<RemoteServiceErrorInfo>();
var exceptions = remoteServiceErrorInfos.Any()
? JsonSerializer.Serialize(remoteServiceErrorInfos, indented: false)
: null;
var comments = auditLogInfo
.Comments?
.JoinAsString(Environment.NewLine);
var auditLog = new AuditLog(
auditLogId,
auditLogInfo.ApplicationName,
auditLogInfo.TenantId,
auditLogInfo.TenantName,
auditLogInfo.UserId,
auditLogInfo.UserName,
auditLogInfo.ExecutionTime,
auditLogInfo.ExecutionDuration,
auditLogInfo.ClientIpAddress,
auditLogInfo.ClientName,
auditLogInfo.ClientId,
auditLogInfo.CorrelationId,
auditLogInfo.BrowserInfo,
auditLogInfo.HttpMethod,
auditLogInfo.Url,
auditLogInfo.HttpStatusCode,
auditLogInfo.ImpersonatorUserId,
auditLogInfo.ImpersonatorTenantId,
extraProperties,
entityChanges,
actions,
exceptions,
comments
);
return Task.FromResult(auditLog);
}
}
}

@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Uow;
namespace Volo.Abp.AuditLogging
@ -13,21 +12,19 @@ namespace Volo.Abp.AuditLogging
public class AuditingStore : IAuditingStore, ITransientDependency
{
public ILogger<AuditingStore> Logger { get; set; }
protected IAuditLogRepository AuditLogRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected AbpAuditingOptions Options { get; }
protected IAuditLogInfoToAuditLogConverter Converter { get; }
public AuditingStore(
IAuditLogRepository auditLogRepository,
IGuidGenerator guidGenerator,
IUnitOfWorkManager unitOfWorkManager,
IOptions<AbpAuditingOptions> options)
IOptions<AbpAuditingOptions> options,
IAuditLogInfoToAuditLogConverter converter)
{
AuditLogRepository = auditLogRepository;
GuidGenerator = guidGenerator;
UnitOfWorkManager = unitOfWorkManager;
Converter = converter;
Options = options.Value;
Logger = NullLogger<AuditingStore>.Instance;
@ -56,9 +53,9 @@ namespace Volo.Abp.AuditLogging
{
using (var uow = UnitOfWorkManager.Begin(true))
{
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, auditInfo));
await AuditLogRepository.InsertAsync(await Converter.ConvertAsync(auditInfo));
await uow.CompleteAsync();
}
}
}
}
}

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Volo.Abp.Auditing;
namespace Volo.Abp.AuditLogging
{
public interface IAuditLogInfoToAuditLogConverter
{
Task<AuditLog> ConvertAsync(AuditLogInfo auditLogInfo);
}
}

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using Shouldly;
using Volo.Abp.Auditing;
using Volo.Abp.Guids;
using Volo.Abp.Modularity;
using Xunit;
@ -17,12 +14,12 @@ namespace Volo.Abp.AuditLogging
where TStartupModule : IAbpModule
{
protected IAuditLogRepository AuditLogRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
protected IAuditLogInfoToAuditLogConverter AuditLogInfoToAuditLogConverter { get; }
protected AuditLogRepository_Tests()
{
AuditLogRepository = GetRequiredService<IAuditLogRepository>();
GuidGenerator = GetRequiredService<IGuidGenerator>();
AuditLogInfoToAuditLogConverter = GetRequiredService<IAuditLogInfoToAuditLogConverter>();
}
[Fact]
@ -119,8 +116,8 @@ namespace Volo.Abp.AuditLogging
}
};
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1));
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log1));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log2));
//Assert
var logs = await AuditLogRepository.GetListAsync();
@ -223,8 +220,8 @@ namespace Volo.Abp.AuditLogging
}
};
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1));
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log1));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log2));
//Assert
var logs = await AuditLogRepository.GetCountAsync();
@ -325,8 +322,8 @@ namespace Volo.Abp.AuditLogging
}
};
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1));
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log1));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log2));
//Assert
var date = DateTime.Parse("2020-01-01");
@ -428,8 +425,8 @@ namespace Volo.Abp.AuditLogging
}
};
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1));
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log1));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log2));
//Assert
var entityChanges = await AuditLogRepository.GetEntityChangeListAsync();
@ -534,8 +531,8 @@ namespace Volo.Abp.AuditLogging
}
};
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1));
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log1));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log2));
var entityChanges = await AuditLogRepository.GetEntityChangeListAsync();
var entityChange =
@ -641,8 +638,8 @@ namespace Volo.Abp.AuditLogging
}
};
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1));
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log1));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log2));
//Assert
var entityChangesDesc = await AuditLogRepository.GetEntityChangeListAsync();
@ -754,8 +751,8 @@ namespace Volo.Abp.AuditLogging
}
};
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1));
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log1));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log2));
//Assert
var entityChanges = await AuditLogRepository.GetEntityChangeListAsync(changeType: EntityChangeType.Created);
@ -864,8 +861,8 @@ namespace Volo.Abp.AuditLogging
}
};
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1));
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log1));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log2));
//Assert
var entityHistory = await AuditLogRepository.GetEntityChangesWithUsernameAsync(entityId, entityType);
@ -976,8 +973,8 @@ namespace Volo.Abp.AuditLogging
}
};
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1));
await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log1));
await AuditLogRepository.InsertAsync(await AuditLogInfoToAuditLogConverter.ConvertAsync(log2));
var entityChanges = await AuditLogRepository.GetEntityChangeListAsync();
var entityHistory =

Loading…
Cancel
Save