利用Filebeat+ELK 来收集.Net Core 微服务日志 (一)

对于所有的服务的日志,应该有相同的格式,收集到一起,称为日志中心,方便发现错误的时候,在统一的一个地方可以debug

整个项目结构图

 

集成后效果图:

 

 

 

拿出错日志为例:

一:建立你的service (我使用 WEB API为例)

1.引用nlog 负责 日志记录 并配置 nlog.config  配置文件如下: 

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Warn"
      internalLogFile="internal-nlog.txt">
  <extensions>
    <!--enable NLog.Web for ASP.NET Core-->
    <add assembly="NLog.Web.AspNetCore"/>
  </extensions>
  <!-- define various log targets -->
  <!--定义日志文件 docker  目录-->
  <variable name="logDirectory" value="/data/logs"/>
  <!--定义本机日志文件  目录-->
  <!--<variable name="logDirectory" value="${basedir}/logs"/>-->
  <!--定义本机你的服务名-->
  <variable name="ServceName" value="API001"/>
  <targets async="true">
    
    <!-- 本地文件日志target --> 
    <!-- 约定以 err 为文件后缀的日志文件记录了程序输出的警告或者错误。 -->
    <target name="ERROR_LOG_FILE"
            xsi:type="File"
            layout="[${longdate}]#${ServceName}#${message}#"
            encoding="utf-8"
            archiveNumbering="Date"
            archiveEvery="Day"
            archiveDateFormat="yyyy-MM-dd"
            fileName="${logDirectory}/${ServceName}/${shortdate}/${shortdate}.err" />

    <!--grok 规则-->
    <!--\[%{DATA:time}\]#%{DATA:ser_name}\#%{DATA:req_url}\#%{DATA:req_method}\#%{DATA:rep_param}\#\s*(?<err_msg>([\s\S]*))-->
    <!--空白-->
    <target xsi:type="Null" name="blackhole" />
  </targets>
  <!--日志级别 Trace -》Debug-》 Info -》Warn-》 Error-》 Fatal-->
  <!--日志规则-->
  <rules>
    <!-- 记录所有日志级别不低于 Warn 的日志到日志文件 -->
    <logger name="*" minlevel="Error" writeTo="ERROR_LOG_FILE" /> 
    <!--自定义日志,排除Microsoft日志-->
    <logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
  </rules>
</nlog>

 

2.编写全局异常中间件:

   /// <summary>
    /// 全局异常处理中间件
    /// </summary>
    public class GlobalErrorHandlingMiddleware
    {
        private readonly RequestDelegate next;
        private readonly ILogger<GlobalErrorHandlingMiddleware> _logger;

        public GlobalErrorHandlingMiddleware(RequestDelegate next, ILogger<GlobalErrorHandlingMiddleware> logger)
        {
            this.next = next;
            this._logger = logger;
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await next(context);
            }
            catch (Exception ex)
            { 

                var Request = context.Request;
                ///访问路径
                string visit_url = Request.Path;
                ///URL 请求方法
                string method = Request.Method.ToUpper();
                ///URL 请求的参数
                string url_paramters = string.Empty;

                if (method == "GET") url_paramters = Request.QueryString.Value;


                if (method == "POST")
                {
                    foreach (var item in Request.Form)
                        url_paramters = url_paramters + item.Key + "=" + item.Value + "&";
                }

                ///错识信息
                string err_msg = ex.StackTrace;

                ///日志格式内容
                var logs_msg = $"{visit_url}#{method}#{url_paramters}#{err_msg}";

                _logger.LogError(logs_msg);

                var statusCode = context.Response.StatusCode;

                var msg = $"错误代码:{statusCode},提示信息:{ex.Message}";

                await HandleExceptionAsync(context, msg);
            }
        }

        private static Task HandleExceptionAsync(HttpContext context, string msg)
        {
            var data = new Result { Title = "异常中间件返回", Msg = msg };
            var result = JsonConvert.SerializeObject(data);
            context.Response.ContentType = "application/json;charset=utf-8";
            return context.Response.WriteAsync(result);
        }
    }

 

3.在API Startup.cs 文件配置nlog

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            //添加NLog
            loggerFactory.AddNLog();

            env.ConfigureNLog(Path.Combine("configs", "nlog.config"));

            //异常处理中间件
            app.UseMiddleware<GlobalErrorHandlingMiddleware>();         

            app.UseMvc();
        }

 

到这里。API 出错就会捕获至日志里,日志格式如下:

[2018-06-26 15:07:22.1562]#API001#/api/get#GET#?id=ad#   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at API001.Controllers.ValuesController.test(String id) in D:\code\study_demo\API001\Controllers\ValuesController.cs:line 26
   at lambda_method(Closure , Object , Object[] )
   at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextActionFilterAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeInnerFilterAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeFilterPipelineAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at API001.GlobalErrorHandlingMiddleware.<Invoke>d__3.MoveNext() in D:\code\study_demo\API001\GlobalErrorHandlingMiddleware.cs:line 28#

 

到这里你的service 负责日志创造的部份已完成

注意:使用docker 运行容器的同志,要将 服务的日志目录挂载 至 filebeat 目录。这样方便统一监控目录

 ///将日志挂载到filebeat 目录
sudo docker run --name api001 -e "ASPNETCORE_URLS=http://+:5004" --restart=always -d -p 5004:5004 -v /home/aimei/apps/api001:/publish  -v /home/aimei/filebeat/logs:/data/logs -v /etc/localtime:/etc/localtime -w /publish --network=default 730e3899d926 dotnet API001.dll

 

posted on 2018-06-26 17:56  yaobo  阅读(746)  评论(0编辑  收藏  举报