diff --git a/Directory.Packages.props b/Directory.Packages.props
index f7205a9ae..0c030dad2 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -365,6 +365,7 @@
+
diff --git a/aspnet-core/LINGYUN.MicroService.Aspire.sln b/aspnet-core/LINGYUN.MicroService.Aspire.sln
index 643cb28c3..953bd9423 100644
--- a/aspnet-core/LINGYUN.MicroService.Aspire.sln
+++ b/aspnet-core/LINGYUN.MicroService.Aspire.sln
@@ -925,6 +925,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.MicroService.Ap
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.BackgroundTasks.Quartz", "modules\task-management\LINGYUN.Abp.BackgroundTasks.Quartz\LINGYUN.Abp.BackgroundTasks.Quartz.csproj", "{ABCAB030-29ED-8219-F1DB-39D16098805F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Elasticsearch.Jobs", "modules\task-management\LINGYUN.Abp.Elasticsearch.Jobs\LINGYUN.Abp.Elasticsearch.Jobs.csproj", "{C4F5372D-3127-A2CA-3B22-B343D5E54EB5}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -2439,6 +2441,10 @@ Global
{ABCAB030-29ED-8219-F1DB-39D16098805F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABCAB030-29ED-8219-F1DB-39D16098805F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABCAB030-29ED-8219-F1DB-39D16098805F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C4F5372D-3127-A2CA-3B22-B343D5E54EB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C4F5372D-3127-A2CA-3B22-B343D5E54EB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C4F5372D-3127-A2CA-3B22-B343D5E54EB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C4F5372D-3127-A2CA-3B22-B343D5E54EB5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2889,6 +2895,7 @@ Global
{B856BFF0-8D0E-4C4A-97C7-5406E1B7613C} = {FAB71536-FCDB-4135-B61A-732B72FDA6A6}
{410E0FFF-705D-4471-9E52-FF495096A945} = {B856BFF0-8D0E-4C4A-97C7-5406E1B7613C}
{ABCAB030-29ED-8219-F1DB-39D16098805F} = {77ED7922-BF30-4436-8A85-78F812583913}
+ {C4F5372D-3127-A2CA-3B22-B343D5E54EB5} = {77ED7922-BF30-4436-8A85-78F812583913}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN.Abp.AuditLogging.Elasticsearch.csproj b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN.Abp.AuditLogging.Elasticsearch.csproj
index 7fad23128..b1b4a2035 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN.Abp.AuditLogging.Elasticsearch.csproj
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN.Abp.AuditLogging.Elasticsearch.csproj
@@ -15,6 +15,7 @@
+
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchOptions.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchOptions.cs
index e3976e330..1701762ec 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchOptions.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchOptions.cs
@@ -14,18 +14,10 @@ public class AbpAuditLoggingElasticsearchOptions
///
public bool ThrowIfIndexInitFailed { get; set; }
///
- /// 是否启用审计日志记录
- ///
- public bool IsAuditLogEnabled { get; set; }
- ///
/// 审计日志索引设置
///
public IndexSettings AuditLogSettings { get; set; }
///
- /// 是否启用安全日志记录
- ///
- public bool IsSecurityLogEnabled { get; set; }
- ///
/// 安全日志索引设置
///
public IndexSettings SecurityLogSettings { get; set; }
@@ -33,8 +25,8 @@ public class AbpAuditLoggingElasticsearchOptions
public AbpAuditLoggingElasticsearchOptions()
{
IndexPrefix = DefaultIndexPrefix;
- IsAuditLogEnabled = true;
ThrowIfIndexInitFailed = true;
+
AuditLogSettings = new IndexSettings()
{
NumberOfReplicas = 1,
@@ -55,7 +47,7 @@ public class AbpAuditLoggingElasticsearchOptions
},
}
};
- IsSecurityLogEnabled = true;
+
SecurityLogSettings = new IndexSettings();
}
}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchAuditLogManager.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchAuditLogManager.cs
index f3276e0cb..bd5beee38 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchAuditLogManager.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchAuditLogManager.cs
@@ -8,11 +8,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using Volo.Abp;
-using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
@@ -21,12 +18,9 @@ namespace LINGYUN.Abp.AuditLogging.Elasticsearch;
[Dependency(ReplaceServices = true)]
public class ElasticsearchAuditLogManager : IAuditLogManager, ITransientDependency
{
- private readonly AbpAuditingOptions _auditingOptions;
private readonly AbpElasticsearchOptions _elasticsearchOptions;
- private readonly AbpAuditLoggingElasticsearchOptions _loggingEsOptions;
private readonly IIndexNameNormalizer _indexNameNormalizer;
private readonly IElasticsearchClientFactory _clientFactory;
- private readonly IAuditLogInfoToAuditLogConverter _converter;
private readonly IClock _clock;
public ILogger Logger { protected get; set; }
@@ -35,18 +29,12 @@ public class ElasticsearchAuditLogManager : IAuditLogManager, ITransientDependen
IClock clock,
IIndexNameNormalizer indexNameNormalizer,
IOptions elasticsearchOptions,
- IElasticsearchClientFactory clientFactory,
- IOptions auditingOptions,
- IAuditLogInfoToAuditLogConverter converter,
- IOptionsMonitor loggingEsOptions)
+ IElasticsearchClientFactory clientFactory)
{
_clock = clock;
- _converter = converter;
_clientFactory = clientFactory;
- _auditingOptions = auditingOptions.Value;
_elasticsearchOptions = elasticsearchOptions.Value;
_indexNameNormalizer = indexNameNormalizer;
- _loggingEsOptions = loggingEsOptions.CurrentValue;
Logger = NullLogger.Instance;
}
@@ -221,81 +209,6 @@ public class ElasticsearchAuditLogManager : IAuditLogManager, ITransientDependen
cancellationToken);
}
- public async virtual Task SaveAsync(
- AuditLogInfo auditInfo,
- CancellationToken cancellationToken = default)
- {
- if (!_loggingEsOptions.IsAuditLogEnabled)
- {
- Logger.LogInformation(auditInfo.ToString());
- return "";
- }
-
- if (!_auditingOptions.HideErrors)
- {
- return await SaveLogAsync(auditInfo, cancellationToken);
- }
-
- try
- {
- return await SaveLogAsync(auditInfo, cancellationToken);
- }
- catch (Exception ex)
- {
- Logger.LogWarning("Could not save the audit log object: " + Environment.NewLine + auditInfo.ToString());
- Logger.LogException(ex, LogLevel.Error);
- }
- return "";
- }
-
- protected async virtual Task SaveLogAsync(
- AuditLogInfo auditLogInfo,
- CancellationToken cancellationToken = default)
- {
- var client = _clientFactory.Create();
-
- var auditLog = await _converter.ConvertAsync(auditLogInfo);
-
- //var response = await client.IndexAsync(
- // auditLog,
- // (x) => x.Index(CreateIndex())
- // .Id(auditLog.Id),
- // cancellationToken);
-
- // 使用 Bulk 命令传输可能存在参数庞大的日志结构
- var response = await client.BulkAsync(
- dsl => dsl.Index(CreateIndex())
- .Create(auditLog, ct => ct.Id(auditLog.Id)));
- if (!response.IsValidResponse)
- {
- if (response.TryGetOriginalException(out var ex))
- {
- throw ex;
- }
- else if (response.ElasticsearchServerError != null)
- {
- throw new AbpException(response.ElasticsearchServerError.ToString());
- }
- else if (response.ItemsWithErrors.Any())
- {
- var reasonBuilder = new StringBuilder();
- foreach (var itemError in response.ItemsWithErrors)
- {
- if (itemError.Error?.Reason.IsNullOrWhiteSpace() == false)
- {
- reasonBuilder.AppendLine(itemError.Error.Reason);
- }
- }
- if (reasonBuilder.Length > 0)
- {
- throw new AbpException(reasonBuilder.ToString());
- }
- }
- }
-
- return response.Items?.FirstOrDefault()?.Id;
- }
-
protected virtual List BuildQueryDescriptor(
DateTime? startTime = null,
DateTime? endTime = null,
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchAuditLogWriter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchAuditLogWriter.cs
new file mode 100644
index 000000000..c88aa3d51
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchAuditLogWriter.cs
@@ -0,0 +1,114 @@
+using Elastic.Clients.Elasticsearch;
+using Elastic.Clients.Elasticsearch.Core.Bulk;
+using LINGYUN.Abp.Elasticsearch;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Auditing;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.AuditLogging.Elasticsearch;
+
+[Dependency(ReplaceServices = true)]
+public class ElasticsearchAuditLogWriter : IAuditLogWriter, ITransientDependency
+{
+ private readonly IAuditLogInfoToAuditLogConverter _auditLogConverter;
+ private readonly IElasticsearchClientFactory _clientFactory;
+ private readonly IIndexNameNormalizer _indexNameNormalizer;
+
+ private readonly ILogger _logger;
+
+ public ElasticsearchAuditLogWriter(
+ IAuditLogInfoToAuditLogConverter auditLogConverter,
+ IElasticsearchClientFactory clientFactory,
+ IIndexNameNormalizer indexNameNormalizer,
+ ILogger logger)
+ {
+ _auditLogConverter = auditLogConverter;
+ _clientFactory = clientFactory;
+ _indexNameNormalizer = indexNameNormalizer;
+ _logger = logger;
+ }
+
+ public async virtual Task WriteAsync(AuditLogInfo auditLogInfo, CancellationToken cancellationToken = default)
+ {
+ var client = _clientFactory.Create();
+ var auditLog = await _auditLogConverter.ConvertAsync(auditLogInfo);
+ var response = await client.IndexAsync(
+ auditLog,
+ dsl => dsl.Index(CreateIndex())
+ .Id(auditLog.Id),
+ cancellationToken);
+
+ if (!response.IsValidResponse)
+ {
+ _logger.LogWarning("Could not save the audit log object: " + Environment.NewLine + auditLog.ToString());
+ if (response.TryGetOriginalException(out var ex))
+ {
+ _logger.LogWarning(ex, ex.Message);
+ }
+ else if (response.ElasticsearchServerError != null)
+ {
+ _logger.LogWarning(response.ElasticsearchServerError.ToString());
+ }
+ }
+ }
+
+ public async virtual Task BulkWriteAsync(IEnumerable auditLogInfos, CancellationToken cancellationToken = default)
+ {
+ if (!auditLogInfos.Any())
+ {
+ return;
+ }
+
+ var client = _clientFactory.Create();
+
+ var indexName = CreateIndex();
+
+ var bulkOperations = new List();
+ foreach (var auditLogInfo in auditLogInfos)
+ {
+ var auditLog = await _auditLogConverter.ConvertAsync(auditLogInfo);
+ bulkOperations.Add(new BulkCreateOperation(auditLog)
+ {
+ Id = auditLog.Id.ToString()
+ });
+ }
+
+ var bulkRequest = new BulkRequest
+ {
+ Operations = [.. bulkOperations],
+ Index = indexName
+ };
+
+ var response = await client.BulkAsync(bulkRequest, cancellationToken);
+
+ if (!response.IsValidResponse)
+ {
+ await HandleBulkErrorsAsync(response, auditLogInfos);
+ }
+ }
+
+ private Task HandleBulkErrorsAsync(BulkResponse response, IEnumerable auditLogInfos)
+ {
+ foreach (var itemWithError in response.ItemsWithErrors)
+ {
+ _logger.LogError($"Failed to write audit log: {itemWithError.Error?.Reason}");
+ }
+
+ foreach (var auditLog in auditLogInfos)
+ {
+ _logger.LogInformation(auditLog.ToString());
+ }
+
+ return Task.CompletedTask;
+ }
+
+ protected virtual string CreateIndex()
+ {
+ return _indexNameNormalizer.NormalizeIndex("audit-log");
+ }
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchSecurityLogManager.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchSecurityLogManager.cs
index 396bdd4ab..5a5a72930 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchSecurityLogManager.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchSecurityLogManager.cs
@@ -10,8 +10,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
-using Volo.Abp.Guids;
-using Volo.Abp.SecurityLog;
using Volo.Abp.Timing;
namespace LINGYUN.Abp.AuditLogging.Elasticsearch;
@@ -19,11 +17,8 @@ namespace LINGYUN.Abp.AuditLogging.Elasticsearch;
[Dependency(ReplaceServices = true)]
public class ElasticsearchSecurityLogManager : ISecurityLogManager, ITransientDependency
{
- private readonly AbpSecurityLogOptions _securityLogOptions;
private readonly AbpElasticsearchOptions _elasticsearchOptions;
- private readonly AbpAuditLoggingElasticsearchOptions _loggingEsOptions;
private readonly IIndexNameNormalizer _indexNameNormalizer;
- private readonly IGuidGenerator _guidGenerator;
private readonly IElasticsearchClientFactory _clientFactory;
private readonly IClock _clock;
@@ -31,67 +26,18 @@ public class ElasticsearchSecurityLogManager : ISecurityLogManager, ITransientDe
public ElasticsearchSecurityLogManager(
IClock clock,
- IGuidGenerator guidGenerator,
IIndexNameNormalizer indexNameNormalizer,
- IOptions securityLogOptions,
IOptions elasticsearchOptions,
- IElasticsearchClientFactory clientFactory,
- IOptionsMonitor loggingEsOptions)
+ IElasticsearchClientFactory clientFactory)
{
_clock = clock;
- _guidGenerator = guidGenerator;
_clientFactory = clientFactory;
_indexNameNormalizer = indexNameNormalizer;
- _securityLogOptions = securityLogOptions.Value;
_elasticsearchOptions = elasticsearchOptions.Value;
- _loggingEsOptions = loggingEsOptions.CurrentValue;
Logger = NullLogger.Instance;
}
- public async virtual Task SaveAsync(
- SecurityLogInfo securityLogInfo,
- CancellationToken cancellationToken = default)
- {
- // TODO: 框架不把这玩意儿放在 ISecurityLogManager?
- if (!_securityLogOptions.IsEnabled)
- {
- return;
- }
-
-
- if (!_loggingEsOptions.IsSecurityLogEnabled)
- {
- Logger.LogInformation(securityLogInfo.ToString());
- return;
- }
-
- var client = _clientFactory.Create();
-
- var securityLog = new SecurityLog(
- _guidGenerator.Create(),
- securityLogInfo);
-
- var response = await client.IndexAsync(
- securityLog,
- (x) => x.Index(CreateIndex())
- .Id(securityLog.Id),
- cancellationToken);
-
- if (!response.IsValidResponse)
- {
- Logger.LogWarning("Could not save the security log object: " + Environment.NewLine + securityLogInfo.ToString());
- if (response.TryGetOriginalException(out var ex))
- {
- Logger.LogWarning(ex, ex.Message);
- }
- else if (response.ElasticsearchServerError != null)
- {
- Logger.LogWarning(response.ElasticsearchServerError.ToString());
- }
- }
- }
-
public async virtual Task GetAsync(
Guid id,
bool includeDetails = false,
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchSecurityLogWriter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchSecurityLogWriter.cs
new file mode 100644
index 000000000..20f9e56b0
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/ElasticsearchSecurityLogWriter.cs
@@ -0,0 +1,122 @@
+using Elastic.Clients.Elasticsearch;
+using Elastic.Clients.Elasticsearch.Core.Bulk;
+using LINGYUN.Abp.Elasticsearch;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Guids;
+using Volo.Abp.SecurityLog;
+
+namespace LINGYUN.Abp.AuditLogging.Elasticsearch;
+
+[Dependency(ReplaceServices = true)]
+public class ElasticsearchSecurityLogWriter : ISecurityLogWriter, ITransientDependency
+{
+ private readonly IElasticsearchClientFactory _clientFactory;
+ private readonly IIndexNameNormalizer _indexNameNormalizer;
+ private readonly IGuidGenerator _guidGenerator;
+
+ private readonly ILogger _logger;
+
+ public ElasticsearchSecurityLogWriter(
+ IElasticsearchClientFactory clientFactory,
+ IIndexNameNormalizer indexNameNormalizer,
+ IGuidGenerator guidGenerator,
+ ILogger logger)
+ {
+ _clientFactory = clientFactory;
+ _indexNameNormalizer = indexNameNormalizer;
+ _guidGenerator = guidGenerator;
+ _logger = logger;
+ }
+
+ public async virtual Task WriteAsync(SecurityLogInfo securityLogInfo, CancellationToken cancellationToken = default)
+ {
+ var client = _clientFactory.Create();
+
+ var securityLog = new SecurityLog(
+ _guidGenerator.Create(),
+ securityLogInfo);
+
+ var response = await client.IndexAsync(
+ securityLog,
+ dsl => dsl.Index(CreateIndex())
+ .Id(securityLog.Id),
+ cancellationToken);
+
+ if (!response.IsValidResponse)
+ {
+ _logger.LogWarning("Could not save the security log object: " + Environment.NewLine + securityLog.ToString());
+ if (response.TryGetOriginalException(out var ex))
+ {
+ _logger.LogWarning(ex, ex.Message);
+ }
+ else if (response.ElasticsearchServerError != null)
+ {
+ _logger.LogWarning(response.ElasticsearchServerError.ToString());
+ }
+ }
+ }
+
+ public async virtual Task BulkWriteAsync(IEnumerable securityLogInfos, CancellationToken cancellationToken = default)
+ {
+ if (!securityLogInfos.Any())
+ {
+ return;
+ }
+
+ var client = _clientFactory.Create();
+
+ var indexName = CreateIndex();
+
+ var bulkOperations = new List();
+ foreach (var securityLogInfo in securityLogInfos)
+ {
+ var securityLog = new SecurityLog(
+ _guidGenerator.Create(),
+ securityLogInfo);
+
+ bulkOperations.Add(new BulkCreateOperation(securityLog)
+ {
+ Id = securityLog.Id.ToString()
+ });
+ }
+
+ var bulkRequest = new BulkRequest
+ {
+ Operations = [.. bulkOperations],
+ Index = indexName
+ };
+
+ var response = await client.BulkAsync(bulkRequest, cancellationToken);
+
+ if (!response.IsValidResponse)
+ {
+ await HandleBulkErrorsAsync(response, securityLogInfos);
+ }
+ }
+
+ private Task HandleBulkErrorsAsync(BulkResponse response, IEnumerable securityLogInfos)
+ {
+ foreach (var itemWithError in response.ItemsWithErrors)
+ {
+ _logger.LogError($"Failed to write security log: {itemWithError.Error?.Reason}");
+ }
+
+ foreach (var auditLog in securityLogInfos)
+ {
+ _logger.LogInformation(auditLog.ToString());
+ }
+
+ return Task.CompletedTask;
+ }
+
+ protected virtual string CreateIndex()
+ {
+ return _indexNameNormalizer.NormalizeIndex("security-log");
+ }
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/AuditLogManager.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/AuditLogManager.cs
index b254d10ca..c803e4525 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/AuditLogManager.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/AuditLogManager.cs
@@ -1,12 +1,8 @@
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Microsoft.Extensions.Options;
-using System;
+using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
-using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;
@@ -20,25 +16,15 @@ public class AuditLogManager : IAuditLogManager, ITransientDependency
protected IObjectMapper ObjectMapper { get; }
protected IAuditLogRepository AuditLogRepository { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
- protected AbpAuditingOptions Options { get; }
- protected IAuditLogInfoToAuditLogConverter Converter { get; }
-
- public ILogger Logger { protected get; set; }
public AuditLogManager(
IAuditLogRepository auditLogRepository,
IUnitOfWorkManager unitOfWorkManager,
- IOptions options,
- IAuditLogInfoToAuditLogConverter converter,
IObjectMapper objectMapper)
{
ObjectMapper = objectMapper;
AuditLogRepository = auditLogRepository;
UnitOfWorkManager = unitOfWorkManager;
- Converter = converter;
- Options = options.Value;
-
- Logger = NullLogger.Instance;
}
@@ -149,41 +135,4 @@ public class AuditLogManager : IAuditLogManager, ITransientDependency
await uow.CompleteAsync();
}
}
-
- public async virtual Task SaveAsync(
- AuditLogInfo auditInfo,
- CancellationToken cancellationToken = default)
- {
- if (!Options.HideErrors)
- {
- return await SaveLogAsync(auditInfo, cancellationToken);
- }
-
- try
- {
- return await SaveLogAsync(auditInfo, cancellationToken);
- }
- catch (Exception ex)
- {
- Logger.LogWarning("Could not save the audit log object: " + Environment.NewLine + auditInfo.ToString());
- Logger.LogException(ex, LogLevel.Error);
- }
- return "";
- }
-
- protected async virtual Task SaveLogAsync(
- AuditLogInfo auditInfo,
- CancellationToken cancellationToken = default)
- {
- using (var uow = UnitOfWorkManager.Begin(true))
- {
- var auditLog = await AuditLogRepository.InsertAsync(
- await Converter.ConvertAsync(auditInfo),
- false,
- cancellationToken);
- await uow.CompleteAsync();
-
- return auditLog.Id.ToString();
- }
- }
}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogWriter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogWriter.cs
new file mode 100644
index 000000000..df0181d5b
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogWriter.cs
@@ -0,0 +1,62 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Auditing;
+using Volo.Abp.AuditLogging;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Guids;
+using Volo.Abp.Uow;
+using IVoloAuditLogInfoToAuditLogConverter = Volo.Abp.AuditLogging.IAuditLogInfoToAuditLogConverter;
+using VoloAuditLog = Volo.Abp.AuditLogging.AuditLog;
+
+namespace LINGYUN.Abp.AuditLogging.EntityFrameworkCore;
+
+[Dependency(ReplaceServices = true)]
+public class EfCoreAuditLogWriter : IAuditLogWriter, ITransientDependency
+{
+ protected IVoloAuditLogInfoToAuditLogConverter AuditLogConverter { get; }
+ protected IAuditLogRepository AuditLogRepository { get; }
+ protected IUnitOfWorkManager UnitOfWorkManager { get; }
+ protected IGuidGenerator GuidGenerator { get; }
+
+ public EfCoreAuditLogWriter(
+ IVoloAuditLogInfoToAuditLogConverter auditLogConverter,
+ IAuditLogRepository auditLogRepository,
+ IUnitOfWorkManager unitOfWorkManager,
+ IGuidGenerator guidGenerator)
+ {
+ AuditLogConverter = auditLogConverter;
+ AuditLogRepository = auditLogRepository;
+ UnitOfWorkManager = unitOfWorkManager;
+ GuidGenerator = guidGenerator;
+ }
+
+ public async virtual Task WriteAsync(AuditLogInfo auditLogInfo, CancellationToken cancellationToken = default)
+ {
+ using (var uow = UnitOfWorkManager.Begin(true))
+ {
+ var auditLog = await AuditLogConverter.ConvertAsync(auditLogInfo);
+
+ await AuditLogRepository.InsertAsync(auditLog);
+
+ await uow.CompleteAsync();
+ }
+ }
+
+ public async virtual Task BulkWriteAsync(IEnumerable auditLogInfos, CancellationToken cancellationToken = default)
+ {
+ using (var uow = UnitOfWorkManager.Begin(true))
+ {
+ var auditLogs = new List();
+ foreach (var auditLogInfo in auditLogInfos)
+ {
+ var auditLog = await AuditLogConverter.ConvertAsync(auditLogInfo);
+ auditLogs.Add(auditLog);
+ }
+
+ await AuditLogRepository.InsertManyAsync(auditLogs);
+
+ await uow.CompleteAsync();
+ }
+ }
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/EfCoreSecurityLogWriter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/EfCoreSecurityLogWriter.cs
new file mode 100644
index 000000000..d9b27a0f5
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/EfCoreSecurityLogWriter.cs
@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Guids;
+using Volo.Abp.Identity;
+using Volo.Abp.SecurityLog;
+using Volo.Abp.Uow;
+
+namespace LINGYUN.Abp.AuditLogging.EntityFrameworkCore;
+
+[Dependency(ReplaceServices = true)]
+public class EfCoreSecurityLogWriter : ISecurityLogWriter, ITransientDependency
+{
+ protected IIdentitySecurityLogRepository IdentitySecurityLogRepository { get; }
+ protected IUnitOfWorkManager UnitOfWorkManager { get; }
+ protected IGuidGenerator GuidGenerator { get; }
+
+ public EfCoreSecurityLogWriter(
+ IIdentitySecurityLogRepository identitySecurityLogRepository,
+ IUnitOfWorkManager unitOfWorkManager,
+ IGuidGenerator guidGenerator)
+ {
+ IdentitySecurityLogRepository = identitySecurityLogRepository;
+ UnitOfWorkManager = unitOfWorkManager;
+ GuidGenerator = guidGenerator;
+ }
+
+ public async virtual Task BulkWriteAsync(IEnumerable securityLogInfos, CancellationToken cancellationToken = default)
+ {
+ using (var uow = UnitOfWorkManager.Begin(requiresNew: true))
+ {
+ var securityLogs = securityLogInfos.Select(securityLogInfo =>
+ new IdentitySecurityLog(GuidGenerator, securityLogInfo));
+
+ await IdentitySecurityLogRepository.InsertManyAsync(
+ securityLogs,
+ false,
+ cancellationToken);
+
+ await uow.CompleteAsync();
+ }
+ }
+
+ public async virtual Task WriteAsync(SecurityLogInfo securityLogInfo, CancellationToken cancellationToken = default)
+ {
+ using (var uow = UnitOfWorkManager.Begin(requiresNew: true))
+ {
+ await IdentitySecurityLogRepository.InsertAsync(
+ new IdentitySecurityLog(GuidGenerator, securityLogInfo),
+ false,
+ cancellationToken);
+ await uow.CompleteAsync();
+ }
+ }
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/SecurityLogManager.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/SecurityLogManager.cs
index 759350042..00df36963 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/SecurityLogManager.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/SecurityLogManager.cs
@@ -1,14 +1,10 @@
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using System;
+using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
-using Volo.Abp.Guids;
using Volo.Abp.Identity;
using Volo.Abp.ObjectMapping;
-using Volo.Abp.SecurityLog;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.AuditLogging.EntityFrameworkCore;
@@ -16,26 +12,17 @@ namespace LINGYUN.Abp.AuditLogging.EntityFrameworkCore;
[Dependency(ReplaceServices = true)]
public class SecurityLogManager : ISecurityLogManager, ITransientDependency
{
- public ILogger Logger { get; set; }
protected IObjectMapper ObjectMapper { get; }
- protected AbpSecurityLogOptions SecurityLogOptions { get; }
protected IIdentitySecurityLogRepository IdentitySecurityLogRepository { get; }
- protected IGuidGenerator GuidGenerator { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
public SecurityLogManager(
IObjectMapper objectMapper,
- ILogger logger,
- IOptions securityLogOptions,
IIdentitySecurityLogRepository identitySecurityLogRepository,
- IGuidGenerator guidGenerator,
IUnitOfWorkManager unitOfWorkManager)
{
- Logger = logger;
ObjectMapper = objectMapper;
- SecurityLogOptions = securityLogOptions.Value;
IdentitySecurityLogRepository = identitySecurityLogRepository;
- GuidGenerator = guidGenerator;
UnitOfWorkManager = unitOfWorkManager;
}
@@ -49,25 +36,6 @@ public class SecurityLogManager : ISecurityLogManager, ITransientDependency
}
}
- public async virtual Task SaveAsync(
- SecurityLogInfo securityLogInfo,
- CancellationToken cancellationToken = default)
- {
- if (!SecurityLogOptions.IsEnabled)
- {
- return;
- }
-
- using (var uow = UnitOfWorkManager.Begin(requiresNew: true))
- {
- await IdentitySecurityLogRepository.InsertAsync(
- new IdentitySecurityLog(GuidGenerator, securityLogInfo),
- false,
- cancellationToken);
- await uow.CompleteAsync();
- }
- }
-
public async virtual Task GetAsync(
Guid id,
bool includeDetails = false,
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationAuditingStore.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationAuditingStore.cs
index ca078097d..18545ca72 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationAuditingStore.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationAuditingStore.cs
@@ -1,4 +1,5 @@
using LINGYUN.Abp.IP.Location;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
@@ -12,8 +13,10 @@ public class IPLocationAuditingStore : AuditingStore
public IPLocationAuditingStore(
IOptionsMonitor options,
IIPLocationResolver iPLocationResolver,
- IAuditLogManager manager)
- : base(manager)
+ IOptionsMonitor loggingOptions,
+ IAuditLogQueue auditLogQueue,
+ ILogger logger)
+ : base(loggingOptions, auditLogQueue, logger)
{
_options = options.CurrentValue;
_iPLocationResolver = iPLocationResolver;
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationSecurityLogStore.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationSecurityLogStore.cs
index ca65cfaed..c961d782f 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationSecurityLogStore.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN/Abp/AuditLogging/IP/Location/IPLocationSecurityLogStore.cs
@@ -1,4 +1,5 @@
using LINGYUN.Abp.IP.Location;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
@@ -13,8 +14,11 @@ public class IPLocationSecurityLogStore : SecurityLogStore
public IPLocationSecurityLogStore(
IOptionsMonitor options,
IIPLocationResolver iPLocationResolver,
- ISecurityLogManager manager)
- : base(manager)
+ IOptionsMonitor securityLogOptions,
+ IOptionsMonitor loggingOptions,
+ ISecurityLogQueue securityLogQueue,
+ ILogger logger)
+ : base(securityLogOptions, loggingOptions, securityLogQueue, logger)
{
_options = options.CurrentValue;
_iPLocationResolver = iPLocationResolver;
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN.Abp.AuditLogging.csproj b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN.Abp.AuditLogging.csproj
index 3684d96a7..e99d9c8d5 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN.Abp.AuditLogging.csproj
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN.Abp.AuditLogging.csproj
@@ -19,6 +19,7 @@
+
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AbpAuditLoggingModule.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AbpAuditLoggingModule.cs
index 1de4e8c42..7fcdf53f9 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AbpAuditLoggingModule.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AbpAuditLoggingModule.cs
@@ -1,9 +1,15 @@
-using System.Collections.Generic;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp;
using Volo.Abp.Auditing;
+using Volo.Abp.DependencyInjection;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.Guids;
using Volo.Abp.Modularity;
+using Volo.Abp.Threading;
namespace LINGYUN.Abp.AuditLogging;
@@ -13,12 +19,71 @@ namespace LINGYUN.Abp.AuditLogging;
typeof(AbpExceptionHandlingModule))]
public class AbpAuditLoggingModule : AbpModule
{
+ private readonly CancellationTokenSource _cancellationTokenSource = new();
public override void ConfigureServices(ServiceConfigurationContext context)
{
+ var configuration = context.Services.GetConfiguration();
+ Configure(configuration.GetSection("AuditLogging"));
+
Configure(options =>
{
options.IgnoredTypes.AddIfNotContains(typeof(CancellationToken));
options.IgnoredTypes.AddIfNotContains(typeof(CancellationTokenSource));
});
}
+
+ public override void OnApplicationInitialization(ApplicationInitializationContext context)
+ {
+ AsyncHelper.RunSync(() => OnApplicationInitializationAsync(context));
+ }
+
+ public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
+ {
+ var rootServiceProvider = context.ServiceProvider.GetRequiredService();
+ var options = context.ServiceProvider.GetRequiredService>();
+
+ if (options.Value.UseAuditLogQueue)
+ {
+ var auditLogQueue = rootServiceProvider.GetRequiredService();
+ if (auditLogQueue is AuditLogQueue queue1)
+ {
+ await queue1.StartAsync(_cancellationTokenSource.Token);
+ }
+ }
+
+ if (options.Value.UseSecurityLogQueue)
+ {
+ var securityLogQueue = rootServiceProvider.GetRequiredService();
+ if (securityLogQueue is SecurityLogQueue queue2)
+ {
+ await queue2.StartAsync(_cancellationTokenSource.Token);
+ }
+ }
+ }
+
+ public async override Task OnApplicationShutdownAsync(ApplicationShutdownContext context)
+ {
+ var rootServiceProvider = context.ServiceProvider.GetRequiredService();
+ var options = context.ServiceProvider.GetRequiredService>();
+
+ if (options.Value.UseAuditLogQueue)
+ {
+ var auditLogQueue = rootServiceProvider.GetRequiredService();
+ if (auditLogQueue is AuditLogQueue queue1)
+ {
+ await queue1.StopAsync(_cancellationTokenSource.Token);
+ }
+ }
+
+ if (options.Value.UseSecurityLogQueue)
+ {
+ var securityLogQueue = rootServiceProvider.GetRequiredService();
+ if (securityLogQueue is SecurityLogQueue queue2)
+ {
+ await queue2.StopAsync(_cancellationTokenSource.Token);
+ }
+ }
+
+ _cancellationTokenSource.Cancel();
+ }
}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AbpAuditLoggingOptions.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AbpAuditLoggingOptions.cs
new file mode 100644
index 000000000..d19d06fe3
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AbpAuditLoggingOptions.cs
@@ -0,0 +1,54 @@
+namespace LINGYUN.Abp.AuditLogging;
+public class AbpAuditLoggingOptions
+{
+ ///
+ /// 是否启用审计日志记录
+ ///
+ public bool IsAuditLogEnabled { get; set; }
+ ///
+ /// 使用审计日志队列
+ ///
+ ///
+ /// 不启用队列则直接写入到持久化设施
+ ///
+ public bool UseAuditLogQueue { get; set; }
+ ///
+ /// 审计日志最大队列大小
+ ///
+ public int MaxAuditLogQueueSize { get; set; }
+ ///
+ /// 一次处理审计日志队列大小
+ ///
+ public int BatchAuditLogSize { get; set; }
+ ///
+ /// 是否启用安全日志记录
+ ///
+ public bool IsSecurityLogEnabled { get; set; }
+ ///
+ /// 使用安全日志队列
+ ///
+ ///
+ /// 不启用队列则直接写入到持久化设施
+ ///
+ public bool UseSecurityLogQueue { get; set; }
+ ///
+ /// 安全日志最大队列大小
+ ///
+ public int MaxSecurityLogQueueSize { get; set; }
+ ///
+ /// 一次处理安全日志队列大小
+ ///
+ public int BatchSecurityLogSize { get; set; }
+ public AbpAuditLoggingOptions()
+ {
+ IsAuditLogEnabled = true;
+ UseAuditLogQueue = true;
+ BatchAuditLogSize = 100;
+ MaxAuditLogQueueSize = 10000;
+
+ IsSecurityLogEnabled = true;
+ UseSecurityLogQueue = true;
+ BatchSecurityLogSize = 100;
+ MaxSecurityLogQueueSize = 10000;
+ }
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/AuditLogInfoToAuditLogConverter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLogInfoToAuditLogConverter.cs
similarity index 100%
rename from aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/AuditLogInfoToAuditLogConverter.cs
rename to aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLogInfoToAuditLogConverter.cs
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLogQueue.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLogQueue.cs
new file mode 100644
index 000000000..99ee5cc85
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLogQueue.cs
@@ -0,0 +1,50 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Auditing;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.MultiTenancy;
+
+namespace LINGYUN.Abp.AuditLogging;
+public class AuditLogQueue : AuditLoggingQueue, IAuditLogQueue, ISingletonDependency
+{
+ private readonly IAuditLogWriter _auditLogWriter;
+ private readonly ICurrentTenant _currentTenant;
+ public AuditLogQueue(
+ IOptions options,
+ IAuditLogWriter auditLogWriter,
+ ICurrentTenant currentTenant,
+ ILogger logger)
+ : base(
+ "AuditLog",
+ options.Value.MaxAuditLogQueueSize,
+ options.Value.BatchAuditLogSize,
+ logger)
+ {
+ _auditLogWriter = auditLogWriter;
+ _currentTenant = currentTenant;
+ }
+
+ protected async override Task BulkWriteAsync(IEnumerable auditLogInfos, CancellationToken cancellationToken = default)
+ {
+ var tenantAuditlogGroup = auditLogInfos.GroupBy(x => x.ImpersonatorTenantId ?? x.TenantId);
+ foreach (var tenantAuditlogs in tenantAuditlogGroup)
+ {
+ using (_currentTenant.Change(tenantAuditlogs.Key))
+ {
+ await _auditLogWriter.BulkWriteAsync(tenantAuditlogs, cancellationToken);
+ }
+ }
+ }
+
+ protected async override Task WriteAsync(AuditLogInfo auditLogInfo, CancellationToken cancellationToken = default)
+ {
+ using (_currentTenant.Change(auditLogInfo.ImpersonatorTenantId ?? auditLogInfo.TenantId))
+ {
+ await _auditLogWriter.WriteAsync(auditLogInfo, cancellationToken);
+ }
+ }
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLoggingQueue.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLoggingQueue.cs
new file mode 100644
index 000000000..3b615f6f2
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLoggingQueue.cs
@@ -0,0 +1,196 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.AuditLogging;
+public abstract class AuditLoggingQueue
+{
+ private readonly ILogger> _logger;
+ private readonly Channel _channel;
+ private readonly string _logName;
+ private readonly int _batchSize;
+ private readonly int _maxConcurrency;
+
+ private volatile Task _consumerTask;
+ private readonly SemaphoreSlim _flushSemaphore;
+ private readonly CancellationTokenSource _cts = new CancellationTokenSource();
+ protected AuditLoggingQueue(
+ string logName,
+ int maxQueueSize,
+ int batchSize,
+ ILogger> logger)
+ {
+ _logName = logName;
+ _batchSize = batchSize;
+ _logger = logger;
+
+ var channelOptions = new BoundedChannelOptions(maxQueueSize)
+ {
+ FullMode = BoundedChannelFullMode.Wait,
+ SingleWriter = false,
+ SingleReader = true,
+ };
+ _channel = Channel.CreateBounded(channelOptions);
+
+ var calculatedConcurrency = (int)Math.Ceiling(Math.Max(1, maxQueueSize) / (double)Math.Max(1, batchSize));
+ var defaultConcurrency = Environment.ProcessorCount * 2;
+ _maxConcurrency = Math.Min(calculatedConcurrency, defaultConcurrency);
+ _flushSemaphore = new SemaphoreSlim(_maxConcurrency, _maxConcurrency);
+ }
+
+ public virtual Task EnqueueAsync(TLog log, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ if (!_channel.Writer.TryWrite(log))
+ {
+ _logger.LogWarning("{logName} channel is full; {logName} is recorded in the log.", _logName, _logName);
+ _logger.LogInformation(log!.ToString());
+ }
+
+ return Task.CompletedTask;
+ }
+ catch (ChannelClosedException)
+ {
+ _logger.LogWarning("{logName} channel is closed; dropping it.", _logName);
+ }
+ catch (OperationCanceledException)
+ {
+ _logger.LogDebug("EnqueueAsync was canceled while waiting to write to {logName} channel.", _logName);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Unexpected exception while enqueuing {logName}.", _logName);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ public virtual Task StartAsync(CancellationToken cancellationToken)
+ {
+ _consumerTask = Task.Factory.StartNew(
+ () => ConsumeBatchesAsync(),
+ CancellationToken.None,
+ TaskCreationOptions.LongRunning,
+ TaskScheduler.Default)
+ .Unwrap();
+
+ return Task.CompletedTask;
+ }
+
+ public async virtual Task StopAsync(CancellationToken cancellationToken)
+ {
+ _channel.Writer.TryComplete();
+
+ if (_consumerTask != null)
+ {
+ try
+ {
+ await Task.WhenAny(_consumerTask, Task.Delay(TimeSpan.FromSeconds(5), cancellationToken));
+ _cts.Cancel();
+ _logger.LogInformation("Stopped consumer loop: {logName}.", _logName);
+ }
+ catch (OperationCanceledException)
+ {
+ _logger.LogWarning("StopAsync was canceled while waiting for consumer loop: {logName} to finish.", _logName);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Exception while stopping consumer loop: {logName}.", _logName);
+ }
+ finally
+ {
+ _cts.Dispose();
+ }
+ }
+ }
+
+ private async Task ConsumeBatchesAsync()
+ {
+ var reader = _channel.Reader;
+ var batchSize = Math.Max(1, _batchSize);
+ var batchSendTaskList = new List(_maxConcurrency * 2);
+
+ _logger.LogInformation("Starting {logName} consumer loop. BatchSize={batchSize}", _logName, batchSize);
+
+ try
+ {
+ while (await reader.WaitToReadAsync(_cts.Token))
+ {
+ var buffer = new List(batchSize);
+
+ while (buffer.Count < batchSize && reader.TryRead(out var item))
+ {
+ buffer.Add(item);
+ }
+
+ if (buffer.Count > 0)
+ {
+ batchSendTaskList.Add(SendBatchAsync(buffer, _cts.Token));
+ if (batchSendTaskList.Count >= _maxConcurrency)
+ {
+ try
+ {
+ var completedTask = await Task.WhenAny(batchSendTaskList);
+ batchSendTaskList.Remove(completedTask);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Background send {logName} task failed.", _logName);
+ }
+ }
+ }
+ }
+
+ await Task.WhenAll(batchSendTaskList);
+ }
+ catch (OperationCanceledException)
+ {
+ // ignore
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Unexpected exception in {logName} consumer loop.", _logName);
+ }
+ }
+
+ private async Task SendBatchAsync(List batch, CancellationToken cancellationToken)
+ {
+ if (batch == null || batch.Count == 0)
+ {
+ return;
+ }
+
+ await _flushSemaphore.WaitAsync(cancellationToken);
+
+ try
+ {
+ if (batch.Count == 1)
+ {
+ await WriteAsync(batch[0], cancellationToken);
+ }
+ else
+ {
+ await BulkWriteAsync(batch, cancellationToken);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ _logger.LogDebug("SendBatchAsync canceled while writing {logName}.", _logName);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to write {logName} batch to Elasticsearch. Items={count}", _logName, batch.Count);
+ }
+ finally
+ {
+ _flushSemaphore.Release();
+ }
+ }
+
+ protected abstract Task WriteAsync(TLog log, CancellationToken cancellationToken = default);
+ protected abstract Task BulkWriteAsync(IEnumerable logs, CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditingStore.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditingStore.cs
index 660b820f8..218672e08 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditingStore.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditingStore.cs
@@ -1,4 +1,6 @@
-using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
@@ -7,16 +9,37 @@ namespace LINGYUN.Abp.AuditLogging;
[Dependency(ReplaceServices = true)]
public class AuditingStore : IAuditingStore, ITransientDependency
{
- private readonly IAuditLogManager _manager;
+ private readonly AbpAuditLoggingOptions _loggingOptions;
+ private readonly IAuditLogWriter _auditLogWriter;
+ private readonly IAuditLogQueue _auditLogQueue;
+ private readonly ILogger _logger;
public AuditingStore(
- IAuditLogManager manager)
+ IOptionsMonitor loggingOptions,
+ IAuditLogWriter auditLogWriter,
+ IAuditLogQueue auditLogQueue,
+ ILogger logger)
{
- _manager = manager;
+ _loggingOptions = loggingOptions.CurrentValue;
+ _auditLogWriter = auditLogWriter;
+ _auditLogQueue = auditLogQueue;
+ _logger = logger;
}
public async virtual Task SaveAsync(AuditLogInfo auditInfo)
{
- await _manager.SaveAsync(auditInfo);
+ if (!_loggingOptions.IsAuditLogEnabled)
+ {
+ _logger.LogInformation(auditInfo.ToString());
+ return;
+ }
+ if (_loggingOptions.UseAuditLogQueue)
+ {
+ await _auditLogQueue.EnqueueAsync(auditInfo);
+ }
+ else
+ {
+ await _auditLogWriter.WriteAsync(auditInfo);
+ }
}
}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/IAuditLogInfoToAuditLogConverter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogInfoToAuditLogConverter.cs
similarity index 100%
rename from aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN/Abp/AuditLogging/Elasticsearch/IAuditLogInfoToAuditLogConverter.cs
rename to aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogInfoToAuditLogConverter.cs
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogManager.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogManager.cs
index e140cdf32..f689a463b 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogManager.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogManager.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
-using Volo.Abp.Auditing;
namespace LINGYUN.Abp.AuditLogging;
@@ -22,10 +21,6 @@ public interface IAuditLogManager
List ids,
CancellationToken cancellationToken = default);
- Task SaveAsync(
- AuditLogInfo auditInfo,
- CancellationToken cancellationToken = default);
-
Task GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogQueue.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogQueue.cs
new file mode 100644
index 000000000..ca22f4312
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogQueue.cs
@@ -0,0 +1,9 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Auditing;
+
+namespace LINGYUN.Abp.AuditLogging;
+public interface IAuditLogQueue
+{
+ Task EnqueueAsync(AuditLogInfo auditLogInfo, CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogWriter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogWriter.cs
new file mode 100644
index 000000000..0fc2fb0b0
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/IAuditLogWriter.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Auditing;
+
+namespace LINGYUN.Abp.AuditLogging;
+public interface IAuditLogWriter
+{
+ Task WriteAsync(AuditLogInfo auditLogInfo, CancellationToken cancellationToken = default);
+
+ Task BulkWriteAsync(IEnumerable auditLogInfos, CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogManager.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogManager.cs
index f8d48320e..e031c0b51 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogManager.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogManager.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using Volo.Abp.SecurityLog;
namespace LINGYUN.Abp.AuditLogging;
@@ -21,10 +20,6 @@ public interface ISecurityLogManager
List ids,
CancellationToken cancellationToken = default);
- Task SaveAsync(
- SecurityLogInfo securityLogInfo,
- CancellationToken cancellationToken = default);
-
Task> GetListAsync(
string? sorting = null,
int maxResultCount = 50,
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogQueue.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogQueue.cs
new file mode 100644
index 000000000..05de095a6
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogQueue.cs
@@ -0,0 +1,9 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.SecurityLog;
+
+namespace LINGYUN.Abp.AuditLogging;
+public interface ISecurityLogQueue
+{
+ Task EnqueueAsync(SecurityLogInfo securityLogInfo, CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogWriter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogWriter.cs
new file mode 100644
index 000000000..ef249b9b5
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/ISecurityLogWriter.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.SecurityLog;
+
+namespace LINGYUN.Abp.AuditLogging;
+public interface ISecurityLogWriter
+{
+ Task WriteAsync(SecurityLogInfo securityLogInfo, CancellationToken cancellationToken = default);
+
+ Task BulkWriteAsync(IEnumerable securityLogInfos, CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/LoggerAuditLogWriter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/LoggerAuditLogWriter.cs
new file mode 100644
index 000000000..873f28be2
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/LoggerAuditLogWriter.cs
@@ -0,0 +1,33 @@
+using Microsoft.Extensions.Logging;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Auditing;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.AuditLogging;
+
+[Dependency(TryRegister = true)]
+public class LoggerAuditLogWriter : IAuditLogWriter, ISingletonDependency
+{
+ private readonly ILogger _logger;
+ public LoggerAuditLogWriter(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public async virtual Task BulkWriteAsync(IEnumerable auditLogInfos, CancellationToken cancellationToken = default)
+ {
+ foreach (var auditLogInfo in auditLogInfos)
+ {
+ await WriteAsync(auditLogInfo, cancellationToken);
+ }
+ }
+
+ public virtual Task WriteAsync(AuditLogInfo auditLogInfo, CancellationToken cancellationToken = default)
+ {
+ _logger.LogInformation(auditLogInfo.ToString());
+
+ return Task.CompletedTask;
+ }
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/LoggerSecurityLogWriter.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/LoggerSecurityLogWriter.cs
new file mode 100644
index 000000000..b19e426a8
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/LoggerSecurityLogWriter.cs
@@ -0,0 +1,33 @@
+using Microsoft.Extensions.Logging;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.SecurityLog;
+
+namespace LINGYUN.Abp.AuditLogging;
+
+[Dependency(TryRegister = true)]
+public class LoggerSecurityLogWriter : ISecurityLogWriter, ISingletonDependency
+{
+ private readonly ILogger _logger;
+ public LoggerSecurityLogWriter(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public async virtual Task BulkWriteAsync(IEnumerable securityLogInfos, CancellationToken cancellationToken = default)
+ {
+ foreach (var securityLogInfo in securityLogInfos)
+ {
+ await WriteAsync(securityLogInfo, cancellationToken);
+ }
+ }
+
+ public virtual Task WriteAsync(SecurityLogInfo securityLogInfo, CancellationToken cancellationToken = default)
+ {
+ _logger.LogInformation(securityLogInfo.ToString());
+
+ return Task.CompletedTask;
+ }
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/SecurityLogQueue.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/SecurityLogQueue.cs
new file mode 100644
index 000000000..e45714962
--- /dev/null
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/SecurityLogQueue.cs
@@ -0,0 +1,50 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.SecurityLog;
+
+namespace LINGYUN.Abp.AuditLogging;
+public class SecurityLogQueue : AuditLoggingQueue, ISecurityLogQueue, ISingletonDependency
+{
+ private readonly ISecurityLogWriter _securityLogWriter;
+ private readonly ICurrentTenant _currentTenant;
+ public SecurityLogQueue(
+ IOptions options,
+ ISecurityLogWriter securityLogWriter,
+ ICurrentTenant currentTenant,
+ ILogger logger)
+ : base(
+ "SecurityLog",
+ options.Value.MaxSecurityLogQueueSize,
+ options.Value.BatchSecurityLogSize,
+ logger)
+ {
+ _securityLogWriter = securityLogWriter;
+ _currentTenant = currentTenant;
+ }
+
+ protected async override Task BulkWriteAsync(IEnumerable securityLogInfos, CancellationToken cancellationToken = default)
+ {
+ var tenantSecurityLogGroup = securityLogInfos.GroupBy(x => x.TenantId);
+ foreach (var tenantSecurityLogs in tenantSecurityLogGroup)
+ {
+ using (_currentTenant.Change(tenantSecurityLogs.Key))
+ {
+ await _securityLogWriter.BulkWriteAsync(tenantSecurityLogs, cancellationToken);
+ }
+ }
+ }
+
+ protected async override Task WriteAsync(SecurityLogInfo securityLogInfo, CancellationToken cancellationToken = default)
+ {
+ using (_currentTenant.Change(securityLogInfo.TenantId))
+ {
+ await _securityLogWriter.WriteAsync(securityLogInfo, cancellationToken);
+ }
+ }
+}
diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/SecurityLogStore.cs b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/SecurityLogStore.cs
index 1918ccc71..6b1642dca 100644
--- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/SecurityLogStore.cs
+++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/SecurityLogStore.cs
@@ -1,4 +1,6 @@
-using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SecurityLog;
@@ -7,16 +9,40 @@ namespace LINGYUN.Abp.AuditLogging;
[Dependency(ReplaceServices = true)]
public class SecurityLogStore : ISecurityLogStore, ITransientDependency
{
- private readonly ISecurityLogManager _manager;
+ private readonly AbpSecurityLogOptions _securityLogOptions;
+ private readonly AbpAuditLoggingOptions _loggingOptions;
+ private readonly ISecurityLogWriter _securityLogWriter;
+ private readonly ISecurityLogQueue _securityLogQueue;
+ private readonly ILogger _logger;
public SecurityLogStore(
- ISecurityLogManager manager)
+ IOptionsMonitor securityLogOptions,
+ IOptionsMonitor loggingOptions,
+ ISecurityLogWriter securityLogWriter,
+ ISecurityLogQueue securityLogQueue,
+ ILogger logger)
{
- _manager = manager;
+ _securityLogOptions = securityLogOptions.CurrentValue;
+ _loggingOptions = loggingOptions.CurrentValue;
+ _securityLogWriter = securityLogWriter;
+ _securityLogQueue = securityLogQueue;
+ _logger = logger;
}
public async virtual Task SaveAsync(SecurityLogInfo securityLogInfo)
{
- await _manager.SaveAsync(securityLogInfo);
+ if (!_loggingOptions.IsAuditLogEnabled || !_securityLogOptions.IsEnabled)
+ {
+ _logger.LogInformation(securityLogInfo.ToString());
+ return;
+ }
+ if (_loggingOptions.UseSecurityLogQueue)
+ {
+ await _securityLogQueue.EnqueueAsync(securityLogInfo);
+ }
+ else
+ {
+ await _securityLogWriter.WriteAsync(securityLogInfo);
+ }
}
}
diff --git a/aspnet-core/framework/auditing/README.md b/aspnet-core/framework/auditing/README.md
index 2f21293a5..91d54667f 100644
--- a/aspnet-core/framework/auditing/README.md
+++ b/aspnet-core/framework/auditing/README.md
@@ -15,8 +15,11 @@
### 存储支持
-- EntityFrameworkCore 实现
-- Elasticsearch 实现
+- EntityFrameworkCore 实现
+- Elasticsearch 实现
+
+> 注意: Elastic库限制, 兼容8.x; 9.x版本, 如需使用10.x版本, 请切换 **Elastic.Clients.Elasticsearch** 为9.x版本
+> 参考: https://www.nuget.org/packages/Elastic.Clients.Elasticsearch#readme-body-tab
## 模块引用
@@ -62,6 +65,17 @@ public class YouProjectModule : AbpModule
"IsEnabledForAnonymousUsers": true, // 是否为匿名用户启用审计日志
"IsEnabledForGetRequests": false, // 是否为GET请求启用审计日志
"ApplicationName": null // 应用程序名称
+ },
+ // 审计日志增强配置
+ "AuditLogging": {
+ "IsAuditLogEnabled": true, // 是否启用审计日志记录
+ "UseAuditLogQueue": true, // 使用审计日志队列, 不启用队列则直接写入到持久化设施
+ "MaxAuditLogQueueSize": 10000, // 审计日志最大队列大小, 默认10000
+ "BatchAuditLogSize": 100, // 一次处理审计日志队列大小, 队列中同时写入100条记录后立即写入到持久化设施中
+ "IsSecurityLogEnabled": true, // 是否启用安全日志记录
+ "UseSecurityLogQueue": true, // 使用安全日志队列, 不启用队列则直接写入到持久化设施
+ "MaxSecurityLogQueueSize": 10000, // 安全日志最大队列大小, 默认10000
+ "BatchSecurityLogSize": 100 // 一次处理安全日志队列大小, 队列中同时写入100条记录后立即写入到持久化设施中
}
}
```
@@ -72,7 +86,8 @@ public class YouProjectModule : AbpModule
{
"AuditLogging": {
"Elasticsearch": {
- "IndexPrefix": "auditlogging" // 索引前缀
+ "IndexPrefix": "auditlogging", // 索引前缀
+ "ThrowIfIndexInitFailed": true // 索引初始化失败抛出异常, 默认为: true, 索引初始化失败后应用程序停止运行
}
}
}
@@ -110,4 +125,4 @@ Configure(options =>
## 特殊说明
- Elasticsearch 实现支持跨租户,将根据租户自动切换索引
-- EntityFrameworkCore 实现主要作为桥梁,具体实现交由 Abp 官方模块管理
+- EntityFrameworkCore 实现主要作为桥梁,具体实现交由 Abp 官方模块管理
\ No newline at end of file
diff --git a/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchTestBase.cs
index f27f8eb41..873443ef1 100644
--- a/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchTestBase.cs
+++ b/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchTestBase.cs
@@ -1,10 +1,4 @@
using LINGYUN.Abp.Tests;
-using Moq.AutoMock;
-using Nest;
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Volo.Abp.Auditing;
namespace LINGYUN.Abp.AuditLogging.Elasticsearch
{
diff --git a/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchTestModule.cs
index a787b3ccc..8fd3da9ff 100644
--- a/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchTestModule.cs
+++ b/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchTestModule.cs
@@ -29,10 +29,10 @@ namespace LINGYUN.Abp.AuditLogging.Elasticsearch
var options = context.ServiceProvider.GetRequiredService>().Value;
var clientFactory = context.ServiceProvider.GetRequiredService();
var client = clientFactory.Create();
- var indicesResponse = client.Cat.Indices(i => i.Index($"{options.IndexPrefix}-security-log"));
- foreach (var index in indicesResponse.Records)
+ var indicesResponse = client.Indices.Get($"{options.IndexPrefix}-security-log");
+ foreach (var index in indicesResponse.Indices)
{
- client.Indices.Delete(index.Index);
+ client.Indices.Delete(index.Key);
}
}
}
diff --git a/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AuditLogManagerTests.cs b/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AuditLogManagerTests.cs
index 507d0f13d..befb33bb1 100644
--- a/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AuditLogManagerTests.cs
+++ b/aspnet-core/tests/LINGYUN.Abp.AuditLogging.Elasticsearch.Tests/LINGYUN/Abp/AuditLogging/Elasticsearch/AuditLogManagerTests.cs
@@ -17,6 +17,7 @@ namespace LINGYUN.Abp.AuditLogging.Elasticsearch
_manager = GetRequiredService();
}
+ [Fact]
public async Task Save_Audit_Log_Should_Be_Find_By_Id()
{
var mock = new AutoMocker();