81 changed files with 3500 additions and 449 deletions
@ -0,0 +1,19 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Json" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\elasticsearch\LINGYUN.Abp.Elasticsearch\LINGYUN.Abp.Elasticsearch.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.AuditLogging\LINGYUN.Abp.AuditLogging.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,20 @@ |
|||||
|
using LINGYUN.Abp.Elasticsearch; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Json; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAuditLoggingModule), |
||||
|
typeof(AbpElasticsearchModule), |
||||
|
typeof(AbpJsonModule))] |
||||
|
public class AbpAuditLoggingElasticsearchModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
Configure<AbpAuditLoggingElasticsearchOptions>(configuration.GetSection("AuditLogging:Elasticsearch")); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
public class AbpAuditLoggingElasticsearchOptions |
||||
|
{ |
||||
|
public const string DefaultIndexPrefix = "auditlogging"; |
||||
|
public string IndexPrefix { get; set; } |
||||
|
|
||||
|
public AbpAuditLoggingElasticsearchOptions() |
||||
|
{ |
||||
|
IndexPrefix = DefaultIndexPrefix; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 LINGYUN.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: true) |
||||
|
: 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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,347 @@ |
|||||
|
using LINGYUN.Abp.Elasticsearch; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Nest; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Net; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class ElasticsearchAuditLogManager : IAuditLogManager, ISingletonDependency |
||||
|
{ |
||||
|
private readonly AbpAuditingOptions _auditingOptions; |
||||
|
private readonly AbpElasticsearchOptions _elasticsearchOptions; |
||||
|
private readonly AbpAuditLoggingElasticsearchOptions _options; |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
private readonly IElasticsearchClientFactory _clientFactory; |
||||
|
private readonly IAuditLogInfoToAuditLogConverter _converter; |
||||
|
|
||||
|
public ILogger<ElasticsearchAuditLogManager> Logger { protected get; set; } |
||||
|
|
||||
|
public ElasticsearchAuditLogManager( |
||||
|
ICurrentTenant currentTenant, |
||||
|
IOptions<AbpElasticsearchOptions> elasticsearchOptions, |
||||
|
IOptions<AbpAuditLoggingElasticsearchOptions> options, |
||||
|
IElasticsearchClientFactory clientFactory, |
||||
|
IOptions<AbpAuditingOptions> auditingOptions, |
||||
|
IAuditLogInfoToAuditLogConverter converter) |
||||
|
{ |
||||
|
_options = options.Value; |
||||
|
_converter = converter; |
||||
|
_clientFactory = clientFactory; |
||||
|
_currentTenant = currentTenant; |
||||
|
_auditingOptions = auditingOptions.Value; |
||||
|
_elasticsearchOptions = elasticsearchOptions.Value; |
||||
|
|
||||
|
Logger = NullLogger<ElasticsearchAuditLogManager>.Instance; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public virtual async Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string httpMethod = null, |
||||
|
string url = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string applicationName = null, |
||||
|
string correlationId = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
int? maxExecutionDuration = null, |
||||
|
int? minExecutionDuration = null, |
||||
|
bool? hasException = null, |
||||
|
HttpStatusCode? httpStatusCode = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var querys = BuildQueryDescriptor( |
||||
|
startTime, |
||||
|
endTime, |
||||
|
httpMethod, |
||||
|
url, |
||||
|
userId, |
||||
|
userName, |
||||
|
applicationName, |
||||
|
correlationId, |
||||
|
clientId, |
||||
|
clientIpAddress, |
||||
|
maxExecutionDuration, |
||||
|
minExecutionDuration, |
||||
|
hasException, |
||||
|
httpStatusCode); |
||||
|
|
||||
|
var response = await client.CountAsync<AuditLog>(dsl => |
||||
|
dsl.Index(CreateIndex()) |
||||
|
.Query(log => log.Bool(b => b.Must(querys.ToArray()))), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return response.Count; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<List<AuditLog>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string httpMethod = null, |
||||
|
string url = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string applicationName = null, |
||||
|
string correlationId = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
int? maxExecutionDuration = null, |
||||
|
int? minExecutionDuration = null, |
||||
|
bool? hasException = null, |
||||
|
HttpStatusCode? httpStatusCode = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var sortOrder = !sorting.IsNullOrWhiteSpace() && sorting.EndsWith("desc", StringComparison.InvariantCultureIgnoreCase) |
||||
|
? SortOrder.Descending : SortOrder.Ascending; |
||||
|
sorting = !sorting.IsNullOrWhiteSpace() |
||||
|
? sorting.Split()[0] |
||||
|
: nameof(AuditLog.ExecutionTime); |
||||
|
|
||||
|
if (_elasticsearchOptions.FieldCamelCase) |
||||
|
{ |
||||
|
sorting = sorting.ToCamelCase(); |
||||
|
} |
||||
|
|
||||
|
var querys = BuildQueryDescriptor( |
||||
|
startTime, |
||||
|
endTime, |
||||
|
httpMethod, |
||||
|
url, |
||||
|
userId, |
||||
|
userName, |
||||
|
applicationName, |
||||
|
correlationId, |
||||
|
clientId, |
||||
|
clientIpAddress, |
||||
|
maxExecutionDuration, |
||||
|
minExecutionDuration, |
||||
|
hasException, |
||||
|
httpStatusCode); |
||||
|
|
||||
|
SourceFilterDescriptor<AuditLog> ConvertFileSystem(SourceFilterDescriptor<AuditLog> selector) |
||||
|
{ |
||||
|
selector.IncludeAll(); |
||||
|
if (!includeDetails) |
||||
|
{ |
||||
|
selector.Excludes(field => |
||||
|
field.Field(f => f.Actions) |
||||
|
.Field(f => f.Comments) |
||||
|
.Field(f => f.Exceptions) |
||||
|
.Field(f => f.EntityChanges)); |
||||
|
} |
||||
|
|
||||
|
return selector; |
||||
|
} |
||||
|
|
||||
|
var response = await client.SearchAsync<AuditLog>(dsl => |
||||
|
dsl.Index(CreateIndex()) |
||||
|
.Query(log => log.Bool(b => b.Must(querys.ToArray()))) |
||||
|
.Source(ConvertFileSystem) |
||||
|
.Sort(log => log.Field(sorting, sortOrder)) |
||||
|
.From(skipCount) |
||||
|
.Size(maxResultCount), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return response.Documents.ToList(); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<AuditLog> GetAsync( |
||||
|
Guid id, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var response = await client.GetAsync<AuditLog>( |
||||
|
id, |
||||
|
dsl => |
||||
|
dsl.Index(CreateIndex()), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return response.Source; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
await client.DeleteAsync<AuditLog>( |
||||
|
id, |
||||
|
dsl => |
||||
|
dsl.Index(CreateIndex()), |
||||
|
cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<string> SaveAsync( |
||||
|
AuditLogInfo auditInfo, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
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, Microsoft.Extensions.Logging.LogLevel.Error); |
||||
|
} |
||||
|
return ""; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> SaveLogAsync( |
||||
|
AuditLogInfo auditLogInfo, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var auditLog = await _converter.ConvertAsync(auditLogInfo); |
||||
|
|
||||
|
var response = await client.IndexAsync( |
||||
|
auditLog, |
||||
|
(x) => x.Index(CreateIndex()) |
||||
|
.Id(auditLog.Id), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return response.Id; |
||||
|
} |
||||
|
|
||||
|
protected virtual List<Func<QueryContainerDescriptor<AuditLog>, QueryContainer>> BuildQueryDescriptor( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string httpMethod = null, |
||||
|
string url = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string applicationName = null, |
||||
|
string correlationId = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
int? maxExecutionDuration = null, |
||||
|
int? minExecutionDuration = null, |
||||
|
bool? hasException = null, |
||||
|
HttpStatusCode? httpStatusCode = null) |
||||
|
{ |
||||
|
var querys = new List<Func<QueryContainerDescriptor<AuditLog>, QueryContainer>>(); |
||||
|
|
||||
|
if (startTime.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.DateRange((q) => q.Field(f => f.ExecutionTime).GreaterThanOrEquals(startTime))); |
||||
|
} |
||||
|
if (endTime.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.DateRange((q) => q.Field(f => f.ExecutionTime).LessThanOrEquals(endTime))); |
||||
|
} |
||||
|
if (!httpMethod.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.HttpMethod.Suffix("keyword")).Value(httpMethod))); |
||||
|
} |
||||
|
if (!url.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Match((q) => q.Field(f => f.Url.Suffix("keyword")).Query(url))); |
||||
|
} |
||||
|
if (userId.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.UserId.Suffix("keyword")).Value(userId))); |
||||
|
} |
||||
|
if (!userName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.UserName.Suffix("keyword")).Value(userName))); |
||||
|
} |
||||
|
if (!applicationName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.ApplicationName.Suffix("keyword")).Value(applicationName))); |
||||
|
} |
||||
|
if (!correlationId.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.CorrelationId.Suffix("keyword")).Value(correlationId))); |
||||
|
} |
||||
|
if (!clientId.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.ClientId.Suffix("keyword")).Value(clientId))); |
||||
|
} |
||||
|
if (!clientIpAddress.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.ClientIpAddress.Suffix("keyword")).Value(clientIpAddress))); |
||||
|
} |
||||
|
if (maxExecutionDuration.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.Range((q) => q.Field(f => f.ExecutionDuration).LessThanOrEquals(maxExecutionDuration))); |
||||
|
} |
||||
|
if (minExecutionDuration.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.Range((q) => q.Field(f => f.ExecutionDuration).GreaterThanOrEquals(minExecutionDuration))); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
if (hasException.HasValue) |
||||
|
{ |
||||
|
if (hasException.Value) |
||||
|
{ |
||||
|
querys.Add( |
||||
|
(q) => q.Bool( |
||||
|
(b) => b.Must( |
||||
|
(m) => m.Exists( |
||||
|
(e) => e.Field((f) => f.Exceptions))) |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
querys.Add( |
||||
|
(q) => q.Bool( |
||||
|
(b) => b.MustNot( |
||||
|
(mn) => mn.Exists( |
||||
|
(e) => e.Field( |
||||
|
(f) => f.Exceptions))) |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (httpStatusCode.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.HttpStatusCode).Value(httpStatusCode))); |
||||
|
} |
||||
|
|
||||
|
return querys; |
||||
|
} |
||||
|
|
||||
|
protected virtual string CreateIndex() |
||||
|
{ |
||||
|
if (_currentTenant.IsAvailable) |
||||
|
{ |
||||
|
return $"{_options.IndexPrefix}-audit-log-{_currentTenant.Id:N}"; |
||||
|
} |
||||
|
return _options.IndexPrefix.IsNullOrWhiteSpace() |
||||
|
? "audit-log" |
||||
|
: $"{_options.IndexPrefix}-audit-log"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,249 @@ |
|||||
|
using LINGYUN.Abp.Elasticsearch; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Nest; |
||||
|
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.MultiTenancy; |
||||
|
using Volo.Abp.SecurityLog; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class ElasticsearchSecurityLogManager : ISecurityLogManager, ISingletonDependency |
||||
|
{ |
||||
|
private readonly AbpElasticsearchOptions _elasticsearchOptions; |
||||
|
private readonly AbpAuditLoggingElasticsearchOptions _options; |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
private readonly IGuidGenerator _guidGenerator; |
||||
|
private readonly IElasticsearchClientFactory _clientFactory; |
||||
|
|
||||
|
public ILogger<ElasticsearchSecurityLogManager> Logger { protected get; set; } |
||||
|
|
||||
|
public ElasticsearchSecurityLogManager( |
||||
|
ICurrentTenant currentTenant, |
||||
|
IGuidGenerator guidGenerator, |
||||
|
IOptions<AbpElasticsearchOptions> elasticsearchOptions, |
||||
|
IOptions<AbpAuditLoggingElasticsearchOptions> options, |
||||
|
IElasticsearchClientFactory clientFactory) |
||||
|
{ |
||||
|
_options = options.Value; |
||||
|
_currentTenant = currentTenant; |
||||
|
_guidGenerator = guidGenerator; |
||||
|
_clientFactory = clientFactory; |
||||
|
_elasticsearchOptions = elasticsearchOptions.Value; |
||||
|
|
||||
|
Logger = NullLogger<ElasticsearchSecurityLogManager>.Instance; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task SaveAsync( |
||||
|
SecurityLogInfo securityLogInfo, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var securityLog = new SecurityLog( |
||||
|
_guidGenerator.Create(), |
||||
|
securityLogInfo); |
||||
|
|
||||
|
await client.IndexAsync( |
||||
|
securityLog, |
||||
|
(x) => x.Index(CreateIndex()) |
||||
|
.Id(securityLog.Id), |
||||
|
cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<SecurityLog> GetAsync( |
||||
|
Guid id, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var response = await client.GetAsync<SecurityLog>( |
||||
|
id, |
||||
|
dsl => |
||||
|
dsl.Index(CreateIndex()), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return response.Source; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
await client.DeleteAsync<SecurityLog>( |
||||
|
id, |
||||
|
dsl => |
||||
|
dsl.Index(CreateIndex()), |
||||
|
cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<List<SecurityLog>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string applicationName = null, |
||||
|
string identity = null, |
||||
|
string action = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
string correlationId = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var sortOrder = !sorting.IsNullOrWhiteSpace() && sorting.EndsWith("desc", StringComparison.InvariantCultureIgnoreCase) |
||||
|
? SortOrder.Descending : SortOrder.Ascending; |
||||
|
sorting = !sorting.IsNullOrWhiteSpace() |
||||
|
? sorting.Split()[0] |
||||
|
: nameof(SecurityLog.CreationTime); |
||||
|
|
||||
|
if (_elasticsearchOptions.FieldCamelCase) |
||||
|
{ |
||||
|
sorting = sorting.ToCamelCase(); |
||||
|
} |
||||
|
|
||||
|
var querys = BuildQueryDescriptor( |
||||
|
startTime, |
||||
|
endTime, |
||||
|
applicationName, |
||||
|
identity, |
||||
|
action, |
||||
|
userId, |
||||
|
userName, |
||||
|
clientId, |
||||
|
clientIpAddress, |
||||
|
correlationId); |
||||
|
|
||||
|
var response = await client.SearchAsync<SecurityLog>(dsl => |
||||
|
dsl.Index(CreateIndex()) |
||||
|
.Query(log => log.Bool(b => b.Must(querys.ToArray()))) |
||||
|
.Source(log => log.IncludeAll()) |
||||
|
.Sort(log => log.Field(sorting, sortOrder)) |
||||
|
.From(skipCount) |
||||
|
.Size(maxResultCount), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return response.Documents.ToList(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public virtual async Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string applicationName = null, |
||||
|
string identity = null, |
||||
|
string action = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
string correlationId = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var querys = BuildQueryDescriptor( |
||||
|
startTime, |
||||
|
endTime, |
||||
|
applicationName, |
||||
|
identity, |
||||
|
action, |
||||
|
userId, |
||||
|
userName, |
||||
|
clientId, |
||||
|
clientIpAddress, |
||||
|
correlationId); |
||||
|
|
||||
|
var response = await client.CountAsync<SecurityLog>(dsl => |
||||
|
dsl.Index(CreateIndex()) |
||||
|
.Query(log => log.Bool(b => b.Must(querys.ToArray()))), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return response.Count; |
||||
|
} |
||||
|
|
||||
|
protected virtual List<Func<QueryContainerDescriptor<SecurityLog>, QueryContainer>> BuildQueryDescriptor( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string applicationName = null, |
||||
|
string identity = null, |
||||
|
string action = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
string correlationId = null) |
||||
|
{ |
||||
|
var querys = new List<Func<QueryContainerDescriptor<SecurityLog>, QueryContainer>>(); |
||||
|
|
||||
|
if (startTime.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.DateRange((q) => q.Field(f => f.CreationTime).GreaterThanOrEquals(startTime))); |
||||
|
} |
||||
|
if (endTime.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.DateRange((q) => q.Field(f => f.CreationTime).LessThanOrEquals(endTime))); |
||||
|
} |
||||
|
if (!applicationName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.ApplicationName.Suffix("keyword")).Value(applicationName))); |
||||
|
} |
||||
|
if (!identity.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.Identity.Suffix("keyword")).Value(identity))); |
||||
|
} |
||||
|
if (!action.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.Action.Suffix("keyword")).Value(action))); |
||||
|
} |
||||
|
if (userId.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.UserId.Suffix("keyword")).Value(userId))); |
||||
|
} |
||||
|
if (!userName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.UserName.Suffix("keyword")).Value(userName))); |
||||
|
} |
||||
|
if (!clientId.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.ClientId.Suffix("keyword")).Value(clientId))); |
||||
|
} |
||||
|
if (!clientIpAddress.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.ClientIpAddress.Suffix("keyword")).Value(clientIpAddress))); |
||||
|
} |
||||
|
if (!correlationId.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.CorrelationId.Suffix("keyword")).Value(correlationId))); |
||||
|
} |
||||
|
|
||||
|
return querys; |
||||
|
} |
||||
|
|
||||
|
protected virtual string CreateIndex() |
||||
|
{ |
||||
|
// TODO: 会出现索引很长的情况...
|
||||
|
if (_currentTenant.IsAvailable) |
||||
|
{ |
||||
|
return $"{_options.IndexPrefix}-security-log-{_currentTenant.Id:N}"; |
||||
|
} |
||||
|
return _options.IndexPrefix.IsNullOrWhiteSpace() |
||||
|
? "security-log" |
||||
|
: $"{_options.IndexPrefix}-security-log"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Auditing; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
public interface IAuditLogInfoToAuditLogConverter |
||||
|
{ |
||||
|
Task<AuditLog> ConvertAsync(AuditLogInfo auditLogInfo); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.AutoMapper" Version="4.4.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Identity.EntityFrameworkCore" Version="4.4.0" /> |
||||
|
<PackageReference Include="Volo.Abp.AuditLogging.EntityFrameworkCore" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.AuditLogging\LINGYUN.Abp.AuditLogging.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,25 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AutoMapper; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.EntityFrameworkCore |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(Volo.Abp.Identity.EntityFrameworkCore.AbpIdentityEntityFrameworkCoreModule), |
||||
|
typeof(Volo.Abp.AuditLogging.EntityFrameworkCore.AbpAuditLoggingEntityFrameworkCoreModule))] |
||||
|
[DependsOn( |
||||
|
typeof(AbpAuditLoggingModule), |
||||
|
typeof(AbpAutoMapperModule))] |
||||
|
public class AbpAuditLoggingEntityFrameworkCoreModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAutoMapperObjectMapper<AbpAuditLoggingEntityFrameworkCoreModule>(); |
||||
|
|
||||
|
Configure<AbpAutoMapperOptions>(options => |
||||
|
{ |
||||
|
options.AddProfile<AbpAuditingMapperProfile>(validate: true); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using AutoMapper; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.EntityFrameworkCore |
||||
|
{ |
||||
|
public class AbpAuditingMapperProfile : Profile |
||||
|
{ |
||||
|
public AbpAuditingMapperProfile() |
||||
|
{ |
||||
|
CreateMap<Volo.Abp.AuditLogging.AuditLogAction, LINGYUN.Abp.AuditLogging.AuditLogAction>() |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<Volo.Abp.AuditLogging.EntityPropertyChange, LINGYUN.Abp.AuditLogging.EntityPropertyChange>(); |
||||
|
CreateMap<Volo.Abp.AuditLogging.EntityChange, LINGYUN.Abp.AuditLogging.EntityChange>() |
||||
|
.MapExtraProperties(); |
||||
|
CreateMap<Volo.Abp.AuditLogging.AuditLog, LINGYUN.Abp.AuditLogging.AuditLog>() |
||||
|
.MapExtraProperties(); |
||||
|
|
||||
|
CreateMap<Volo.Abp.Identity.IdentitySecurityLog, LINGYUN.Abp.AuditLogging.SecurityLog>() |
||||
|
.MapExtraProperties(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,177 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
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; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.EntityFrameworkCore |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class AuditLogManager : IAuditLogManager, ISingletonDependency |
||||
|
{ |
||||
|
protected IObjectMapper ObjectMapper { get; } |
||||
|
protected IAuditLogRepository AuditLogRepository { get; } |
||||
|
protected IUnitOfWorkManager UnitOfWorkManager { get; } |
||||
|
protected AbpAuditingOptions Options { get; } |
||||
|
protected IAuditLogInfoToAuditLogConverter Converter { get; } |
||||
|
|
||||
|
public ILogger<AuditLogManager> Logger { protected get; set; } |
||||
|
|
||||
|
public AuditLogManager( |
||||
|
IObjectMapper objectMapper, |
||||
|
IAuditLogRepository auditLogRepository, |
||||
|
IUnitOfWorkManager unitOfWorkManager, |
||||
|
IOptions<AbpAuditingOptions> options, |
||||
|
IAuditLogInfoToAuditLogConverter converter) |
||||
|
{ |
||||
|
ObjectMapper = objectMapper; |
||||
|
AuditLogRepository = auditLogRepository; |
||||
|
UnitOfWorkManager = unitOfWorkManager; |
||||
|
Converter = converter; |
||||
|
Options = options.Value; |
||||
|
|
||||
|
Logger = NullLogger<AuditLogManager>.Instance; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public virtual async Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string httpMethod = null, |
||||
|
string url = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string applicationName = null, |
||||
|
string correlationId = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
int? maxExecutionDuration = null, |
||||
|
int? minExecutionDuration = null, |
||||
|
bool? hasException = null, |
||||
|
HttpStatusCode? httpStatusCode = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
return await AuditLogRepository.GetCountAsync( |
||||
|
startTime, |
||||
|
endTime, |
||||
|
httpMethod, |
||||
|
url, |
||||
|
userId, |
||||
|
userName, |
||||
|
applicationName, |
||||
|
correlationId, |
||||
|
maxExecutionDuration, |
||||
|
minExecutionDuration, |
||||
|
hasException, |
||||
|
httpStatusCode, |
||||
|
cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<List<AuditLog>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string httpMethod = null, |
||||
|
string url = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string applicationName = null, |
||||
|
string correlationId = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
int? maxExecutionDuration = null, |
||||
|
int? minExecutionDuration = null, |
||||
|
bool? hasException = null, |
||||
|
HttpStatusCode? httpStatusCode = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var auditLogs = await AuditLogRepository.GetListAsync( |
||||
|
sorting, |
||||
|
maxResultCount, |
||||
|
skipCount, |
||||
|
startTime, |
||||
|
endTime, |
||||
|
httpMethod, |
||||
|
url, |
||||
|
userId, |
||||
|
userName, |
||||
|
applicationName, |
||||
|
correlationId, |
||||
|
maxExecutionDuration, |
||||
|
minExecutionDuration, |
||||
|
hasException, |
||||
|
httpStatusCode, |
||||
|
includeDetails, |
||||
|
cancellationToken); |
||||
|
|
||||
|
return ObjectMapper.Map<List<Volo.Abp.AuditLogging.AuditLog>, List<AuditLog>>(auditLogs); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<AuditLog> GetAsync( |
||||
|
Guid id, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var auditLog = await AuditLogRepository.GetAsync(id, includeDetails, cancellationToken); |
||||
|
|
||||
|
return ObjectMapper.Map<Volo.Abp.AuditLogging.AuditLog, AuditLog>(auditLog); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
using (var uow = UnitOfWorkManager.Begin(true)) |
||||
|
{ |
||||
|
await AuditLogRepository.DeleteAsync(id); |
||||
|
await uow.CompleteAsync(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<string> SaveAsync( |
||||
|
AuditLogInfo auditInfo, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
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 virtual async Task<string> SaveLogAsync( |
||||
|
AuditLogInfo auditInfo, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
using (var uow = UnitOfWorkManager.Begin(true)) |
||||
|
{ |
||||
|
var auditLog = await AuditLogRepository.InsertAsync( |
||||
|
await Converter.ConvertAsync(auditInfo), |
||||
|
false, |
||||
|
cancellationToken); |
||||
|
await uow.CompleteAsync(); |
||||
|
|
||||
|
return auditLog.Id.ToString(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,144 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
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 |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class SecurityLogManager : ISecurityLogManager, ISingletonDependency |
||||
|
{ |
||||
|
public ILogger<SecurityLogManager> 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<SecurityLogManager> logger, |
||||
|
IOptions<AbpSecurityLogOptions> securityLogOptions, |
||||
|
IIdentitySecurityLogRepository identitySecurityLogRepository, |
||||
|
IGuidGenerator guidGenerator, |
||||
|
IUnitOfWorkManager unitOfWorkManager) |
||||
|
{ |
||||
|
Logger = logger; |
||||
|
ObjectMapper = objectMapper; |
||||
|
SecurityLogOptions = securityLogOptions.Value; |
||||
|
IdentitySecurityLogRepository = identitySecurityLogRepository; |
||||
|
GuidGenerator = guidGenerator; |
||||
|
UnitOfWorkManager = unitOfWorkManager; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task SaveAsync( |
||||
|
SecurityLogInfo securityLogInfo, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
if (!SecurityLogOptions.IsEnabled) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) |
||||
|
{ |
||||
|
await IdentitySecurityLogRepository.InsertAsync( |
||||
|
new IdentitySecurityLog(GuidGenerator, securityLogInfo), |
||||
|
false, |
||||
|
cancellationToken); |
||||
|
await uow.CompleteAsync(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<SecurityLog> GetAsync( |
||||
|
Guid id, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var securityLog = await IdentitySecurityLogRepository.GetAsync(id, includeDetails, cancellationToken); |
||||
|
|
||||
|
return ObjectMapper.Map<IdentitySecurityLog, SecurityLog>(securityLog); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
using (var uow = UnitOfWorkManager.Begin(true)) |
||||
|
{ |
||||
|
await IdentitySecurityLogRepository.DeleteAsync(id); |
||||
|
await uow.CompleteAsync(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<List<SecurityLog>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string applicationName = null, |
||||
|
string identity = null, |
||||
|
string action = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
string correlationId = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var securityLogs = await IdentitySecurityLogRepository.GetListAsync( |
||||
|
sorting, |
||||
|
maxResultCount, |
||||
|
skipCount, |
||||
|
startTime, |
||||
|
endTime, |
||||
|
applicationName, |
||||
|
identity, |
||||
|
action, |
||||
|
userId, |
||||
|
userName, |
||||
|
clientId, |
||||
|
correlationId, |
||||
|
includeDetails, |
||||
|
cancellationToken); |
||||
|
|
||||
|
return ObjectMapper.Map<List<IdentitySecurityLog>, List<SecurityLog>>(securityLogs); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public virtual async Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string applicationName = null, |
||||
|
string identity = null, |
||||
|
string action = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
string correlationId = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
return await IdentitySecurityLogRepository.GetCountAsync( |
||||
|
startTime, |
||||
|
endTime, |
||||
|
applicationName, |
||||
|
identity, |
||||
|
action, |
||||
|
userId, |
||||
|
userName, |
||||
|
clientId, |
||||
|
correlationId, |
||||
|
cancellationToken); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Auditing" Version="4.4.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Guids" Version="4.4.0" /> |
||||
|
<PackageReference Include="Volo.Abp.ExceptionHandling" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.ExceptionHandling; |
||||
|
using Volo.Abp.Guids; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAuditingModule), |
||||
|
typeof(AbpGuidsModule), |
||||
|
typeof(AbpExceptionHandlingModule))] |
||||
|
public class AbpAuditLoggingModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,115 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[DisableAuditing] |
||||
|
public class AuditLog : IHasExtraProperties |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public string ApplicationName { get; set; } |
||||
|
|
||||
|
public Guid? UserId { get; set; } |
||||
|
|
||||
|
public string UserName { get; set; } |
||||
|
|
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public string TenantName { get; set; } |
||||
|
|
||||
|
public Guid? ImpersonatorUserId { get; set; } |
||||
|
|
||||
|
public Guid? ImpersonatorTenantId { get; set; } |
||||
|
|
||||
|
public DateTime ExecutionTime { get; set; } |
||||
|
|
||||
|
public int ExecutionDuration { get; set; } |
||||
|
|
||||
|
public string ClientIpAddress { get; set; } |
||||
|
|
||||
|
public string ClientName { get; set; } |
||||
|
|
||||
|
public string ClientId { get; set; } |
||||
|
|
||||
|
public string CorrelationId { get; set; } |
||||
|
|
||||
|
public string BrowserInfo { get; set; } |
||||
|
|
||||
|
public string HttpMethod { get; set; } |
||||
|
|
||||
|
public string Url { get; set; } |
||||
|
|
||||
|
public string Exceptions { get; set; } |
||||
|
|
||||
|
public string Comments { get; set; } |
||||
|
|
||||
|
public int? HttpStatusCode { get; set; } |
||||
|
|
||||
|
public List<EntityChange> EntityChanges { get; set; } |
||||
|
|
||||
|
public List<AuditLogAction> Actions { get; set; } |
||||
|
|
||||
|
public ExtraPropertyDictionary ExtraProperties { get; set; } |
||||
|
|
||||
|
public AuditLog() |
||||
|
{ |
||||
|
Actions = new List<AuditLogAction>(); |
||||
|
EntityChanges = new List<EntityChange>(); |
||||
|
ExtraProperties = new ExtraPropertyDictionary(); |
||||
|
} |
||||
|
|
||||
|
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) |
||||
|
{ |
||||
|
Id = id; |
||||
|
ApplicationName = applicationName; |
||||
|
TenantId = tenantId; |
||||
|
TenantName = tenantName; |
||||
|
UserId = userId; |
||||
|
UserName = userName; |
||||
|
ExecutionTime = executionTime; |
||||
|
ExecutionDuration = executionDuration; |
||||
|
ClientIpAddress = clientIpAddress; |
||||
|
ClientName = clientName; |
||||
|
ClientId = clientId; |
||||
|
CorrelationId = correlationId; |
||||
|
BrowserInfo = browserInfo; |
||||
|
HttpMethod = httpMethod; |
||||
|
Url = url; |
||||
|
HttpStatusCode = httpStatusCode; |
||||
|
ImpersonatorUserId = impersonatorUserId; |
||||
|
ImpersonatorTenantId = impersonatorTenantId; |
||||
|
|
||||
|
ExtraProperties = extraPropertyDictionary; |
||||
|
EntityChanges = entityChanges; |
||||
|
Actions = actions; |
||||
|
Exceptions = exceptions; |
||||
|
Comments = comments; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[DisableAuditing] |
||||
|
public class AuditLogAction : IHasExtraProperties |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public Guid AuditLogId { get; set; } |
||||
|
|
||||
|
public string ServiceName { get; set; } |
||||
|
|
||||
|
public string MethodName { get; set; } |
||||
|
|
||||
|
public string Parameters { get; set; } |
||||
|
|
||||
|
public DateTime ExecutionTime { get; set; } |
||||
|
|
||||
|
public int ExecutionDuration { get; set; } |
||||
|
|
||||
|
public ExtraPropertyDictionary ExtraProperties { get; set; } |
||||
|
|
||||
|
public AuditLogAction() |
||||
|
{ |
||||
|
ExtraProperties = new ExtraPropertyDictionary(); |
||||
|
} |
||||
|
|
||||
|
public AuditLogAction(Guid id, Guid auditLogId, AuditLogActionInfo actionInfo, Guid? tenantId = null) |
||||
|
{ |
||||
|
|
||||
|
Id = id; |
||||
|
TenantId = tenantId; |
||||
|
AuditLogId = auditLogId; |
||||
|
ExecutionTime = actionInfo.ExecutionTime; |
||||
|
ExecutionDuration = actionInfo.ExecutionDuration; |
||||
|
ExtraProperties = new ExtraPropertyDictionary(actionInfo.ExtraProperties); |
||||
|
ServiceName = actionInfo.ServiceName; |
||||
|
MethodName = actionInfo.MethodName; |
||||
|
Parameters = actionInfo.Parameters.Length > 2000 ? "" : actionInfo.Parameters; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class AuditingStore : IAuditingStore, ITransientDependency |
||||
|
{ |
||||
|
private readonly IAuditLogManager _manager; |
||||
|
|
||||
|
public AuditingStore( |
||||
|
IAuditLogManager manager) |
||||
|
{ |
||||
|
_manager = manager; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task SaveAsync(AuditLogInfo auditInfo) |
||||
|
{ |
||||
|
await _manager.SaveAsync(auditInfo); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,96 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Net; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[Dependency(TryRegister = true)] |
||||
|
public class DefaultAuditLogManager : IAuditLogManager, ISingletonDependency |
||||
|
{ |
||||
|
public ILogger<DefaultAuditLogManager> Logger { protected get; set; } |
||||
|
|
||||
|
public DefaultAuditLogManager() |
||||
|
{ |
||||
|
Logger = NullLogger<DefaultAuditLogManager>.Instance; |
||||
|
} |
||||
|
|
||||
|
public virtual Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string httpMethod = null, |
||||
|
string url = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string applicationName = null, |
||||
|
string correlationId = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
int? maxExecutionDuration = null, |
||||
|
int? minExecutionDuration = null, |
||||
|
bool? hasException = null, |
||||
|
HttpStatusCode? httpStatusCode = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
Logger.LogDebug("No audit log manager is available!"); |
||||
|
return Task.FromResult(0L); |
||||
|
} |
||||
|
|
||||
|
public virtual Task<List<AuditLog>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string httpMethod = null, |
||||
|
string url = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string applicationName = null, |
||||
|
string correlationId = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
int? maxExecutionDuration = null, |
||||
|
int? minExecutionDuration = null, |
||||
|
bool? hasException = null, |
||||
|
HttpStatusCode? httpStatusCode = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
Logger.LogDebug("No audit log manager is available!"); |
||||
|
return Task.FromResult(new List<AuditLog>()); |
||||
|
} |
||||
|
|
||||
|
public virtual Task<string> SaveAsync( |
||||
|
AuditLogInfo auditInfo, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Logger.LogDebug("No audit log manager is available and is written to the local log by default"); |
||||
|
Logger.LogInformation(auditInfo.ToString()); |
||||
|
|
||||
|
return Task.FromResult(""); |
||||
|
} |
||||
|
|
||||
|
public virtual Task<AuditLog> GetAsync( |
||||
|
Guid id, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Logger.LogDebug("No audit log manager is available!"); |
||||
|
|
||||
|
AuditLog auditLog = null; |
||||
|
return Task.FromResult(auditLog); |
||||
|
} |
||||
|
|
||||
|
public virtual Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Logger.LogDebug("No audit log manager is available!"); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,87 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using System; |
||||
|
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 DefaultSecurityLogManager : ISecurityLogManager, ISingletonDependency |
||||
|
{ |
||||
|
public ILogger<DefaultSecurityLogManager> Logger { protected get; set; } |
||||
|
|
||||
|
public DefaultSecurityLogManager() |
||||
|
{ |
||||
|
Logger = NullLogger<DefaultSecurityLogManager>.Instance; |
||||
|
} |
||||
|
|
||||
|
public Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string applicationName = null, |
||||
|
string identity = null, |
||||
|
string action = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
string correlationId = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
Logger.LogDebug("No security log manager is available!"); |
||||
|
return Task.FromResult(0L); |
||||
|
} |
||||
|
|
||||
|
public Task<List<SecurityLog>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string applicationName = null, |
||||
|
string identity = null, |
||||
|
string action = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
string correlationId = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
Logger.LogDebug("No security log manager is available!"); |
||||
|
return Task.FromResult(new List<SecurityLog>()); |
||||
|
} |
||||
|
|
||||
|
public Task SaveAsync( |
||||
|
SecurityLogInfo securityLogInfo, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
Logger.LogDebug("No security log manager is available and is written to the local log by default"); |
||||
|
Logger.LogInformation(securityLogInfo.ToString()); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public virtual Task<SecurityLog> GetAsync( |
||||
|
Guid id, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Logger.LogDebug("No security log manager is available!"); |
||||
|
|
||||
|
SecurityLog securityLog = null; |
||||
|
return Task.FromResult(securityLog); |
||||
|
} |
||||
|
|
||||
|
public virtual Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Logger.LogDebug("No security log manager is available!"); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.Guids; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[DisableAuditing] |
||||
|
public class EntityChange : IHasExtraProperties |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public Guid AuditLogId { get; set; } |
||||
|
|
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public DateTime ChangeTime { get; set; } |
||||
|
|
||||
|
public EntityChangeType ChangeType { get; set; } |
||||
|
|
||||
|
public Guid? EntityTenantId { get; set; } |
||||
|
|
||||
|
public string EntityId { get; set; } |
||||
|
|
||||
|
public string EntityTypeFullName { get; set; } |
||||
|
|
||||
|
public List<EntityPropertyChange> PropertyChanges { get; set; } |
||||
|
|
||||
|
public ExtraPropertyDictionary ExtraProperties { get; set; } |
||||
|
|
||||
|
public EntityChange() |
||||
|
{ |
||||
|
PropertyChanges = new List<EntityPropertyChange>(); |
||||
|
ExtraProperties = new ExtraPropertyDictionary(); |
||||
|
} |
||||
|
|
||||
|
public EntityChange( |
||||
|
IGuidGenerator guidGenerator, |
||||
|
Guid auditLogId, |
||||
|
EntityChangeInfo entityChangeInfo, |
||||
|
Guid? tenantId = null) |
||||
|
{ |
||||
|
Id = guidGenerator.Create(); |
||||
|
AuditLogId = auditLogId; |
||||
|
TenantId = tenantId; |
||||
|
ChangeTime = entityChangeInfo.ChangeTime; |
||||
|
ChangeType = entityChangeInfo.ChangeType; |
||||
|
EntityId = entityChangeInfo.EntityId; |
||||
|
EntityTypeFullName = entityChangeInfo.EntityTypeFullName; |
||||
|
|
||||
|
PropertyChanges = entityChangeInfo |
||||
|
.PropertyChanges? |
||||
|
.Select(p => new EntityPropertyChange(guidGenerator, Id, p, tenantId)) |
||||
|
.ToList() |
||||
|
?? new List<EntityPropertyChange>(); |
||||
|
|
||||
|
ExtraProperties = new ExtraPropertyDictionary(); |
||||
|
if (entityChangeInfo.ExtraProperties != null) |
||||
|
{ |
||||
|
foreach (var pair in entityChangeInfo.ExtraProperties) |
||||
|
{ |
||||
|
ExtraProperties.Add(pair.Key, pair.Value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Guids; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[DisableAuditing] |
||||
|
public class EntityPropertyChange |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public Guid EntityChangeId { get; set; } |
||||
|
|
||||
|
public string NewValue { get; set; } |
||||
|
|
||||
|
public string OriginalValue { get; set; } |
||||
|
|
||||
|
public string PropertyName { get; set; } |
||||
|
|
||||
|
public string PropertyTypeFullName { get; set; } |
||||
|
|
||||
|
public EntityPropertyChange() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public EntityPropertyChange( |
||||
|
IGuidGenerator guidGenerator, |
||||
|
Guid entityChangeId, |
||||
|
EntityPropertyChangeInfo entityChangeInfo, |
||||
|
Guid? tenantId = null) |
||||
|
{ |
||||
|
Id = guidGenerator.Create(); |
||||
|
TenantId = tenantId; |
||||
|
EntityChangeId = entityChangeId; |
||||
|
NewValue = entityChangeInfo.NewValue; |
||||
|
OriginalValue = entityChangeInfo.OriginalValue; |
||||
|
PropertyName = entityChangeInfo.PropertyName; |
||||
|
PropertyTypeFullName = entityChangeInfo.PropertyTypeFullName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Net; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Auditing; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
public interface IAuditLogManager |
||||
|
{ |
||||
|
Task<AuditLog> GetAsync( |
||||
|
Guid id, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
Task DeleteAsync( |
||||
|
Guid id, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
Task<string> SaveAsync( |
||||
|
AuditLogInfo auditInfo, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string httpMethod = null, |
||||
|
string url = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string applicationName = null, |
||||
|
string correlationId = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
int? maxExecutionDuration = null, |
||||
|
int? minExecutionDuration = null, |
||||
|
bool? hasException = null, |
||||
|
HttpStatusCode? httpStatusCode = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
Task<List<AuditLog>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string httpMethod = null, |
||||
|
string url = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string applicationName = null, |
||||
|
string correlationId = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
int? maxExecutionDuration = null, |
||||
|
int? minExecutionDuration = null, |
||||
|
bool? hasException = null, |
||||
|
HttpStatusCode? httpStatusCode = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.SecurityLog; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
public interface ISecurityLogManager |
||||
|
{ |
||||
|
Task<SecurityLog> GetAsync( |
||||
|
Guid id, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
Task DeleteAsync( |
||||
|
Guid id, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
Task SaveAsync( |
||||
|
SecurityLogInfo securityLogInfo, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
Task<List<SecurityLog>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string applicationName = null, |
||||
|
string identity = null, |
||||
|
string action = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
string correlationId = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
|
||||
|
Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string applicationName = null, |
||||
|
string identity = null, |
||||
|
string action = null, |
||||
|
Guid? userId = null, |
||||
|
string userName = null, |
||||
|
string clientId = null, |
||||
|
string clientIpAddress = null, |
||||
|
string correlationId = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.SecurityLog; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
public class SecurityLog : IHasExtraProperties |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public string ApplicationName { get; set; } |
||||
|
|
||||
|
public string Identity { get; set; } |
||||
|
|
||||
|
public string Action { get; set; } |
||||
|
|
||||
|
public Guid? UserId { get; set; } |
||||
|
|
||||
|
public string UserName { get; set; } |
||||
|
|
||||
|
public string TenantName { get; set; } |
||||
|
|
||||
|
public string ClientId { get; set; } |
||||
|
|
||||
|
public string CorrelationId { get; set; } |
||||
|
|
||||
|
public string ClientIpAddress { get; set; } |
||||
|
|
||||
|
public string BrowserInfo { get; set; } |
||||
|
|
||||
|
public DateTime CreationTime { get; set; } |
||||
|
|
||||
|
public ExtraPropertyDictionary ExtraProperties { get; set; } |
||||
|
|
||||
|
public SecurityLog() |
||||
|
{ |
||||
|
ExtraProperties = new ExtraPropertyDictionary(); |
||||
|
} |
||||
|
|
||||
|
public SecurityLog(Guid id, SecurityLogInfo securityLogInfo) |
||||
|
{ |
||||
|
Id = id; |
||||
|
TenantId = securityLogInfo.TenantId; |
||||
|
TenantName = securityLogInfo.TenantName; |
||||
|
|
||||
|
ApplicationName = securityLogInfo.ApplicationName; |
||||
|
Identity = securityLogInfo.Identity; |
||||
|
Action = securityLogInfo.Action; |
||||
|
|
||||
|
UserId = securityLogInfo.UserId; |
||||
|
UserName = securityLogInfo.UserName; |
||||
|
|
||||
|
CreationTime = securityLogInfo.CreationTime; |
||||
|
|
||||
|
ClientIpAddress = securityLogInfo.ClientIpAddress; |
||||
|
ClientId = securityLogInfo.ClientId; |
||||
|
CorrelationId = securityLogInfo.CorrelationId; |
||||
|
BrowserInfo = securityLogInfo.BrowserInfo; |
||||
|
|
||||
|
ExtraProperties = new ExtraPropertyDictionary(); |
||||
|
if (securityLogInfo.ExtraProperties != null) |
||||
|
{ |
||||
|
foreach (var pair in securityLogInfo.ExtraProperties) |
||||
|
{ |
||||
|
ExtraProperties.Add(pair.Key, pair.Value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.SecurityLog; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class SecurityLogStore : ISecurityLogStore, ITransientDependency |
||||
|
{ |
||||
|
private readonly ISecurityLogManager _manager; |
||||
|
|
||||
|
public SecurityLogStore( |
||||
|
ISecurityLogManager manager) |
||||
|
{ |
||||
|
_manager = manager; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task SaveAsync(SecurityLogInfo securityLogInfo) |
||||
|
{ |
||||
|
await _manager.SaveAsync(securityLogInfo); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,36 +1,34 @@ |
|||||
using Volo.Abp.Application; |
using Volo.Abp.Application; |
||||
using Volo.Abp.AuditLogging; |
using Volo.Abp.AuditLogging; |
||||
using Volo.Abp.AuditLogging.Localization; |
using Volo.Abp.AuditLogging.Localization; |
||||
using Volo.Abp.Authorization; |
using Volo.Abp.Authorization; |
||||
using Volo.Abp.Features; |
using Volo.Abp.Features; |
||||
using Volo.Abp.Identity; |
using Volo.Abp.Localization; |
||||
using Volo.Abp.Localization; |
using Volo.Abp.Modularity; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.VirtualFileSystem; |
||||
using Volo.Abp.VirtualFileSystem; |
|
||||
|
namespace LINGYUN.Abp.Auditing |
||||
namespace LINGYUN.Abp.Auditing |
{ |
||||
{ |
[DependsOn( |
||||
[DependsOn( |
typeof(AbpFeaturesModule), |
||||
typeof(AbpFeaturesModule), |
typeof(AbpAuthorizationModule), |
||||
typeof(AbpAuthorizationModule), |
typeof(AbpAuditLoggingDomainSharedModule), |
||||
typeof(AbpAuditLoggingDomainSharedModule), |
typeof(AbpDddApplicationContractsModule))] |
||||
typeof(AbpIdentityDomainSharedModule), |
public class AbpAuditingApplicationContractsModule : AbpModule |
||||
typeof(AbpDddApplicationContractsModule))] |
{ |
||||
public class AbpAuditingApplicationContractsModule : AbpModule |
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
Configure<AbpVirtualFileSystemOptions>(options => |
||||
{ |
{ |
||||
Configure<AbpVirtualFileSystemOptions>(options => |
options.FileSets.AddEmbedded<AbpAuditingApplicationContractsModule>(); |
||||
{ |
}); |
||||
options.FileSets.AddEmbedded<AbpAuditingApplicationContractsModule>(); |
|
||||
}); |
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
Configure<AbpLocalizationOptions>(options => |
options.Resources |
||||
{ |
.Get<AuditLoggingResource>() |
||||
options.Resources |
.AddVirtualJson("/LINGYUN/Abp/Auditing/Localization/Resources"); |
||||
.Get<AuditLoggingResource>() |
}); |
||||
.AddVirtualJson("/LINGYUN/Abp/Auditing/Localization/Resources"); |
} |
||||
}); |
} |
||||
} |
} |
||||
} |
|
||||
} |
|
||||
|
|||||
@ -1,18 +1,18 @@ |
|||||
using System; |
using System; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Logging |
namespace LINGYUN.Abp.Auditing.AuditLogs |
||||
{ |
{ |
||||
public class AuditLogActionDto : ExtensibleEntityDto<Guid> |
public class AuditLogActionDto : ExtensibleEntityDto<Guid> |
||||
{ |
{ |
||||
public string ServiceName { get; set; } |
public string ServiceName { get; set; } |
||||
|
|
||||
public string MethodName { get; set; } |
public string MethodName { get; set; } |
||||
|
|
||||
public string Parameters { get; set; } |
public string Parameters { get; set; } |
||||
|
|
||||
public DateTime ExecutionTime { get; set; } |
public DateTime ExecutionTime { get; set; } |
||||
|
|
||||
public int ExecutionDuration { get; set; } |
public int ExecutionDuration { get; set; } |
||||
} |
} |
||||
} |
} |
||||
@ -1,55 +1,55 @@ |
|||||
using System; |
using System; |
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Logging |
namespace LINGYUN.Abp.Auditing.AuditLogs |
||||
{ |
{ |
||||
public class AuditLogDto : ExtensibleEntityDto<Guid> |
public class AuditLogDto : ExtensibleEntityDto<Guid> |
||||
{ |
{ |
||||
public string ApplicationName { get; set; } |
public string ApplicationName { get; set; } |
||||
|
|
||||
public Guid? UserId { get; set; } |
public Guid? UserId { get; set; } |
||||
|
|
||||
public string UserName { get; set; } |
public string UserName { get; set; } |
||||
|
|
||||
public Guid? TenantId { get; set; } |
public Guid? TenantId { get; set; } |
||||
|
|
||||
public string TenantName { get; set; } |
public string TenantName { get; set; } |
||||
|
|
||||
public Guid? ImpersonatorUserId { get; set; } |
public Guid? ImpersonatorUserId { get; set; } |
||||
|
|
||||
public Guid? ImpersonatorTenantId { get; set; } |
public Guid? ImpersonatorTenantId { get; set; } |
||||
|
|
||||
public DateTime ExecutionTime { get; set; } |
public DateTime ExecutionTime { get; set; } |
||||
|
|
||||
public int ExecutionDuration { get; set; } |
public int ExecutionDuration { get; set; } |
||||
|
|
||||
public string ClientIpAddress { get; set; } |
public string ClientIpAddress { get; set; } |
||||
|
|
||||
public string ClientName { get; set; } |
public string ClientName { get; set; } |
||||
|
|
||||
public string ClientId { get; set; } |
public string ClientId { get; set; } |
||||
|
|
||||
public string CorrelationId { get; set; } |
public string CorrelationId { get; set; } |
||||
|
|
||||
public string BrowserInfo { get; set; } |
public string BrowserInfo { get; set; } |
||||
|
|
||||
public string HttpMethod { get; set; } |
public string HttpMethod { get; set; } |
||||
|
|
||||
public string Url { get; set; } |
public string Url { get; set; } |
||||
|
|
||||
public string Exceptions { get; set; } |
public string Exceptions { get; set; } |
||||
|
|
||||
public string Comments { get; set; } |
public string Comments { get; set; } |
||||
|
|
||||
public int? HttpStatusCode { get; set; } |
public int? HttpStatusCode { get; set; } |
||||
public List<EntityChangeDto> EntityChanges { get; set; } |
public List<EntityChangeDto> EntityChanges { get; set; } |
||||
public List<AuditLogActionDto> Actions { get; set; } |
public List<AuditLogActionDto> Actions { get; set; } |
||||
|
|
||||
public AuditLogDto() |
public AuditLogDto() |
||||
{ |
{ |
||||
EntityChanges = new List<EntityChangeDto>(); |
EntityChanges = new List<EntityChangeDto>(); |
||||
Actions = new List<AuditLogActionDto>(); |
Actions = new List<AuditLogActionDto>(); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -1,25 +1,25 @@ |
|||||
using System; |
using System; |
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.Auditing; |
using Volo.Abp.Auditing; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Logging |
namespace LINGYUN.Abp.Auditing.AuditLogs |
||||
{ |
{ |
||||
public class EntityChangeDto : ExtensibleEntityDto<Guid> |
public class EntityChangeDto : ExtensibleEntityDto<Guid> |
||||
{ |
{ |
||||
public DateTime ChangeTime { get; set; } |
public DateTime ChangeTime { get; set; } |
||||
|
|
||||
public EntityChangeType ChangeType { get; set; } |
public EntityChangeType ChangeType { get; set; } |
||||
|
|
||||
public Guid? EntityTenantId { get; set; } |
public Guid? EntityTenantId { get; set; } |
||||
|
|
||||
public string EntityId { get; set; } |
public string EntityId { get; set; } |
||||
|
|
||||
public string EntityTypeFullName { get; set; } |
public string EntityTypeFullName { get; set; } |
||||
public List<EntityPropertyChangeDto> PropertyChanges { get; set; } |
public List<EntityPropertyChangeDto> PropertyChanges { get; set; } |
||||
public EntityChangeDto() |
public EntityChangeDto() |
||||
{ |
{ |
||||
PropertyChanges = new List<EntityPropertyChangeDto>(); |
PropertyChanges = new List<EntityPropertyChangeDto>(); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -1,16 +1,16 @@ |
|||||
using System; |
using System; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Logging |
namespace LINGYUN.Abp.Auditing.AuditLogs |
||||
{ |
{ |
||||
public class EntityPropertyChangeDto : EntityDto<Guid> |
public class EntityPropertyChangeDto : EntityDto<Guid> |
||||
{ |
{ |
||||
public string NewValue { get; set; } |
public string NewValue { get; set; } |
||||
|
|
||||
public string OriginalValue { get; set; } |
public string OriginalValue { get; set; } |
||||
|
|
||||
public string PropertyName { get; set; } |
public string PropertyName { get; set; } |
||||
|
|
||||
public string PropertyTypeFullName { get; set; } |
public string PropertyTypeFullName { get; set; } |
||||
} |
} |
||||
} |
} |
||||
@ -1,16 +1,16 @@ |
|||||
using System; |
using System; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.Application.Services; |
using Volo.Abp.Application.Services; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Logging |
namespace LINGYUN.Abp.Auditing.AuditLogs |
||||
{ |
{ |
||||
public interface IAuditLogAppService : IApplicationService |
public interface IAuditLogAppService : IApplicationService |
||||
{ |
{ |
||||
Task<PagedResultDto<AuditLogDto>> GetListAsync(AuditLogGetByPagedDto input); |
Task<PagedResultDto<AuditLogDto>> GetListAsync(AuditLogGetByPagedDto input); |
||||
|
|
||||
Task<AuditLogDto> GetAsync(Guid id); |
Task<AuditLogDto> GetAsync(Guid id); |
||||
|
|
||||
Task DeleteAsync(Guid id); |
Task DeleteAsync(Guid id); |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Auditing.Logging |
||||
|
{ |
||||
|
public class LogDto |
||||
|
{ |
||||
|
public DateTime TimeStamp { get; set; } |
||||
|
public LogLevel Level { get; set; } |
||||
|
public string Message { get; set; } |
||||
|
public LogFieldDto Fields { get; set; } |
||||
|
public List<LogExceptionDto> Exceptions { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
namespace LINGYUN.Abp.Auditing.Logging |
||||
|
{ |
||||
|
public class LogExceptionDto |
||||
|
{ |
||||
|
public int Depth { get; set; } |
||||
|
public string Class { get; set; } |
||||
|
public string Message { get; set; } |
||||
|
public string Source { get; set; } |
||||
|
public string StackTrace { get; set; } |
||||
|
public int HResult { get; set; } |
||||
|
public string HelpURL { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
namespace LINGYUN.Abp.Auditing.Logging |
||||
|
{ |
||||
|
public class LogFieldDto |
||||
|
{ |
||||
|
public string Context { get; set; } |
||||
|
public string ActionId { get; set; } |
||||
|
public string ActionName { get; set; } |
||||
|
public string RequestId { get; set; } |
||||
|
public string RequestPath { get; set; } |
||||
|
public string ConnectionId { get; set; } |
||||
|
public string CorrelationId { get; set; } |
||||
|
public string ClientId { get; set; } |
||||
|
public string UserId { get; set; } |
||||
|
public int ProcessId { get; set; } |
||||
|
public int ThreadId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Auditing.Logging |
||||
|
{ |
||||
|
public class LogGetByPagedDto : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public DateTime? StartTime { get; set; } |
||||
|
public DateTime? EndTime { get; set; } |
||||
|
public string Context { get; set; } |
||||
|
public string RequestId { get; set; } |
||||
|
public string RequestPath { get; set; } |
||||
|
public string CorrelationId { get; set; } |
||||
|
public int? ProcessId { get; set; } |
||||
|
public int? ThreadId { get; set; } |
||||
|
public bool? HasException { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Auditing.Logging |
||||
|
{ |
||||
|
public interface ILogAppService : IApplicationService |
||||
|
{ |
||||
|
Task<LogDto> GetAsync(string id); |
||||
|
|
||||
|
Task<PagedResultDto<LogDto>> GetListAsync(LogGetByPagedDto input); |
||||
|
} |
||||
|
} |
||||
@ -1,16 +1,16 @@ |
|||||
using System; |
using System; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.Application.Services; |
using Volo.Abp.Application.Services; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Security |
namespace LINGYUN.Abp.Auditing.SecurityLogs |
||||
{ |
{ |
||||
public interface ISecurityLogAppService : IApplicationService |
public interface ISecurityLogAppService : IApplicationService |
||||
{ |
{ |
||||
Task<PagedResultDto<SecurityLogDto>> GetListAsync(SecurityLogGetByPagedDto input); |
Task<PagedResultDto<SecurityLogDto>> GetListAsync(SecurityLogGetByPagedDto input); |
||||
|
|
||||
Task<SecurityLogDto> GetAsync(Guid id); |
Task<SecurityLogDto> GetAsync(Guid id); |
||||
|
|
||||
Task DeleteAsync(Guid id); |
Task DeleteAsync(Guid id); |
||||
} |
} |
||||
} |
} |
||||
@ -1,30 +1,30 @@ |
|||||
using System; |
using System; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Security |
namespace LINGYUN.Abp.Auditing.SecurityLogs |
||||
{ |
{ |
||||
public class SecurityLogDto : ExtensibleEntityDto<Guid> |
public class SecurityLogDto : ExtensibleEntityDto<Guid> |
||||
{ |
{ |
||||
public string ApplicationName { get; set; } |
public string ApplicationName { get; set; } |
||||
|
|
||||
public string Identity { get; set; } |
public string Identity { get; set; } |
||||
|
|
||||
public string Action { get; set; } |
public string Action { get; set; } |
||||
|
|
||||
public Guid? UserId { get; set; } |
public Guid? UserId { get; set; } |
||||
|
|
||||
public string UserName { get; set; } |
public string UserName { get; set; } |
||||
|
|
||||
public string TenantName { get; set; } |
public string TenantName { get; set; } |
||||
|
|
||||
public string ClientId { get; set; } |
public string ClientId { get; set; } |
||||
|
|
||||
public string CorrelationId { get; set; } |
public string CorrelationId { get; set; } |
||||
|
|
||||
public string ClientIpAddress { get; set; } |
public string ClientIpAddress { get; set; } |
||||
|
|
||||
public string BrowserInfo { get; set; } |
public string BrowserInfo { get; set; } |
||||
|
|
||||
public DateTime CreationTime { get; set; } |
public DateTime CreationTime { get; set; } |
||||
} |
} |
||||
} |
} |
||||
@ -1,18 +1,18 @@ |
|||||
using System; |
using System; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Security |
namespace LINGYUN.Abp.Auditing.SecurityLogs |
||||
{ |
{ |
||||
public class SecurityLogGetByPagedDto : PagedAndSortedResultRequestDto |
public class SecurityLogGetByPagedDto : PagedAndSortedResultRequestDto |
||||
{ |
{ |
||||
public DateTime? StartTime { get; set; } |
public DateTime? StartTime { get; set; } |
||||
public DateTime? EndTime { get; set; } |
public DateTime? EndTime { get; set; } |
||||
public string ApplicationName { get; set; } |
public string ApplicationName { get; set; } |
||||
public string Identity { get; set; } |
public string Identity { get; set; } |
||||
public string ActionName { get; set; } |
public string ActionName { get; set; } |
||||
public Guid? UserId { get; set; } |
public Guid? UserId { get; set; } |
||||
public string UserName { get; set; } |
public string UserName { get; set; } |
||||
public string ClientId { get; set; } |
public string ClientId { get; set; } |
||||
public string CorrelationId { get; set; } |
public string CorrelationId { get; set; } |
||||
} |
} |
||||
} |
} |
||||
@ -1,24 +1,24 @@ |
|||||
using Microsoft.Extensions.DependencyInjection; |
using LINGYUN.Abp.AuditLogging; |
||||
using Volo.Abp.AuditLogging; |
using Microsoft.Extensions.DependencyInjection; |
||||
using Volo.Abp.AutoMapper; |
using Volo.Abp.AutoMapper; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing |
namespace LINGYUN.Abp.Auditing |
||||
{ |
{ |
||||
[DependsOn( |
[DependsOn( |
||||
typeof(AbpAutoMapperModule), |
typeof(AbpAutoMapperModule), |
||||
typeof(AbpAuditLoggingDomainModule), |
typeof(AbpAuditLoggingModule), |
||||
typeof(AbpAuditingApplicationContractsModule))] |
typeof(AbpAuditingApplicationContractsModule))] |
||||
public class AbpAuditingApplicationModule : AbpModule |
public class AbpAuditingApplicationModule : AbpModule |
||||
{ |
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
{ |
||||
context.Services.AddAutoMapperObjectMapper<AbpAuditingApplicationModule>(); |
context.Services.AddAutoMapperObjectMapper<AbpAuditingApplicationModule>(); |
||||
|
|
||||
Configure<AbpAutoMapperOptions>(options => |
Configure<AbpAutoMapperOptions>(options => |
||||
{ |
{ |
||||
options.AddProfile<AbpAuditingMapperProfile>(validate: true); |
options.AddProfile<AbpAuditingMapperProfile>(validate: true); |
||||
}); |
}); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,25 +1,30 @@ |
|||||
using AutoMapper; |
using AutoMapper; |
||||
using LINGYUN.Abp.Auditing.Logging; |
using LINGYUN.Abp.Auditing.AuditLogs; |
||||
using LINGYUN.Abp.Auditing.Security; |
using LINGYUN.Abp.Auditing.Logging; |
||||
using Volo.Abp.AuditLogging; |
using LINGYUN.Abp.Auditing.SecurityLogs; |
||||
using Volo.Abp.AutoMapper; |
using LINGYUN.Abp.AuditLogging; |
||||
using Volo.Abp.Identity; |
using LINGYUN.Abp.Logging; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing |
namespace LINGYUN.Abp.Auditing |
||||
{ |
{ |
||||
public class AbpAuditingMapperProfile : Profile |
public class AbpAuditingMapperProfile : Profile |
||||
{ |
{ |
||||
public AbpAuditingMapperProfile() |
public AbpAuditingMapperProfile() |
||||
{ |
{ |
||||
CreateMap<AuditLogAction, AuditLogActionDto>() |
CreateMap<AuditLogAction, AuditLogActionDto>() |
||||
.MapExtraProperties(); |
.MapExtraProperties(); |
||||
CreateMap<EntityPropertyChange, EntityPropertyChangeDto>(); |
CreateMap<EntityPropertyChange, EntityPropertyChangeDto>(); |
||||
CreateMap<EntityChange, EntityChangeDto>() |
CreateMap<EntityChange, EntityChangeDto>() |
||||
.MapExtraProperties(); |
.MapExtraProperties(); |
||||
CreateMap<AuditLog, AuditLogDto>() |
CreateMap<AuditLog, AuditLogDto>() |
||||
.MapExtraProperties(); |
.MapExtraProperties(); |
||||
|
|
||||
CreateMap<IdentitySecurityLog, SecurityLogDto>(); |
CreateMap<SecurityLog, SecurityLogDto>() |
||||
} |
.MapExtraProperties(); |
||||
} |
|
||||
} |
CreateMap<LogField, LogFieldDto>(); |
||||
|
CreateMap<LogException, LogExceptionDto>(); |
||||
|
CreateMap<LogInfo, LogDto>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|||||
@ -0,0 +1,44 @@ |
|||||
|
using LINGYUN.Abp.Logging; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Auditing.Logging |
||||
|
{ |
||||
|
public class LogAppService : AuditingApplicationServiceBase, ILogAppService |
||||
|
{ |
||||
|
private readonly ILoggingManager _manager; |
||||
|
|
||||
|
public LogAppService(ILoggingManager manager) |
||||
|
{ |
||||
|
_manager = manager; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<LogDto> GetAsync(string id) |
||||
|
{ |
||||
|
var log = await _manager.GetAsync(id); |
||||
|
|
||||
|
return ObjectMapper.Map<LogInfo, LogDto>(log); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<PagedResultDto<LogDto>> GetListAsync(LogGetByPagedDto input) |
||||
|
{ |
||||
|
var count = await _manager.GetCountAsync( |
||||
|
input.StartTime, input.EndTime, |
||||
|
input.Context, input.RequestId, input.RequestPath, |
||||
|
input.CorrelationId, input.ProcessId, input.ThreadId, |
||||
|
input.HasException); |
||||
|
|
||||
|
var logs = await _manager.GetListAsync( |
||||
|
input.Sorting, input.MaxResultCount, input.SkipCount, |
||||
|
input.StartTime, input.EndTime, |
||||
|
input.Context, input.RequestId, input.RequestPath, |
||||
|
input.CorrelationId, input.ProcessId, input.ThreadId, |
||||
|
input.HasException, |
||||
|
includeDetails: false); |
||||
|
|
||||
|
return new PagedResultDto<LogDto>(count, |
||||
|
ObjectMapper.Map<List<LogInfo>, List<LogDto>>(logs)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,59 +1,56 @@ |
|||||
using LINGYUN.Abp.Auditing.Features; |
using LINGYUN.Abp.Auditing.Features; |
||||
using LINGYUN.Abp.Auditing.Permissions; |
using LINGYUN.Abp.Auditing.Permissions; |
||||
using Microsoft.AspNetCore.Authorization; |
using LINGYUN.Abp.AuditLogging; |
||||
using System; |
using Microsoft.AspNetCore.Authorization; |
||||
using System.Collections.Generic; |
using System; |
||||
using System.Threading.Tasks; |
using System.Collections.Generic; |
||||
using Volo.Abp.Application.Dtos; |
using System.Threading.Tasks; |
||||
using Volo.Abp.Features; |
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.Identity; |
using Volo.Abp.Features; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Security |
namespace LINGYUN.Abp.Auditing.SecurityLogs |
||||
{ |
{ |
||||
[Authorize(AuditingPermissionNames.SecurityLog.Default)] |
[Authorize(AuditingPermissionNames.SecurityLog.Default)] |
||||
[RequiresFeature(AuditingFeatureNames.Logging.SecurityLog)] |
[RequiresFeature(AuditingFeatureNames.Logging.SecurityLog)] |
||||
public class SecurityLogAppService : AuditingApplicationServiceBase, ISecurityLogAppService |
public class SecurityLogAppService : AuditingApplicationServiceBase, ISecurityLogAppService |
||||
{ |
{ |
||||
protected IIdentitySecurityLogRepository SecurityLogRepository { get; } |
protected ISecurityLogManager SecurityLogManager { get; } |
||||
public SecurityLogAppService(IIdentitySecurityLogRepository securityLogRepository) |
public SecurityLogAppService(ISecurityLogManager securityLogManager) |
||||
{ |
{ |
||||
SecurityLogRepository = securityLogRepository; |
SecurityLogManager = securityLogManager; |
||||
} |
} |
||||
|
|
||||
public virtual async Task<SecurityLogDto> GetAsync(Guid id) |
public virtual async Task<SecurityLogDto> GetAsync(Guid id) |
||||
{ |
{ |
||||
var securityLog = await SecurityLogRepository.GetAsync(id, includeDetails: true); |
var securityLog = await SecurityLogManager.GetAsync(id, includeDetails: true); |
||||
|
|
||||
return ObjectMapper.Map<IdentitySecurityLog, SecurityLogDto>(securityLog); |
return ObjectMapper.Map<SecurityLog, SecurityLogDto>(securityLog); |
||||
} |
} |
||||
|
|
||||
public virtual async Task<PagedResultDto<SecurityLogDto>> GetListAsync(SecurityLogGetByPagedDto input) |
public virtual async Task<PagedResultDto<SecurityLogDto>> GetListAsync(SecurityLogGetByPagedDto input) |
||||
{ |
{ |
||||
var securityLogCount = await SecurityLogRepository |
var securityLogCount = await SecurityLogManager |
||||
.GetCountAsync(input.StartTime, input.EndTime, |
.GetCountAsync(input.StartTime, input.EndTime, |
||||
input.ApplicationName, input.Identity, input.ActionName, |
input.ApplicationName, input.Identity, input.ActionName, |
||||
input.UserId, input.UserName, input.ClientId, input.CorrelationId |
input.UserId, input.UserName, input.ClientId, input.CorrelationId |
||||
); |
); |
||||
|
|
||||
var securityLogs = await SecurityLogRepository |
var securityLogs = await SecurityLogManager |
||||
.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, |
.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, |
||||
input.StartTime, input.EndTime, |
input.StartTime, input.EndTime, |
||||
input.ApplicationName, input.Identity, input.ActionName, |
input.ApplicationName, input.Identity, input.ActionName, |
||||
input.UserId, input.UserName, input.ClientId, input.CorrelationId, |
input.UserId, input.UserName, input.ClientId, input.CorrelationId, |
||||
includeDetails: false |
includeDetails: false |
||||
); |
); |
||||
|
|
||||
return new PagedResultDto<SecurityLogDto>(securityLogCount, |
return new PagedResultDto<SecurityLogDto>(securityLogCount, |
||||
ObjectMapper.Map<List<IdentitySecurityLog>, List<SecurityLogDto>>(securityLogs)); |
ObjectMapper.Map<List<SecurityLog>, List<SecurityLogDto>>(securityLogs)); |
||||
} |
} |
||||
|
|
||||
[Authorize(AuditingPermissionNames.SecurityLog.Delete)] |
[Authorize(AuditingPermissionNames.SecurityLog.Delete)] |
||||
public virtual async Task DeleteAsync(Guid id) |
public virtual async Task DeleteAsync(Guid id) |
||||
{ |
{ |
||||
var securityLog = await SecurityLogRepository.GetAsync(id); |
await SecurityLogManager.DeleteAsync(id); |
||||
await SecurityLogRepository.DeleteAsync(securityLog); |
} |
||||
|
} |
||||
await CurrentUnitOfWork.SaveChangesAsync(); |
} |
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,43 +1,43 @@ |
|||||
using Microsoft.AspNetCore.Mvc; |
using Microsoft.AspNetCore.Mvc; |
||||
using System; |
using System; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Volo.Abp; |
using Volo.Abp; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.AspNetCore.Mvc; |
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Logging |
namespace LINGYUN.Abp.Auditing.AuditLogs |
||||
{ |
{ |
||||
[RemoteService(Name = AuditingRemoteServiceConsts.RemoteServiceName)] |
[RemoteService(Name = AuditingRemoteServiceConsts.RemoteServiceName)] |
||||
[Area("auditing")] |
[Area("auditing")] |
||||
[ControllerName("audit-log")] |
[ControllerName("audit-log")] |
||||
[Route("api/auditing/audit-log")] |
[Route("api/auditing/audit-log")] |
||||
public class AuditLogController : AbpController, IAuditLogAppService |
public class AuditLogController : AbpController, IAuditLogAppService |
||||
{ |
{ |
||||
protected IAuditLogAppService AuditLogAppService { get; } |
protected IAuditLogAppService AuditLogAppService { get; } |
||||
|
|
||||
public AuditLogController(IAuditLogAppService auditLogAppService) |
public AuditLogController(IAuditLogAppService auditLogAppService) |
||||
{ |
{ |
||||
AuditLogAppService = auditLogAppService; |
AuditLogAppService = auditLogAppService; |
||||
} |
} |
||||
|
|
||||
[HttpDelete] |
[HttpDelete] |
||||
[Route("{id}")] |
[Route("{id}")] |
||||
public virtual async Task DeleteAsync(Guid id) |
public virtual async Task DeleteAsync(Guid id) |
||||
{ |
{ |
||||
await AuditLogAppService.DeleteAsync(id); |
await AuditLogAppService.DeleteAsync(id); |
||||
} |
} |
||||
|
|
||||
[HttpGet] |
[HttpGet] |
||||
[Route("{id}")] |
[Route("{id}")] |
||||
public virtual async Task<AuditLogDto> GetAsync(Guid id) |
public virtual async Task<AuditLogDto> GetAsync(Guid id) |
||||
{ |
{ |
||||
return await AuditLogAppService.GetAsync(id); |
return await AuditLogAppService.GetAsync(id); |
||||
} |
} |
||||
|
|
||||
[HttpGet] |
[HttpGet] |
||||
public virtual async Task<PagedResultDto<AuditLogDto>> GetListAsync(AuditLogGetByPagedDto input) |
public virtual async Task<PagedResultDto<AuditLogDto>> GetListAsync(AuditLogGetByPagedDto input) |
||||
{ |
{ |
||||
return await AuditLogAppService.GetListAsync(input); |
return await AuditLogAppService.GetListAsync(input); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Auditing.Logging |
||||
|
{ |
||||
|
[RemoteService(Name = AuditingRemoteServiceConsts.RemoteServiceName)] |
||||
|
[Area("auditing")] |
||||
|
[ControllerName("logging")] |
||||
|
[Route("api/auditing/logging")] |
||||
|
public class LogController : AbpController, ILogAppService |
||||
|
{ |
||||
|
private readonly ILogAppService _service; |
||||
|
|
||||
|
public LogController(ILogAppService service) |
||||
|
{ |
||||
|
_service = service; |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("{id}")] |
||||
|
public virtual async Task<LogDto> GetAsync(string id) |
||||
|
{ |
||||
|
return await _service.GetAsync(id); |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
public virtual async Task<PagedResultDto<LogDto>> GetListAsync(LogGetByPagedDto input) |
||||
|
{ |
||||
|
return await _service.GetListAsync(input); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,43 +1,43 @@ |
|||||
using Microsoft.AspNetCore.Mvc; |
using Microsoft.AspNetCore.Mvc; |
||||
using System; |
using System; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Volo.Abp; |
using Volo.Abp; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.AspNetCore.Mvc; |
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
namespace LINGYUN.Abp.Auditing.Security |
namespace LINGYUN.Abp.Auditing.SecurityLogs |
||||
{ |
{ |
||||
[RemoteService(Name = AuditingRemoteServiceConsts.RemoteServiceName)] |
[RemoteService(Name = AuditingRemoteServiceConsts.RemoteServiceName)] |
||||
[Area("auditing")] |
[Area("auditing")] |
||||
[ControllerName("security-log")] |
[ControllerName("security-log")] |
||||
[Route("api/auditing/security-log")] |
[Route("api/auditing/security-log")] |
||||
public class SecurityLogController : AbpController, ISecurityLogAppService |
public class SecurityLogController : AbpController, ISecurityLogAppService |
||||
{ |
{ |
||||
protected ISecurityLogAppService SecurityLogAppService { get; } |
protected ISecurityLogAppService SecurityLogAppService { get; } |
||||
|
|
||||
public SecurityLogController(ISecurityLogAppService securityLogAppService) |
public SecurityLogController(ISecurityLogAppService securityLogAppService) |
||||
{ |
{ |
||||
SecurityLogAppService = securityLogAppService; |
SecurityLogAppService = securityLogAppService; |
||||
} |
} |
||||
|
|
||||
[HttpDelete] |
[HttpDelete] |
||||
[Route("{id}")] |
[Route("{id}")] |
||||
public virtual async Task DeleteAsync(Guid id) |
public virtual async Task DeleteAsync(Guid id) |
||||
{ |
{ |
||||
await SecurityLogAppService.DeleteAsync(id); |
await SecurityLogAppService.DeleteAsync(id); |
||||
} |
} |
||||
|
|
||||
[HttpGet] |
[HttpGet] |
||||
[Route("{id}")] |
[Route("{id}")] |
||||
public virtual async Task<SecurityLogDto> GetAsync(Guid id) |
public virtual async Task<SecurityLogDto> GetAsync(Guid id) |
||||
{ |
{ |
||||
return await SecurityLogAppService.GetAsync(id); |
return await SecurityLogAppService.GetAsync(id); |
||||
} |
} |
||||
|
|
||||
[HttpGet] |
[HttpGet] |
||||
public virtual async Task<PagedResultDto<SecurityLogDto>> GetListAsync(SecurityLogGetByPagedDto input) |
public virtual async Task<PagedResultDto<SecurityLogDto>> GetListAsync(SecurityLogGetByPagedDto input) |
||||
{ |
{ |
||||
return await SecurityLogAppService.GetListAsync(input); |
return await SecurityLogAppService.GetListAsync(input); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="NEST" Version="7.15.1" /> |
||||
|
<PackageReference Include="Volo.Abp.Core" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,14 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Elasticsearch |
||||
|
{ |
||||
|
public class AbpElasticsearchModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
Configure<AbpElasticsearchOptions>(configuration.GetSection("Elasticsearch")); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
using Elasticsearch.Net; |
||||
|
using Nest; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Elasticsearch |
||||
|
{ |
||||
|
public class AbpElasticsearchOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 字段名称 是否为 camelCase 格式
|
||||
|
/// 如果为true, 在ES中为 camelCase
|
||||
|
/// 如果为false,在ES中为 CamelCase
|
||||
|
/// 默认:false
|
||||
|
/// </summary>
|
||||
|
public bool FieldCamelCase { get; set; } |
||||
|
public string TypeName { get; set; } |
||||
|
public string NodeUris { get; set; } |
||||
|
public int ConnectionLimit { get; set; } |
||||
|
public string UserName { get; set; } |
||||
|
public string Password { get; set; } |
||||
|
public TimeSpan ConnectionTimeout { get; set; } |
||||
|
public IConnection Connection { get; set; } |
||||
|
public ConnectionSettings.SourceSerializerFactory SerializerFactory { get; set; } |
||||
|
|
||||
|
public AbpElasticsearchOptions() |
||||
|
{ |
||||
|
TypeName = "_doc"; |
||||
|
ConnectionLimit = ConnectionConfiguration.DefaultConnectionLimit; |
||||
|
ConnectionTimeout = ConnectionConfiguration.DefaultTimeout; |
||||
|
} |
||||
|
|
||||
|
internal IConnectionSettingsValues CreateConfiguration() |
||||
|
{ |
||||
|
IConnectionPool connectionPool; |
||||
|
IEnumerable<Uri> nodes = NodeUris |
||||
|
.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) |
||||
|
.Select(uriString => new Uri(uriString)); |
||||
|
if (nodes.Count() == 1) |
||||
|
{ |
||||
|
connectionPool = new SingleNodeConnectionPool(nodes.First()); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
connectionPool = new StaticConnectionPool(nodes); |
||||
|
} |
||||
|
|
||||
|
var configuration = new ConnectionSettings( |
||||
|
connectionPool, |
||||
|
Connection, |
||||
|
SerializerFactory) |
||||
|
.ConnectionLimit(ConnectionLimit) |
||||
|
.RequestTimeout(ConnectionTimeout); |
||||
|
|
||||
|
if (!FieldCamelCase) |
||||
|
{ |
||||
|
configuration.DefaultFieldNameInferrer((name) => name); |
||||
|
} |
||||
|
|
||||
|
if (UserName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
configuration.BasicAuthentication(UserName, Password); |
||||
|
} |
||||
|
|
||||
|
return configuration; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using Microsoft.Extensions.Options; |
||||
|
using Nest; |
||||
|
using System; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Elasticsearch |
||||
|
{ |
||||
|
public class ElasticsearchClientFactory : IElasticsearchClientFactory, ISingletonDependency |
||||
|
{ |
||||
|
private readonly AbpElasticsearchOptions _options; |
||||
|
private readonly Lazy<IElasticClient> _lazyClient; |
||||
|
|
||||
|
public ElasticsearchClientFactory( |
||||
|
IOptions<AbpElasticsearchOptions> options) |
||||
|
{ |
||||
|
_options = options.Value; |
||||
|
|
||||
|
_lazyClient = new Lazy<IElasticClient>(CreateClient); |
||||
|
} |
||||
|
|
||||
|
public IElasticClient Create() => _lazyClient.Value; |
||||
|
|
||||
|
protected virtual IElasticClient CreateClient() |
||||
|
{ |
||||
|
var configuration = _options.CreateConfiguration(); |
||||
|
|
||||
|
var client = new ElasticClient(configuration); |
||||
|
|
||||
|
return client; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Nest; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Elasticsearch |
||||
|
{ |
||||
|
public interface IElasticsearchClientFactory |
||||
|
{ |
||||
|
IElasticClient Create(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.4.1" /> |
||||
|
<PackageReference Include="Volo.Abp.AutoMapper" Version="4.4.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Json" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\elasticsearch\LINGYUN.Abp.Elasticsearch\LINGYUN.Abp.Elasticsearch.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Logging\LINGYUN.Abp.Logging.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,14 @@ |
|||||
|
using AutoMapper; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Logging.Serilog.Elasticsearch |
||||
|
{ |
||||
|
public class AbpLoggingSerilogElasticsearchMapperProfile : Profile |
||||
|
{ |
||||
|
public AbpLoggingSerilogElasticsearchMapperProfile() |
||||
|
{ |
||||
|
CreateMap<SerilogException, LogException>(); |
||||
|
CreateMap<SerilogField, LogField>(); |
||||
|
CreateMap<SerilogInfo, LogInfo>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using LINGYUN.Abp.Elasticsearch; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.DependencyInjection.Extensions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.AutoMapper; |
||||
|
using Volo.Abp.Json; |
||||
|
using Volo.Abp.Json.SystemTextJson; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Logging.Serilog.Elasticsearch |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpLoggingModule), |
||||
|
typeof(AbpElasticsearchModule), |
||||
|
typeof(AbpAutoMapperModule), |
||||
|
typeof(AbpJsonModule))] |
||||
|
public class AbpLoggingSerilogElasticsearchModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
|
||||
|
Configure<AbpLoggingSerilogElasticsearchOptions>(configuration.GetSection("Logging:Serilog:Elasticsearch")); |
||||
|
|
||||
|
context.Services.AddAutoMapperObjectMapper<AbpLoggingSerilogElasticsearchModule>(); |
||||
|
|
||||
|
Configure<AbpAutoMapperOptions>(options => |
||||
|
{ |
||||
|
options.AddProfile<AbpLoggingSerilogElasticsearchMapperProfile>(validate: true); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
namespace LINGYUN.Abp.Logging.Serilog.Elasticsearch |
||||
|
{ |
||||
|
public class AbpLoggingSerilogElasticsearchOptions |
||||
|
{ |
||||
|
public string IndexFormat { get; set; } |
||||
|
|
||||
|
public AbpLoggingSerilogElasticsearchOptions() |
||||
|
{ |
||||
|
IndexFormat = "logstash-{0:yyyy.MM.dd}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,265 @@ |
|||||
|
using LINGYUN.Abp.Elasticsearch; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Nest; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text.RegularExpressions; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.ObjectMapping; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Logging.Serilog.Elasticsearch |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class SerilogElasticsearchLoggingManager : ILoggingManager, ISingletonDependency |
||||
|
{ |
||||
|
private static readonly Regex IndexFormatRegex = new Regex(@"^(.*)(?:\{0\:.+\})(.*)$"); |
||||
|
|
||||
|
private readonly IObjectMapper _objectMapper; |
||||
|
private readonly AbpLoggingSerilogElasticsearchOptions _options; |
||||
|
private readonly IElasticsearchClientFactory _clientFactory; |
||||
|
|
||||
|
public ILogger<SerilogElasticsearchLoggingManager> Logger { protected get; set; } |
||||
|
|
||||
|
public SerilogElasticsearchLoggingManager( |
||||
|
IObjectMapper objectMapper, |
||||
|
IOptions<AbpLoggingSerilogElasticsearchOptions> options, |
||||
|
IElasticsearchClientFactory clientFactory) |
||||
|
{ |
||||
|
_objectMapper = objectMapper; |
||||
|
_clientFactory = clientFactory; |
||||
|
_options = options.Value; |
||||
|
|
||||
|
Logger = NullLogger<SerilogElasticsearchLoggingManager>.Instance; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
///
|
||||
|
/// </summary>
|
||||
|
/// <param name="id">时间类型或者转换为timestamp都可以查询</param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public virtual async Task<LogInfo> GetAsync( |
||||
|
string id, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var response = await client.SearchAsync<SerilogInfo>( |
||||
|
dsl => |
||||
|
dsl.Index(CreateIndex()) |
||||
|
.Query( |
||||
|
(q) => q.Bool( |
||||
|
(b) => b.Should( |
||||
|
(s) => s.Term( |
||||
|
(t) => t.Field("@timestamp").Value(id))))), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return _objectMapper.Map<SerilogInfo, LogInfo>(response.Documents.FirstOrDefault()); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string context = null, |
||||
|
string requestId = null, |
||||
|
string requestPath = null, |
||||
|
string correlationId = null, |
||||
|
int? processId = null, |
||||
|
int? threadId = null, |
||||
|
bool? hasException = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var querys = BuildQueryDescriptor( |
||||
|
startTime, |
||||
|
endTime, |
||||
|
context, |
||||
|
requestId, |
||||
|
requestPath, |
||||
|
correlationId, |
||||
|
processId, |
||||
|
threadId, |
||||
|
hasException); |
||||
|
|
||||
|
var response = await client.CountAsync<SerilogInfo>((dsl) => |
||||
|
dsl.Index(CreateIndex()) |
||||
|
.Query(log => log.Bool(b => b.Must(querys.ToArray()))), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return response.Count; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取日志列表
|
||||
|
/// </summary>
|
||||
|
/// <param name="sorting">排序字段,注意:忽略排序字段仅使用timestamp排序,根据传递的ASC、DESC字段区分倒序还是正序</param>
|
||||
|
/// <param name="maxResultCount"></param>
|
||||
|
/// <param name="skipCount"></param>
|
||||
|
/// <param name="startTime"></param>
|
||||
|
/// <param name="endTime"></param>
|
||||
|
/// <param name="context"></param>
|
||||
|
/// <param name="requestId"></param>
|
||||
|
/// <param name="requestPath"></param>
|
||||
|
/// <param name="correlationId"></param>
|
||||
|
/// <param name="processId"></param>
|
||||
|
/// <param name="threadId"></param>
|
||||
|
/// <param name="hasException"></param>
|
||||
|
/// <param name="includeDetails"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public virtual async Task<List<LogInfo>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string context = null, |
||||
|
string requestId = null, |
||||
|
string requestPath = null, |
||||
|
string correlationId = null, |
||||
|
int? processId = null, |
||||
|
int? threadId = null, |
||||
|
bool? hasException = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)) |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
|
||||
|
var sortOrder = !sorting.IsNullOrWhiteSpace() && sorting.EndsWith("desc", StringComparison.InvariantCultureIgnoreCase) |
||||
|
? SortOrder.Descending : SortOrder.Ascending; |
||||
|
|
||||
|
var querys = BuildQueryDescriptor( |
||||
|
startTime, |
||||
|
endTime, |
||||
|
context, |
||||
|
requestId, |
||||
|
requestPath, |
||||
|
correlationId, |
||||
|
processId, |
||||
|
threadId, |
||||
|
hasException); |
||||
|
|
||||
|
SourceFilterDescriptor<SerilogInfo> ConvertFileSystem(SourceFilterDescriptor<SerilogInfo> selector) |
||||
|
{ |
||||
|
selector.IncludeAll(); |
||||
|
if (!includeDetails) |
||||
|
{ |
||||
|
selector.Excludes(field => |
||||
|
field.Field("exceptions")); |
||||
|
} |
||||
|
|
||||
|
return selector; |
||||
|
} |
||||
|
|
||||
|
var response = await client.SearchAsync<SerilogInfo>((dsl) => |
||||
|
dsl.Index(CreateIndex()) |
||||
|
.Query(log => log.Bool(b => b.Must(querys.ToArray()))) |
||||
|
.Source(ConvertFileSystem) |
||||
|
.Sort(log => log.Field("@timestamp", sortOrder)) |
||||
|
.From(skipCount) |
||||
|
.Size(maxResultCount), |
||||
|
cancellationToken); |
||||
|
|
||||
|
return _objectMapper.Map<List<SerilogInfo>, List<LogInfo>>(response.Documents.ToList()); |
||||
|
} |
||||
|
|
||||
|
protected virtual List<Func<QueryContainerDescriptor<SerilogInfo>, QueryContainer>> BuildQueryDescriptor( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string context = null, |
||||
|
string requestId = null, |
||||
|
string requestPath = null, |
||||
|
string correlationId = null, |
||||
|
int? processId = null, |
||||
|
int? threadId = null, |
||||
|
bool? hasException = null) |
||||
|
{ |
||||
|
var querys = new List<Func<QueryContainerDescriptor<SerilogInfo>, QueryContainer>>(); |
||||
|
|
||||
|
if (startTime.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.DateRange((q) => q.Field(f => f.TimeStamp).GreaterThanOrEquals(startTime))); |
||||
|
} |
||||
|
if (endTime.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.DateRange((q) => q.Field(f => f.TimeStamp).LessThanOrEquals(endTime))); |
||||
|
} |
||||
|
if (!context.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field((f) => f.Fields.Context.Suffix("keyword")).Value(context))); |
||||
|
} |
||||
|
if (!requestId.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Match((q) => q.Field(f => f.Fields.RequestId.Suffix("keyword")).Query(requestId))); |
||||
|
} |
||||
|
if (!requestPath.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.Fields.RequestPath.Suffix("keyword")).Value(requestPath))); |
||||
|
} |
||||
|
if (!correlationId.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.Fields.CorrelationId.Suffix("keyword")).Value(correlationId))); |
||||
|
} |
||||
|
if (processId.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.Fields.ProcessId).Value(processId))); |
||||
|
} |
||||
|
if (threadId.HasValue) |
||||
|
{ |
||||
|
querys.Add((log) => log.Term((q) => q.Field(f => f.Fields.ThreadId).Value(threadId))); |
||||
|
} |
||||
|
|
||||
|
if (hasException.HasValue) |
||||
|
{ |
||||
|
if (hasException.Value) |
||||
|
{ |
||||
|
/* 存在exceptions字段则就是有异常信息 |
||||
|
* "exists": { |
||||
|
"field": "exceptions" |
||||
|
} |
||||
|
*/ |
||||
|
querys.Add( |
||||
|
(q) => q.Exists( |
||||
|
(e) => e.Field("exceptions"))); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// 不存在 exceptions字段就是没有异常信息的消息
|
||||
|
/* |
||||
|
* "bool": { |
||||
|
"must_not": [ |
||||
|
{ |
||||
|
"exists": { |
||||
|
"field": "exceptions" |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
*/ |
||||
|
querys.Add( |
||||
|
(q) => q.Bool( |
||||
|
(b) => b.MustNot( |
||||
|
(m) => m.Exists( |
||||
|
(e) => e.Field("exceptions"))))); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return querys; |
||||
|
} |
||||
|
|
||||
|
protected virtual string CreateIndex(DateTimeOffset? offset = null) |
||||
|
{ |
||||
|
if (!offset.HasValue) |
||||
|
{ |
||||
|
return IndexFormatRegex.Replace(_options.IndexFormat, @"$1*$2"); |
||||
|
} |
||||
|
return string.Format(_options.IndexFormat, offset.Value).ToLowerInvariant(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
namespace LINGYUN.Abp.Logging.Serilog.Elasticsearch |
||||
|
{ |
||||
|
public class SerilogException |
||||
|
{ |
||||
|
[Nest.PropertyName("SourceContext")] |
||||
|
public int Depth { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("ClassName")] |
||||
|
public string Class { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("Message")] |
||||
|
public string Message { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("Source")] |
||||
|
public string Source { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("StackTraceString")] |
||||
|
public string StackTrace { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("HResult")] |
||||
|
public int HResult { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("HelpURL")] |
||||
|
public string HelpURL { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
namespace LINGYUN.Abp.Logging.Serilog.Elasticsearch |
||||
|
{ |
||||
|
public class SerilogField |
||||
|
{ |
||||
|
[Nest.PropertyName("SourceContext")] |
||||
|
public string Context { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("ActionId")] |
||||
|
public string ActionId { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("ActionName")] |
||||
|
public string ActionName { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("RequestId")] |
||||
|
public string RequestId { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("RequestPath")] |
||||
|
public string RequestPath { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("ConnectionId")] |
||||
|
public string ConnectionId { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("CorrelationId")] |
||||
|
public string CorrelationId { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("ClientId")] |
||||
|
public string ClientId { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("UserId")] |
||||
|
public string UserId { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("ProcessId")] |
||||
|
public int ProcessId { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("ThreadId")] |
||||
|
public int ThreadId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Serilog.Formatting.Elasticsearch; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Logging.Serilog.Elasticsearch |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class SerilogInfo |
||||
|
{ |
||||
|
[Nest.PropertyName(ElasticsearchJsonFormatter.TimestampPropertyName)] |
||||
|
public DateTime TimeStamp { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName(ElasticsearchJsonFormatter.LevelPropertyName)] |
||||
|
public LogLevel Level { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName(ElasticsearchJsonFormatter.RenderedMessagePropertyName)] |
||||
|
public string Message { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("fields")] |
||||
|
public SerilogField Fields { get; set; } |
||||
|
|
||||
|
[Nest.PropertyName("exceptions")] |
||||
|
public List<SerilogException> Exceptions { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Core" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Logging |
||||
|
{ |
||||
|
public class AbpLoggingModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
using LINGYUN.Abp.Logging; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[Dependency(TryRegister = true)] |
||||
|
public class DefaultLoggingManager : ILoggingManager, ISingletonDependency |
||||
|
{ |
||||
|
public ILogger<DefaultLoggingManager> Logger { protected get; set; } |
||||
|
|
||||
|
public DefaultLoggingManager() |
||||
|
{ |
||||
|
Logger = NullLogger<DefaultLoggingManager>.Instance; |
||||
|
} |
||||
|
|
||||
|
public Task<LogInfo> GetAsync(string id, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Logger.LogDebug("No logging manager is available!"); |
||||
|
LogInfo logInfo = null; |
||||
|
return Task.FromResult(logInfo); |
||||
|
} |
||||
|
|
||||
|
public Task<long> GetCountAsync(DateTime? startTime = null, DateTime? endTime = null, string context = null, string requestId = null, string requestPath = null, string correlationId = null, int? processId = null, int? threadId = null, bool? hasException = null, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Logger.LogDebug("No logging manager is available!"); |
||||
|
return Task.FromResult(0L); |
||||
|
} |
||||
|
|
||||
|
public Task<List<LogInfo>> GetListAsync(string sorting = null, int maxResultCount = 50, int skipCount = 0, DateTime? startTime = null, DateTime? endTime = null, string context = null, string requestId = null, string requestPath = null, string correlationId = null, int? processId = null, int? threadId = null, bool? hasException = null, bool includeDetails = false, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Logger.LogDebug("No logging manager is available!"); |
||||
|
return Task.FromResult(new List<LogInfo>()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Logging |
||||
|
{ |
||||
|
public interface ILoggingManager |
||||
|
{ |
||||
|
Task<LogInfo> GetAsync( |
||||
|
string id, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
Task<long> GetCountAsync( |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string context = null, |
||||
|
string requestId = null, |
||||
|
string requestPath = null, |
||||
|
string correlationId = null, |
||||
|
int? processId = null, |
||||
|
int? threadId = null, |
||||
|
bool? hasException = null, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
|
||||
|
Task<List<LogInfo>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
string context = null, |
||||
|
string requestId = null, |
||||
|
string requestPath = null, |
||||
|
string correlationId = null, |
||||
|
int? processId = null, |
||||
|
int? threadId = null, |
||||
|
bool? hasException = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default(CancellationToken)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
namespace LINGYUN.Abp.Logging |
||||
|
{ |
||||
|
public class LogException |
||||
|
{ |
||||
|
public int Depth { get; set; } |
||||
|
public string Class { get; set; } |
||||
|
public string Message { get; set; } |
||||
|
public string Source { get; set; } |
||||
|
public string StackTrace { get; set; } |
||||
|
public int HResult { get; set; } |
||||
|
public string HelpURL { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
namespace LINGYUN.Abp.Logging |
||||
|
{ |
||||
|
public class LogField |
||||
|
{ |
||||
|
public string Context { get; set; } |
||||
|
public string ActionId { get; set; } |
||||
|
public string ActionName { get; set; } |
||||
|
public string RequestId { get; set; } |
||||
|
public string RequestPath { get; set; } |
||||
|
public string ConnectionId { get; set; } |
||||
|
public string CorrelationId { get; set; } |
||||
|
public string ClientId { get; set; } |
||||
|
public string UserId { get; set; } |
||||
|
public int ProcessId { get; set; } |
||||
|
public int ThreadId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Logging |
||||
|
{ |
||||
|
public class LogInfo |
||||
|
{ |
||||
|
public DateTime TimeStamp { get; set; } |
||||
|
public LogLevel Level { get; set; } |
||||
|
public string Message { get; set; } |
||||
|
public LogField Fields { get; set; } |
||||
|
public List<LogException> Exceptions { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<PropertyGroup> |
||||
|
<ShowAllFiles>false</ShowAllFiles> |
||||
|
</PropertyGroup> |
||||
|
</Project> |
||||
@ -1,4 +1,5 @@ |
|||||
bin |
bin |
||||
obj |
obj |
||||
Logs |
Logs |
||||
appsettings.*.json |
appsettings.*.json |
||||
|
Modules |
||||
@ -0,0 +1,18 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
||||
|
<PackageReference Include="Moq.AutoMock" Version="3.0.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\modules\auditing\LINGYUN.Abp.AuditLogging.Elasticsearch\LINGYUN.Abp.AuditLogging.Elasticsearch.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" /> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,15 @@ |
|||||
|
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 |
||||
|
{ |
||||
|
public abstract class AbpAuditLoggingElasticsearchTestBase : AbpTestsBase<AbpAuditLoggingElasticsearchTestModule> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using LINGYUN.Abp.Elasticsearch; |
||||
|
using LINGYUN.Abp.Tests; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpTestsBaseModule), |
||||
|
typeof(AbpAuditLoggingElasticsearchModule))] |
||||
|
public class AbpAuditLoggingElasticsearchTestModule : AbpModule |
||||
|
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configurationOptions = new AbpConfigurationBuilderOptions |
||||
|
{ |
||||
|
BasePath = @"D:\Projects\Development\Abp\AuditLogging\Elasticsearch", |
||||
|
EnvironmentName = "Development" |
||||
|
}; |
||||
|
|
||||
|
context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(configurationOptions)); |
||||
|
} |
||||
|
|
||||
|
public override void OnApplicationShutdown(ApplicationShutdownContext context) |
||||
|
{ |
||||
|
var options = context.ServiceProvider.GetRequiredService<IOptions<AbpAuditLoggingElasticsearchOptions>>().Value; |
||||
|
var clientFactory = context.ServiceProvider.GetRequiredService<IElasticsearchClientFactory>(); |
||||
|
var client = clientFactory.Create(); |
||||
|
var indicesResponse = client.Cat.Indices(i => i.Index($"{options.IndexPrefix}-security-log")); |
||||
|
foreach (var index in indicesResponse.Records) |
||||
|
{ |
||||
|
client.Indices.Delete(index.Index); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,121 @@ |
|||||
|
using Moq.AutoMock; |
||||
|
using Shouldly; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
public class AuditLogManagerTests : AbpAuditLoggingElasticsearchTestBase |
||||
|
{ |
||||
|
private readonly IAuditLogManager _manager; |
||||
|
|
||||
|
public AuditLogManagerTests() |
||||
|
{ |
||||
|
_manager = GetRequiredService<IAuditLogManager>(); |
||||
|
} |
||||
|
|
||||
|
public async Task Save_Audit_Log_Should_Be_Find_By_Id() |
||||
|
{ |
||||
|
var mock = new AutoMocker(); |
||||
|
var auditLogInfo = mock.CreateInstance<AuditLogInfo>(); |
||||
|
|
||||
|
var id = await _manager.SaveAsync(auditLogInfo); |
||||
|
id.ShouldNotBeNullOrWhiteSpace(); |
||||
|
|
||||
|
var findId = Guid.Parse(id); |
||||
|
var auditLog = await _manager.GetAsync(findId); |
||||
|
|
||||
|
auditLog.ShouldNotBeNull(); |
||||
|
auditLog.Id.ShouldBe(findId); |
||||
|
|
||||
|
await _manager.DeleteAsync(findId); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Save_Audit_Log_Should_Get_List() |
||||
|
{ |
||||
|
//await MockcAsync(10);
|
||||
|
|
||||
|
// 异常应该只有3个
|
||||
|
(await _manager.GetCountAsync( |
||||
|
hasException: true)).ShouldBe(3); |
||||
|
|
||||
|
// 正常可以查询7个
|
||||
|
(await _manager.GetCountAsync( |
||||
|
hasException: false)).ShouldBe(7); |
||||
|
|
||||
|
// POST方法能查到5个
|
||||
|
(await _manager.GetCountAsync( |
||||
|
httpMethod: "POST")).ShouldBe(5); |
||||
|
|
||||
|
(await _manager.GetCountAsync( |
||||
|
startTime: DateTime.Now.AddDays(-1).AddHours(5))).ShouldBe(6); |
||||
|
|
||||
|
(await _manager.GetCountAsync( |
||||
|
endTime: DateTime.Now.AddDays(-1))).ShouldBe(4); |
||||
|
|
||||
|
(await _manager.GetCountAsync( |
||||
|
startTime: DateTime.Now.AddDays(-3).AddHours(1), |
||||
|
endTime: DateTime.Now)).ShouldBe(8); |
||||
|
|
||||
|
// 索引5只存在一个
|
||||
|
(await _manager.GetCountAsync( |
||||
|
userName: "_user_5", |
||||
|
clientId: "_client_5")).ShouldBe(1); |
||||
|
|
||||
|
var logs = await _manager.GetListAsync( |
||||
|
userName: "_user_5", |
||||
|
clientId: "_client_5"); |
||||
|
|
||||
|
logs.Count.ShouldBe(1); |
||||
|
logs[0].Url.ShouldBe("_url_5"); |
||||
|
logs[0].BrowserInfo.ShouldBe("_browser_5"); |
||||
|
logs[0].ApplicationName.ShouldBe("_app_5"); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<List<string>> MockcAsync(int count) |
||||
|
{ |
||||
|
var mock = new AutoMocker(); |
||||
|
|
||||
|
var auditLogIds = new List<string>(); |
||||
|
|
||||
|
for (int i = 1; i <= count; i++) |
||||
|
{ |
||||
|
var auditLogInfo = mock.CreateInstance<AuditLogInfo>(); |
||||
|
auditLogInfo.ClientId = $"_client_{i}"; |
||||
|
auditLogInfo.Url = $"_url_{i}"; |
||||
|
auditLogInfo.UserName = $"_user_{i}"; |
||||
|
auditLogInfo.ApplicationName = $"_app_{i}"; |
||||
|
auditLogInfo.BrowserInfo = $"_browser_{i}"; |
||||
|
auditLogInfo.ExecutionTime = DateTime.Now; |
||||
|
|
||||
|
if (i % 3 == 0) |
||||
|
{ |
||||
|
auditLogInfo.Exceptions.Add(new Exception($"_exception_{i}")); |
||||
|
} |
||||
|
|
||||
|
if (i % 2 == 0) |
||||
|
{ |
||||
|
auditLogInfo.HttpMethod = "POST"; |
||||
|
} |
||||
|
|
||||
|
if (i % 4 == 0) |
||||
|
{ |
||||
|
auditLogInfo.ExecutionTime = DateTime.Now.AddDays(-3); |
||||
|
} |
||||
|
|
||||
|
if (i % 5 == 0) |
||||
|
{ |
||||
|
auditLogInfo.ExecutionTime = DateTime.Now.AddDays(-2); |
||||
|
} |
||||
|
|
||||
|
auditLogIds.Add(await _manager.SaveAsync(auditLogInfo)); |
||||
|
} |
||||
|
|
||||
|
return auditLogIds; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue