13 changed files with 286 additions and 32 deletions
@ -1,13 +1,17 @@ |
|||||
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
using Nest; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
{ |
{ |
||||
public class AbpAuditLoggingElasticsearchOptions |
public class AbpAuditLoggingElasticsearchOptions |
||||
{ |
{ |
||||
public const string DefaultIndexPrefix = "auditlogging"; |
public const string DefaultIndexPrefix = "auditlogging"; |
||||
public string IndexPrefix { get; set; } |
public string IndexPrefix { get; set; } |
||||
|
public IIndexSettings IndexSettings { get; set; } |
||||
|
|
||||
public AbpAuditLoggingElasticsearchOptions() |
public AbpAuditLoggingElasticsearchOptions() |
||||
{ |
{ |
||||
IndexPrefix = DefaultIndexPrefix; |
IndexPrefix = DefaultIndexPrefix; |
||||
|
IndexSettings = new IndexSettings(); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
public interface IIndexInitializer |
||||
|
{ |
||||
|
Task InitializeAsync(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
public interface IIndexNameNormalizer |
||||
|
{ |
||||
|
string NormalizeIndex(string index); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,106 @@ |
|||||
|
using LINGYUN.Abp.Elasticsearch; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Nest; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
public class IndexInitializer : IIndexInitializer, ISingletonDependency |
||||
|
{ |
||||
|
private readonly AbpJsonOptions _jsonOptions; |
||||
|
private readonly AbpAuditLoggingElasticsearchOptions _elasticsearchOptions; |
||||
|
private readonly IIndexNameNormalizer _nameNormalizer; |
||||
|
private readonly IElasticsearchClientFactory _clientFactory; |
||||
|
|
||||
|
public ILogger<IndexInitializer> Logger { protected get; set; } |
||||
|
|
||||
|
public IndexInitializer( |
||||
|
IOptions<AbpJsonOptions> jsonOptions, |
||||
|
IOptions<AbpAuditLoggingElasticsearchOptions> elasticsearchOptions, |
||||
|
IIndexNameNormalizer nameNormalizer, |
||||
|
IElasticsearchClientFactory clientFactory) |
||||
|
{ |
||||
|
_jsonOptions = jsonOptions.Value; |
||||
|
_elasticsearchOptions = elasticsearchOptions.Value; |
||||
|
_nameNormalizer = nameNormalizer; |
||||
|
_clientFactory = clientFactory; |
||||
|
|
||||
|
Logger = NullLogger<IndexInitializer>.Instance; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task InitializeAsync() |
||||
|
{ |
||||
|
var client = _clientFactory.Create(); |
||||
|
var dateTimeFormat = !_jsonOptions.DefaultDateTimeFormat.IsNullOrWhiteSpace() |
||||
|
? $"{_jsonOptions.DefaultDateTimeFormat}||strict_date_optional_time||epoch_millis" |
||||
|
: "strict_date_optional_time||epoch_millis"; |
||||
|
var indexState = new IndexState |
||||
|
{ |
||||
|
Settings = _elasticsearchOptions.IndexSettings, |
||||
|
}; |
||||
|
await InitlizeAuditLogIndex(client, indexState, dateTimeFormat); |
||||
|
await InitlizeSecurityLogIndex(client, indexState, dateTimeFormat); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task InitlizeAuditLogIndex(IElasticClient client, IIndexState indexState, string dateTimeFormat) |
||||
|
{ |
||||
|
var indexName = _nameNormalizer.NormalizeIndex("audit-log"); |
||||
|
var indexExists = await client.Indices.ExistsAsync(indexName); |
||||
|
if (!indexExists.Exists) |
||||
|
{ |
||||
|
var indexCreateResponse = await client.Indices.CreateAsync( |
||||
|
indexName, |
||||
|
dsl => dsl.InitializeUsing(indexState) |
||||
|
.Map<AuditLog>(map => |
||||
|
map.AutoMap() |
||||
|
.Properties(mp => |
||||
|
mp.Date(p => p.Name(n => n.ExecutionTime).Format(dateTimeFormat)) |
||||
|
.Object<ExtraPropertyDictionary>(p => p.Name(n => n.ExtraProperties)) |
||||
|
.Nested<EntityChange>(n => |
||||
|
n.AutoMap() |
||||
|
.Name(nameof(AuditLog.EntityChanges)) |
||||
|
.Properties(np => |
||||
|
np.Object<ExtraPropertyDictionary>(p => p.Name(n => n.ExtraProperties)) |
||||
|
.Date(p => p.Name(n => n.ChangeTime).Format(dateTimeFormat)) |
||||
|
.Nested<EntityPropertyChange>(npn => npn.Name(nameof(EntityChange.PropertyChanges))))) |
||||
|
.Nested<AuditLogAction>(n => n.Name(nameof(AuditLog.Actions)) |
||||
|
.AutoMap() |
||||
|
.Properties((np => |
||||
|
np.Object<ExtraPropertyDictionary>(p => p.Name(n => n.ExtraProperties)) |
||||
|
.Date(p => p.Name(n => n.ExecutionTime).Format(dateTimeFormat)))))))); |
||||
|
if (indexCreateResponse.IsValid) |
||||
|
{ |
||||
|
Logger.LogWarning("Failed to initialize index and audit log may not be retrieved."); |
||||
|
Logger.LogWarning(indexCreateResponse.OriginalException.ToString()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task InitlizeSecurityLogIndex(IElasticClient client, IIndexState indexState, string dateTimeFormat) |
||||
|
{ |
||||
|
var indexName = _nameNormalizer.NormalizeIndex("security-log"); |
||||
|
var indexExists = await client.Indices.ExistsAsync(indexName); |
||||
|
if (!indexExists.Exists) |
||||
|
{ |
||||
|
var indexCreateResponse = await client.Indices.CreateAsync( |
||||
|
indexName, |
||||
|
dsl => dsl.InitializeUsing(indexState) |
||||
|
.Map<SecurityLog>(map => |
||||
|
map.AutoMap() |
||||
|
.Properties(mp => |
||||
|
mp.Object<ExtraPropertyDictionary>(p => p.Name(n => n.ExtraProperties)) |
||||
|
.Date(p => p.Name(n => n.CreationTime).Format(dateTimeFormat))))); |
||||
|
if (indexCreateResponse.IsValid) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using Microsoft.Extensions.Hosting; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
public class IndexInitializerService : BackgroundService |
||||
|
{ |
||||
|
private readonly IIndexInitializer _indexInitializer; |
||||
|
|
||||
|
public IndexInitializerService(IIndexInitializer indexInitializer) |
||||
|
{ |
||||
|
_indexInitializer = indexInitializer; |
||||
|
} |
||||
|
|
||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken) |
||||
|
{ |
||||
|
await _indexInitializer.InitializeAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging.Elasticsearch |
||||
|
{ |
||||
|
public class IndexNameNormalizer : IIndexNameNormalizer, ISingletonDependency |
||||
|
{ |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
private readonly AbpAuditLoggingElasticsearchOptions _options; |
||||
|
|
||||
|
public IndexNameNormalizer( |
||||
|
ICurrentTenant currentTenant, |
||||
|
IOptions<AbpAuditLoggingElasticsearchOptions> options) |
||||
|
{ |
||||
|
_currentTenant = currentTenant; |
||||
|
_options = options.Value; |
||||
|
} |
||||
|
|
||||
|
public string NormalizeIndex(string index) |
||||
|
{ |
||||
|
if (_currentTenant.IsAvailable) |
||||
|
{ |
||||
|
return $"{_options.IndexPrefix}-{index}-{_currentTenant.Id:N}"; |
||||
|
} |
||||
|
return _options.IndexPrefix.IsNullOrWhiteSpace() |
||||
|
? index |
||||
|
: $"{_options.IndexPrefix}-{index}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
[Dependency(TryRegister = true)] |
||||
|
public class DefaultEntityChangeStore : IEntityChangeStore, ISingletonDependency |
||||
|
{ |
||||
|
public Task<EntityChange> GetAsync(Guid entityChangeId, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
EntityChange entityChange = null; |
||||
|
return Task.FromResult(entityChange); |
||||
|
} |
||||
|
|
||||
|
public Task<long> GetCountAsync(Guid? auditLogId = null, DateTime? startTime = null, DateTime? endTime = null, EntityChangeType? changeType = null, string entityId = null, string entityTypeFullName = null, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return Task.FromResult(0L); |
||||
|
} |
||||
|
|
||||
|
public Task<List<EntityChange>> GetListAsync(string sorting = null, int maxResultCount = 50, int skipCount = 0, Guid? auditLogId = null, DateTime? startTime = null, DateTime? endTime = null, EntityChangeType? changeType = null, string entityId = null, string entityTypeFullName = null, bool includeDetails = false, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return Task.FromResult(new List<EntityChange>()); |
||||
|
} |
||||
|
|
||||
|
public Task<EntityChangeWithUsername> GetWithUsernameAsync(Guid entityChangeId, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
EntityChangeWithUsername entityChange = null; |
||||
|
return Task.FromResult(entityChange); |
||||
|
} |
||||
|
|
||||
|
public Task<List<EntityChangeWithUsername>> GetWithUsernameAsync(string entityId, string entityTypeFullName, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return Task.FromResult(new List<EntityChangeWithUsername>()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
public class EntityChangeWithUsername |
||||
|
{ |
||||
|
public EntityChange EntityChange { get; set; } |
||||
|
|
||||
|
public string UserName { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Auditing; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AuditLogging |
||||
|
{ |
||||
|
public interface IEntityChangeStore |
||||
|
{ |
||||
|
Task<EntityChange> GetAsync( |
||||
|
Guid entityChangeId, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<long> GetCountAsync( |
||||
|
Guid? auditLogId = null, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
EntityChangeType? changeType = null, |
||||
|
string entityId = null, |
||||
|
string entityTypeFullName = null, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<EntityChange>> GetListAsync( |
||||
|
string sorting = null, |
||||
|
int maxResultCount = 50, |
||||
|
int skipCount = 0, |
||||
|
Guid? auditLogId = null, |
||||
|
DateTime? startTime = null, |
||||
|
DateTime? endTime = null, |
||||
|
EntityChangeType? changeType = null, |
||||
|
string entityId = null, |
||||
|
string entityTypeFullName = null, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<EntityChangeWithUsername> GetWithUsernameAsync( |
||||
|
Guid entityChangeId, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<EntityChangeWithUsername>> GetWithUsernameAsync( |
||||
|
string entityId, |
||||
|
string entityTypeFullName, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue