You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
18 KiB
18 KiB
执行日志
**本文档中引用的文件** - [AuditLog.cs](file://aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging/LINGYUN/Abp/AuditLogging/AuditLog.cs) - [AuditLogManager.cs](file://aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN/Abp/AuditLogging/EntityFrameworkCore/AuditLogManager.cs) - [BackgroundJobLog.cs](file://aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobLog.cs) - [BackgroundJobLogAppService.cs](file://aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Application/LINGYUN/Abp/TaskManagement/BackgroundJobLogAppService.cs) - [EfCoreBackgroundJobLogRepository.cs](file://aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.EntityFrameworkCore/LINGYUN/Abp/TaskManagement/EntityFrameworkCore/EfCoreBackgroundJobLogRepository.cs) - [AbpBackgroundTasksOptions.cs](file://aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs) - [JobLogEvent.cs](file://aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/Internal/JobLogEvent.cs) - [BackgroundJobStore.cs](file://aspnet-core/modules/task-management/LINGYUN.Abp.TaskManagement.Domain/LINGYUN/Abp/TaskManagement/BackgroundJobStore.cs)目录
简介
执行日志系统是ABP Next Admin框架中的重要组成部分,负责记录和管理各种类型的作业执行过程。该系统提供了完整的审计日志功能和专门的任务执行日志记录,支持批量写入、多维度查询、分页处理以及自动归档等功能。
系统主要包含两个核心日志类型:
- 审计日志(AuditLog):记录应用程序级别的操作审计信息
- 作业日志(BackgroundJobLog):专门记录后台任务的执行详情
这些日志系统为监控系统集成、问题诊断和合规性要求提供了强大的数据支持。
项目结构
执行日志系统的文件组织结构如下:
graph TB
subgraph "审计日志模块"
A[AuditLog.cs<br/>审计日志实体]
B[AuditLogManager.cs<br/>审计日志管理器]
C[IAuditLogManager.cs<br/>审计日志接口]
end
subgraph "任务日志模块"
D[BackgroundJobLog.cs<br/>作业日志实体]
E[BackgroundJobLogAppService.cs<br/>作业日志应用服务]
F[EfCoreBackgroundJobLogRepository.cs<br/>作业日志仓储]
end
subgraph "配置模块"
G[AbpBackgroundTasksOptions.cs<br/>任务配置选项]
H[JobLogEvent.cs<br/>作业日志事件]
end
A --> B
B --> C
D --> E
E --> F
G --> H
H --> D
图表来源
- AuditLog.cs
- BackgroundJobLog.cs
核心组件
审计日志实体(AuditLog)
审计日志实体是整个审计系统的核心数据结构,包含了详细的执行信息:
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 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; }
}
作业日志实体(BackgroundJobLog)
作业日志实体专门用于记录后台任务的执行情况:
public class BackgroundJobLog : Entity<long>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual string JobId { get; set; }
public virtual string JobName { get; protected set; }
public virtual string JobGroup { get; protected set; }
public virtual string JobType { get; protected set; }
public virtual string Message { get; protected set; }
public virtual DateTime RunTime { get; protected set; }
public virtual string Exception { get; protected set; }
public BackgroundJobLog SetMessage(string message, Exception ex)
{
Message = message.Length > BackgroundJobLogConsts.MaxMessageLength
? message.Substring(0, BackgroundJobLogConsts.MaxMessageLength - 1)
: message;
if (ex != null)
{
var errMsg = ex.ToString();
Exception = errMsg.Length > BackgroundJobLogConsts.MaxExceptionLength
? errMsg.Substring(0, BackgroundJobLogConsts.MaxExceptionLength - 1)
: errMsg;
}
return this;
}
}
章节来源
- AuditLog.cs
- BackgroundJobLog.cs
架构概览
执行日志系统采用分层架构设计,确保了良好的可扩展性和维护性:
graph TB
subgraph "表现层"
A[HTTP API]
B[应用服务层]
end
subgraph "业务逻辑层"
C[审计日志管理器]
D[作业日志管理器]
E[作业事件处理器]
end
subgraph "数据访问层"
F[EF Core仓储]
G[数据库上下文]
end
subgraph "持久化层"
H[(关系型数据库)]
I[(可选:Elasticsearch)]
end
A --> B
B --> C
B --> D
C --> F
D --> F
E --> D
F --> G
G --> H
G --> I
图表来源
- AuditLogManager.cs
- BackgroundJobLogAppService.cs
详细组件分析
审计日志管理系统
审计日志管理系统提供了完整的CRUD操作和高级查询功能:
classDiagram
class AuditLogManager {
+IObjectMapper ObjectMapper
+IAuditLogRepository AuditLogRepository
+IUnitOfWorkManager UnitOfWorkManager
+AbpAuditingOptions Options
+IAuditLogInfoToAuditLogConverter Converter
+ILogger~AuditLogManager~ Logger
+GetCountAsync(startTime, endTime, ...) Task~long~
+GetListAsync(...) Task~AuditLog[]~
+GetAsync(id, includeDetails) Task~AuditLog~
+SaveAsync(auditInfo) Task~string~
+DeleteAsync(id) Task
+DeleteManyAsync(ids) Task
-SaveLogAsync(auditInfo) Task~string~
}
class IAuditLogManager {
<<interface>>
+GetCountAsync(...) Task~long~
+GetListAsync(...) Task~AuditLog[]~
+GetAsync(id) Task~AuditLog~
+SaveAsync(auditInfo) Task~string~
+DeleteAsync(id) Task
+DeleteManyAsync(ids) Task
}
class AuditLog {
+Guid Id
+string ApplicationName
+DateTime ExecutionTime
+int ExecutionDuration
+string ClientIpAddress
+string HttpMethod
+string Url
+string Exceptions
+string Comments
+EntityChange[] EntityChanges
+AuditLogAction[] Actions
+ExtraPropertyDictionary ExtraProperties
}
AuditLogManager ..|> IAuditLogManager
AuditLogManager --> AuditLog : creates
图表来源
- AuditLogManager.cs
- AuditLog.cs
批量写入策略
审计日志系统采用了事务性批量写入策略,确保数据一致性和性能:
public async virtual Task<string> SaveAsync(
AuditLogInfo auditInfo,
CancellationToken cancellationToken = default)
{
if (!Options.HideErrors)
{
return await SaveLogAsync(auditInfo, cancellationToken);
}
try
{
return await SaveLogAsync(auditInfo, cancellationToken);
}
catch (Exception ex)
{
Logger.LogWarning("Could not save the audit log object: " + Environment.NewLine + auditInfo.ToString());
Logger.LogException(ex, LogLevel.Error);
}
return "";
}
protected async virtual Task<string> SaveLogAsync(
AuditLogInfo auditInfo,
CancellationToken cancellationToken = default)
{
using (var uow = UnitOfWorkManager.Begin(true))
{
var auditLog = await AuditLogRepository.InsertAsync(
await Converter.ConvertAsync(auditInfo),
false,
cancellationToken);
await uow.CompleteAsync();
return auditLog.Id.ToString();
}
}
作业日志管理系统
作业日志管理系统提供了专门针对后台任务的日志记录和查询功能:
sequenceDiagram
participant Job as 后台任务
participant Event as 作业事件处理器
participant Store as 作业存储
participant Repo as 作业日志仓储
participant DB as 数据库
Job->>Event : 任务执行完成事件
Event->>Store : StoreLogAsync(eventData)
Store->>Store : 创建作业日志对象
Store->>Repo : InsertAsync(jobLog)
Repo->>DB : 插入日志记录
DB-->>Repo : 返回插入结果
Repo-->>Store : 日志已保存
Store-->>Event : 处理完成
Event-->>Job : 事件处理完毕
图表来源
- JobLogEvent.cs
- BackgroundJobStore.cs
查询接口和分页实现
作业日志系统提供了灵活的查询接口和高效的分页实现:
public async virtual Task<PagedResultDto<BackgroundJobLogDto>> GetListAsync(BackgroundJobLogGetListInput input)
{
var specification = new BackgroundJobLogGetListSpecification(input);
var totalCount = await BackgroundJobLogRepository.GetCountAsync(specification);
var backgroundJobLogs = await BackgroundJobLogRepository.GetListAsync(
specification, input.Sorting, input.MaxResultCount, input.SkipCount);
return new PagedResultDto<BackgroundJobLogDto>(totalCount,
ObjectMapper.Map<List<BackgroundJobLog>, List<BackgroundJobLogDto>>(backgroundJobLogs));
}
private class BackgroundJobLogGetListSpecification : Volo.Abp.Specifications.Specification<BackgroundJobLog>
{
protected BackgroundJobLogGetListInput Input { get; }
public override Expression<Func<BackgroundJobLog, bool>> ToExpression()
{
Expression<Func<BackgroundJobLog, bool>> expression = _ => true;
return expression
.AndIf(!Input.JobId.IsNullOrWhiteSpace(), x => x.JobId.Equals(Input.JobId))
.AndIf(!Input.Type.IsNullOrWhiteSpace(), x => x.JobType.Contains(Input.Type))
.AndIf(!Input.Group.IsNullOrWhiteSpace(), x => x.JobGroup.Equals(Input.Group))
.AndIf(!Input.Name.IsNullOrWhiteSpace(), x => x.JobName.Equals(Input.Name))
.AndIf(!Input.Filter.IsNullOrWhiteSpace(), x => x.JobName.Contains(Input.Filter) ||
x.JobGroup.Contains(Input.Filter) || x.JobType.Contains(Input.Filter) || x.Message.Contains(Input.Filter))
.AndIf(Input.HasExceptions.HasValue, x => !string.IsNullOrWhiteSpace(x.Exception))
.AndIf(Input.BeginRunTime.HasValue, x => x.RunTime >= Input.BeginRunTime)
.AndIf(Input.EndRunTime.HasValue, x => x.RunTime <= Input.EndRunTime);
}
}
章节来源
- BackgroundJobLogAppService.cs
日志归档和清理策略
系统提供了完善的日志归档和清理策略配置:
public class AbpBackgroundTasksOptions
{
public bool JobCleanEnabled { get; set; } = false;
public int MaxJobCleanCount { get; set; } = 1000;
public TimeSpan JobExpiratime { get; set; } = TimeSpan.FromDays(15d);
public string JobCleanCronExpression { get; set; } = "0 0/10 * * * ? *";
public void Configure(Action<AbpBackgroundTasksOptions> configureAction)
{
configureAction(this);
}
}
清理策略支持:
- 基于时间的自动清理
- 存储空间管理
- 可配置的清理频率
- 批量清理操作
章节来源
- AbpBackgroundTasksOptions.cs
依赖关系分析
执行日志系统的依赖关系图展示了各组件之间的交互:
graph LR
subgraph "外部依赖"
A[Microsoft.Extensions.Logging]
B[Volo.Abp.Auditing]
C[Volo.Abp.AuditLogging]
D[EntityFrameworkCore]
end
subgraph "内部模块"
E[AuditLogManager]
F[BackgroundJobLogAppService]
G[JobLogEvent]
H[BackgroundJobStore]
end
A --> E
A --> F
A --> G
B --> E
C --> E
D --> F
D --> H
E --> I[IAuditLogRepository]
F --> J[IBackgroundJobLogRepository]
G --> H
H --> K[BackgroundJobLog]
图表来源
- AuditLogManager.cs
- BackgroundJobLogAppService.cs
章节来源
- AuditLogManager.cs
- BackgroundJobLogAppService.cs
性能考虑
批量写入优化
系统通过以下方式优化批量写入性能:
- 事务批处理:使用单元工作模式确保原子性
- 异步操作:所有I/O操作都是异步的
- 连接池管理:合理利用数据库连接池
- 内存优化:及时释放不需要的对象
查询性能优化
- 索引策略:在关键查询字段上建立适当索引
- 分页查询:避免一次性加载大量数据
- 查询缓存:对频繁查询的结果进行缓存
- 延迟加载:按需加载关联数据
存储空间管理
- 日志轮转:定期归档旧日志
- 压缩存储:对历史日志进行压缩
- 分区策略:按时间分区存储日志
- 清理策略:自动删除过期日志
故障排除指南
常见问题及解决方案
1. 日志写入失败
症状:审计日志或作业日志无法正常写入数据库
可能原因:
- 数据库连接问题
- 事务超时
- 内存不足
- 权限不足
解决方案:
// 检查数据库连接
try
{
await AuditLogRepository.InsertAsync(auditLog);
}
catch (DbException ex)
{
Logger.LogError($"Database connection failed: {ex.Message}");
// 实现重试逻辑
}
2. 查询性能问题
症状:日志查询响应缓慢
可能原因:
- 缺少适当的索引
- 查询条件过于宽泛
- 分页参数设置不当
解决方案:
// 使用具体的时间范围
var logs = await GetListAsync(
startTime: DateTime.Now.AddDays(-7),
endTime: DateTime.Now,
maxResultCount: 100,
skipCount: 0
);
3. 存储空间不足
症状:磁盘空间不足导致日志写入失败
可能原因:
- 日志清理策略未启用
- 清理频率设置过低
- 日志文件过大
解决方案:
// 启用自动清理
options.JobCleanEnabled = true;
options.JobExpiratime = TimeSpan.FromDays(30);
options.JobCleanCronExpression = "0 0 1 * * ?"; // 每天凌晨1点清理
章节来源
- AuditLogManager.cs
结论
执行日志系统为ABP Next Admin框架提供了全面的日志记录和管理能力。通过审计日志和作业日志的双重保障,系统能够满足企业级应用对日志记录的各种需求。
主要特性总结
- 完整的数据结构设计:包含执行时间、持续时间、执行结果、异常信息等关键字段
- 高性能批量写入:采用事务性批处理和异步操作
- 灵活的查询接口:支持多维度查询和分页处理
- 自动化的归档清理:基于时间和存储空间的智能管理
- 监控系统集成:为系统监控和问题诊断提供数据支持
最佳实践建议
- 合理配置清理策略:根据业务需求设置合适的保留期限
- 监控系统性能:定期检查日志系统的性能指标
- 备份重要日志:对关键业务日志进行定期备份
- 权限控制:严格控制日志访问权限
- 定期维护:定期清理过期日志和优化数据库
通过遵循这些最佳实践,可以确保执行日志系统长期稳定运行,并为企业提供可靠的审计和监控支持。