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 const string DefaultIndexPrefix = "auditlogging"; |
|||
public string IndexPrefix { get; set; } |
|||
public IIndexSettings IndexSettings { get; set; } |
|||
|
|||
public AbpAuditLoggingElasticsearchOptions() |
|||
{ |
|||
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