功能场景:

随着系统的功能越发增多,需要将系统的各个功能进行拆分服务(比如 Web API,文件上传,Websocket 等),但是不同服务的日志默认下都是生成 log文件,记录在当前服务下,无法统一查看,不方便管理和监控

那么,我们索性直接将日志服务也独立出来(日志方案基于Nlog),并直接收集其他服务的日志,进行统一记录和监控,方便管理

(其实不分离服务也可以对日志进行统一记录的,因为 Nlog 可以配置生成日志的位置,只是我为了各个服务职责单一,并且将日志服务做成一个日志中心(可监控,可分析,可搜索),所以在其他服务中,直接将日志记录功能取消,而是由 日志服务 进行统一处理)

日志中心效果如图:

 

实践:

原理很简单,基于 Redis List (消息队列)来进行数据收集,也就是说

1.假若有 A B C 三个服务,我们直接在原本 记录错误日志的中间件接口请求日志记录的拦截器(ActionFilter)中,将他们的日志消息做好标识(比如服务名称,日志消息生成时间等),直接添加到 Redis List 进行存储
(在这里,我使用三个级别的日志等级,Error记录系统错误,Debug记录认为手动需要记录的日志,Trace为请求日志,也就是说,我这里会有三个 list)

//ErrorHandlingMiddleware
public async Task Invoke(HttpContext context)
{
    try
    {
        if (!context.Response.HasStarted)
        {
            await _next(context);
        }
    }
    catch (Exception e)
    {
        await HandleExceptionAsync(context, e.Message);
        RedisHelper.LPush("LogErrorList", $"{PROJECT_NAME}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} |{context.Response.StatusCode}|{context.Request.Method} {context.Request.Host}{ context.Request.Path } \nMessage:{e.Message} \nInnerException:{e.InnerException} \nStackTrace:{e.StackTrace}");
    }
}

 

2.然后在独立部署出来的 日志服务 中,通过 BackgroundService 后台任务,使用 BRPop List 将数据弹出消费,进行本地化存储(Nlog),这样一来,就达成我们的统一存储记录日志的需求

//LogErrorJob 
public class LogErrorJob : BackgroundService
    {
        private static Logger logger;
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        { 
            while (!stoppingToken.IsCancellationRequested)
            {
                var log = RedisHelper.BRPop(1, "LogErrorList");
                if (!string.IsNullOrEmpty(log))
                {
                    string logName = log.Split('-').First();
                    string msg = log.Replace($"{logName}-", "");

                    logger = LogManager.GetLogger(logName);
                    logger.Error($"{msg}");

                    //error级别日志,发送邮件提示
                    EmailServer.SendEmail(log);
                }
                //添加等待时间,避免cpu过高,这里等待时间为10ms
                await Task.Delay(10, stoppingToken);
            }
        }
    }

 

3.再写一个 SMTP邮件服务,如果发现有 Error 级别的日志,进行邮件发送提醒

4.最后,使用 LogDashboard 来对日志进行可视化和可搜素处理(其日志路径和日志格式被 LogDashboard 指定,一些其他细节处理可看官方文档)

 

Github:待定