diff --git a/docs/en/Audit-Logging.md b/docs/en/Audit-Logging.md index 2076764345..b3bc4335e1 100644 --- a/docs/en/Audit-Logging.md +++ b/docs/en/Audit-Logging.md @@ -41,6 +41,7 @@ Here, a list of the options you can configure: * `IsEnabledForAnonymousUsers` (default: `true`): If you want to write audit logs only for the authenticated users, set this to `false`. If you save audit logs for anonymous users, you will see `null` for `UserId` values for these users. * `AlwaysLogOnException` (default: `true`): If you set to true, it always saves the audit log on an exception/error case without checking other options (except `IsEnabled`, which completely disables the audit logging). * `IsEnabledForGetRequests` (default: `false`): HTTP GET requests should not make any change in the database normally and audit log system doesn't save audit log objects for GET request. Set this to `true` to enable it also for the GET requests. +* `DisableLogActionInfo` (default: `false`):If you set to true, Will no longer log `AuditLogActionInfo`. * `ApplicationName`: If multiple applications saving audit logs into a single database, set this property to your application name, so you can distinguish the logs of different applications. * `IgnoredTypes`: A list of `Type`s to be ignored for audit logging. If this is an entity type, changes for this type of entities will not be saved. This list is also used while serializing the action parameters. * `EntityHistorySelectors`: A list of selectors those are used to determine if an entity type is selected for saving the entity change. See the section below for details. diff --git a/docs/zh-Hans/Audit-Logging.md b/docs/zh-Hans/Audit-Logging.md index a8b6e66449..5463fdb03c 100644 --- a/docs/zh-Hans/Audit-Logging.md +++ b/docs/zh-Hans/Audit-Logging.md @@ -42,6 +42,7 @@ Configure(options => * `AlwaysLogOnException`(默认值: `true`): 如果设置为 `true`,将始终在异常/错误情况下保存审计日志,不检查其他选项(`IsEnabled` 除外,它完全禁用了审计日志). * `IsEnabledForGetRequests` (默认值: `false`): HTTP GET请求通常不应该在数据库进行任何更改,审计日志系统不会为GET请求保存审计日志对象. 将此值设置为 `true` 可为GET请求启用审计日志系统. * `ApplicationName`: 如果有多个应用程序保存审计日志到单一的数据库,使用此属性设置为你的应用程序名称区分不同的应用程序日志. +* `DisableLogActionInfo` (默认值: `false`): 如果设置为 `true`, 将不再记录 `AuditLogActionInfo`. * `IgnoredTypes`: 审计日志系统忽略的 `Type` 列表. 如果它是实体类型,则不会保存此类型实体的更改. 在序列化操作参数时也使用此列表. * `EntityHistorySelectors`:选择器列表,用于确定是否选择了用于保存实体更改的实体类型. 有关详细信息请参阅下面的部分. * `Contributors`: `AuditLogContributor` 实现的列表. 贡献者是扩展审计日志系统的一种方式. 有关详细信息请参阅下面的"审计日志贡献者"部分. diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs index 954a0bd6c7..82105693ec 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs @@ -41,8 +41,12 @@ public class AbpAuditActionFilter : IAsyncActionFilter, ITransientDependency finally { stopwatch.Stop(); - auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); - auditLog.Actions.Add(auditLogAction); + + if (auditLogAction != null) + { + auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + auditLog.Actions.Add(auditLogAction); + } } } } @@ -78,12 +82,16 @@ public class AbpAuditActionFilter : IAsyncActionFilter, ITransientDependency } auditLog = auditLogScope.Log; - auditLogAction = auditingHelper.CreateAuditLogAction( - auditLog, - context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(), - context.ActionDescriptor.AsControllerActionDescriptor().MethodInfo, - context.ActionArguments - ); + + if (!options.DisableLogActionInfo) + { + auditLogAction = auditingHelper.CreateAuditLogAction( + auditLog, + context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(), + context.ActionDescriptor.AsControllerActionDescriptor().MethodInfo, + context.ActionArguments + ); + } return true; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs index 1f347decf7..51137d3812 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs @@ -46,8 +46,12 @@ public class AbpAuditPageFilter : IAsyncPageFilter, ITransientDependency finally { stopwatch.Stop(); - auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); - auditLog.Actions.Add(auditLogAction); + + if (auditLogAction != null) + { + auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + auditLog.Actions.Add(auditLogAction); + } } } } @@ -81,12 +85,16 @@ public class AbpAuditPageFilter : IAsyncPageFilter, ITransientDependency } auditLog = auditLogScope.Log; - auditLogAction = auditingHelper.CreateAuditLogAction( - auditLog, - context.HandlerMethod.MethodInfo.DeclaringType, - context.HandlerMethod.MethodInfo, - context.HandlerArguments - ); + + if (!options.DisableLogActionInfo) + { + auditLogAction = auditingHelper.CreateAuditLogAction( + auditLog, + context.HandlerMethod.MethodInfo.DeclaringType, + context.HandlerMethod.MethodInfo, + context.HandlerArguments + ); + } return true; } diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs index 441cd8ef23..939814cba9 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs @@ -37,7 +37,7 @@ public class AbpAuditingOptions /// Default: true. /// public bool AlwaysLogOnException { get; set; } - + /// /// Disables/enables audit logging for integration services. /// Default: false. @@ -58,6 +58,11 @@ public class AbpAuditingOptions /// public bool IsEnabledForGetRequests { get; set; } + /// + /// Default: false. + /// + public bool DisableLogActionInfo { get; set; } + public AbpAuditingOptions() { IsEnabled = true; diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs index 78de793b6c..bee71b723a 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs @@ -37,7 +37,7 @@ public class AuditingInterceptor : AbpInterceptor, ITransientDependency var auditingManager = serviceScope.ServiceProvider.GetRequiredService(); if (auditingManager.Current != null) { - await ProceedByLoggingAsync(invocation, auditingHelper, auditingManager.Current); + await ProceedByLoggingAsync(invocation, auditingOptions, auditingHelper, auditingManager.Current); } else { @@ -74,16 +74,22 @@ public class AuditingInterceptor : AbpInterceptor, ITransientDependency private static async Task ProceedByLoggingAsync( IAbpMethodInvocation invocation, + AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope) { var auditLog = auditLogScope.Log; - var auditLogAction = auditingHelper.CreateAuditLogAction( - auditLog, - invocation.TargetObject.GetType(), - invocation.Method, - invocation.Arguments - ); + + AuditLogActionInfo auditLogAction = null; + if (!options.DisableLogActionInfo) + { + auditLogAction = auditingHelper.CreateAuditLogAction( + auditLog, + invocation.TargetObject.GetType(), + invocation.Method, + invocation.Arguments + ); + } var stopwatch = Stopwatch.StartNew(); @@ -99,8 +105,12 @@ public class AuditingInterceptor : AbpInterceptor, ITransientDependency finally { stopwatch.Stop(); - auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); - auditLog.Actions.Add(auditLogAction); + + if (auditLogAction != null) + { + auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + auditLog.Actions.Add(auditLogAction); + } } } @@ -117,7 +127,7 @@ public class AuditingInterceptor : AbpInterceptor, ITransientDependency { try { - await ProceedByLoggingAsync(invocation, auditingHelper, auditingManager.Current); + await ProceedByLoggingAsync(invocation, options, auditingHelper, auditingManager.Current); Debug.Assert(auditingManager.Current != null); if (auditingManager.Current.Log.Exceptions.Any()) diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs index 886df9a0ac..78d537e252 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs @@ -1,10 +1,12 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NSubstitute; using System.Threading.Tasks; +using Shouldly; using Volo.Abp.Auditing; using Xunit; @@ -98,4 +100,13 @@ public class AuditTestController_Tests : AspNetCoreMvcTestBase await _auditingStore.Received().SaveAsync(Arg.Is(x => x.Exceptions.Any())); } + + [Fact] + public async Task Should_DisableLogActionInfo() + { + _options.IsEnabledForGetRequests = true; + _options.DisableLogActionInfo = true; + await GetResponseAsync("/api/audit-test/"); + await _auditingStore.Received().SaveAsync(Arg.Is(x => x.Actions.IsNullOrEmpty())); + } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs index 0099202cd2..aae671d6d4 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestPage_Tests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -97,4 +98,14 @@ public class AuditTestPage_Tests : AspNetCoreMvcTestBase await _auditingStore.Received().SaveAsync(Arg.Is(x => x.Exceptions.Any())); } + + [Fact] + public async Task Should_DisableLogActionInfo() + { + _options.IsEnabledForGetRequests = true; + _options.DisableLogActionInfo = true; + + await GetResponseAsync("/Auditing/AuditTestPage"); + await _auditingStore.Received().SaveAsync(Arg.Is(x => x.Actions.IsNullOrEmpty())); + } } diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs index 49d92d2776..6c14d5503f 100644 --- a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs @@ -16,7 +16,7 @@ namespace Volo.Abp.Auditing; public class Auditing_Tests : AbpAuditingTestBase { - private IAuditingStore _auditingStore; + protected IAuditingStore AuditingStore; private IAuditingManager _auditingManager; private IUnitOfWorkManager _unitOfWorkManager; @@ -28,8 +28,8 @@ public class Auditing_Tests : AbpAuditingTestBase protected override void AfterAddApplication(IServiceCollection services) { - _auditingStore = Substitute.For(); - services.Replace(ServiceDescriptor.Singleton(_auditingStore)); + AuditingStore = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(AuditingStore)); } [Fact] @@ -43,7 +43,7 @@ public class Auditing_Tests : AbpAuditingTestBase await scope.SaveAsync(); } - await _auditingStore.Received().SaveAsync(Arg.Any()); + await AuditingStore.Received().SaveAsync(Arg.Any()); } [Fact] @@ -53,9 +53,9 @@ public class Auditing_Tests : AbpAuditingTestBase await myAuditedObject1.DoItAsync(new InputObject { Value1 = "forty-two", Value2 = 42 }); - await _auditingStore.Received().SaveAsync(Arg.Any()); + await AuditingStore.Received().SaveAsync(Arg.Any()); } - + [Fact] public async Task Should_Not_Write_AuditLog_For_Classes_With_IntegrationService_Attribute() { @@ -63,7 +63,7 @@ public class Auditing_Tests : AbpAuditingTestBase await myAuditedObject1.DoItAsync(new InputObject { Value1 = "forty-two", Value2 = 42 }); - await _auditingStore.DidNotReceive().SaveAsync(Arg.Any()); + await AuditingStore.DidNotReceive().SaveAsync(Arg.Any()); } public interface IMyAuditedObject : ITransientDependency, IAuditingEnabled @@ -82,7 +82,7 @@ public class Auditing_Tests : AbpAuditingTestBase }); } } - + /* Integration services should not be audited by default */ [IntegrationService] public class MyNotAuditedIntegrationService1 : IMyAuditedObject @@ -122,7 +122,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Any()); + AuditingStore.Received().SaveAsync(Arg.Any()); #pragma warning restore 4014 } @@ -137,7 +137,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Is(x => + AuditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 && !(x.EntityChanges[0].PropertyChanges.Any(p => p.PropertyName == nameof(AppEntityWithDisableAuditingAndPropertyHasAudited.Name2))))); @@ -155,7 +155,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Is(a => !a.EntityChanges.Any())); + AuditingStore.Received().SaveAsync(Arg.Is(a => !a.EntityChanges.Any())); #pragma warning restore 4014 } @@ -170,7 +170,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Any()); + AuditingStore.Received().SaveAsync(Arg.Any()); #pragma warning restore 4014 } @@ -185,7 +185,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Any()); + AuditingStore.Received().SaveAsync(Arg.Any()); #pragma warning restore 4014 } @@ -200,7 +200,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Is(x => + AuditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 && x.EntityChanges[0].PropertyChanges.Count == 2 && x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithDisableAuditingAndPropertyHasAudited.Name) && x.EntityChanges[0].PropertyChanges[1].PropertyName == nameof(AppEntityWithDisableAuditingAndPropertyHasAudited.Name3))); @@ -230,7 +230,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Is(x => + AuditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 && x.EntityChanges[0].PropertyChanges.Count == 1 && x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithDisableAuditingAndPropertyHasAudited.Name))); #pragma warning restore 4014 @@ -245,7 +245,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Any()); + AuditingStore.Received().SaveAsync(Arg.Any()); #pragma warning restore 4014 } @@ -274,7 +274,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 + AuditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 && x.EntityChanges[0].PropertyChanges.Any(y => !GetBaseAuditPropertyNames().Contains(y.PropertyName)))); #pragma warning restore 4014 @@ -300,7 +300,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 + AuditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 && x.EntityChanges[0].PropertyChanges .Where(y => y.PropertyName != nameof(AppEntityWithAuditedAndHasCustomAuditingProperties .ExtraProperties)) @@ -333,7 +333,7 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 + AuditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 && x.EntityChanges[0].PropertyChanges.Count == 1 && x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithAudited.Name))); #pragma warning restore 4014 @@ -354,10 +354,33 @@ public class Auditing_Tests : AbpAuditingTestBase } #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 && + AuditingStore.Received().SaveAsync(Arg.Is(x => x.EntityChanges.Count == 1 && x.EntityChanges[0].ChangeType == EntityChangeType.Deleted && x.EntityChanges[0].PropertyChanges.Count == 0)); #pragma warning restore 4014 } } + +public class Auditing_DisableLogActionInfo_Tests : Auditing_Tests +{ + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => + { + options.DisableLogActionInfo = true; + }); + + base.AfterAddApplication(services); + } + + [Fact] + public async Task Should_DisableLogActionInfo() + { + var myAuditedObject1 = GetRequiredService(); + + await myAuditedObject1.DoItAsync(new InputObject { Value1 = "forty-two", Value2 = 42 }); + + await AuditingStore.Received().SaveAsync(Arg.Is(x => x.Actions.IsNullOrEmpty())); + } +}