日志记录是开发中不可或缺的一部分,它可以帮助我们追踪应用程序的运行状态、调试问题以及记录重要事件。
ASP.NET Core 提供了内置的日志记录功能,支持多种日志提供程序。我们将使用OpenTelemetry
来实现日志记录。
业务日志是根据实际业务需求对特定对象操作时进行记录。
这不同于请求日志的记录,无法进行统一的拦截处理。
如以下需求场景: 用户张三删除了一篇博客《程序员的素养》,需要在日志中记录:张三删除了博客:程序员的素养。
且能够根据用户(张三),操作(删除),模块(博客),对象(程序员的素养)进行日志的筛选。
为了实现此种业务需求,我们提供了实现的方式。
通常我们会把业务日志写入库,以便后续的筛选查询。
我们将通过后台队列来执行日志写入操作,以避免阻塞正常业务代码的执行。
SystemMod
模块Worker
目录下的SystemLogTaskHostedService.cs
给出了实现示例。
如若使用请将该服务添加到依赖注入中,如:
services.AddSingleton(typeof(EntityTaskQueue<SystemLogs>)); services.AddSingleton(typeof(SystemLogService)); services.AddHostedService<SystemLogTaskHostedService>();
接下来我们就可以在其他业务代码中通过EntityTaskQueue
,将日志对象添加到队列中。
我们可以在SystemLogs.cs
实体中添加一个静态方法,如:
public static SystemLogs NewLog(string userName, Guid userId, string targetName, ActionType actionType, string? route = null, string? description = null) { return new SystemLogs { SystemUserId = userId, ActionUserName = userName, TargetName = targetName, Route = route ?? string.Empty, ActionType = actionType, Description = description, }; }
我们可以在Manager
中封装日志记录的方法,以便在控制器中调用,如记录登录日志:
public async Task SaveLoginLogAsync(SystemUser user, string description) { var log = SystemLogs.NewLog(user.UserName, user.Id, "登录", ActionType.Login, description: description); await _taskQueue.AddItemAsync(log); }
我们可以将业务日志封装成服务,以便在其他地方使用。可查看SystemMod中的SystemLogService
。
using Ater.Web.Extension; namespace SystemMod; /// <summary> /// 业务日志服务 /// </summary> public class SystemLogService { private readonly IServiceProvider _serviceProvider; private readonly EntityTaskQueue<SystemLogs> _taskQueue; private readonly IUserContext _context; /// <summary> /// /// </summary> /// <param name="serviceProvider"></param> /// <param name="taskQueue"></param> public SystemLogService(IServiceProvider serviceProvider, EntityTaskQueue<SystemLogs> taskQueue) { _serviceProvider = serviceProvider; _taskQueue = taskQueue; _context = _serviceProvider.CreateScope().ServiceProvider.GetRequiredService<IUserContext>(); } /// <summary> /// 记录日志,优先从UserContext中获取用户信息 /// 匿名用户访问,需要传入userName和userId /// </summary> /// <param name="targetName"></param> /// <param name="actionType"></param> /// <param name="description"></param> /// <param name="userName"></param> /// <param name="userId"></param> /// <returns></returns> public async Task NewLog(string targetName, ActionType actionType, string description, string? userName = null, Guid? userId = null) { userId = _context.UserId == Guid.Empty ? userId : _context.UserId; userName = string.IsNullOrEmpty(_context.Username) ? userName : _context.Username; var route = _context!.GetHttpContext()?.Request.Path.Value; if (userId == null || userId.Equals(Guid.Empty)) { return; } var log = SystemLogs.NewLog(userName ?? "", userId.Value, targetName, actionType, route, description); await _taskQueue.AddItemAsync(log); } }
然后你可以在其他控制器或Manager中使用该服务记录业务日志。
Tip
以上示例可在SystemMod
中找到相关实现,你也可参考该实现在其他模块或Http.API
中实现自己的日志记录服务。
内容大纲