在WebApi2上使用Serilog的正确方法 [英] Correct way to use Serilog with WebApi2

查看:306
本文介绍了在WebApi2上使用Serilog的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找将serilog与aspnet webapi2结合使用的正确方法. 现在,我像这样初始化全局Log.Logger属性:

I am in search of the correct way to use serilog with aspnet webapi2. As for now I initialize the global Log.Logger property like that :

   public static void Register(HttpConfiguration config)
    {

        Log.Logger = new LoggerConfiguration()
            .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://localhost:9200"))
            {
                IndexFormat = IndexFormat,
                BufferBaseFilename = outputLogPath,
                AutoRegisterTemplate = true,
                AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6,
                CustomFormatter = new ElasticsearchJsonFormatter(renderMessageTemplate: false),
                BufferFileCountLimit = NbDaysRetention
            })
            .MinimumLevel.ControlledBy(new LoggingLevelSwitch() { MinimumLevel = LogEventLevel.Information})
            .Enrich.FromLogContext()
            .Enrich.WithWebApiRouteTemplate()
            .Enrich.WithWebApiActionName()
            .CreateLogger();

        //Trace all requests
        SerilogWebClassic.Configure(cfg => cfg.LogAtLevel(LogEventLevel.Information));


        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }

有更清洁的方法吗?我想知道,如果我必须对控制器进行一些测试,这是否可能是个问题.

Is there a more cleaner way to do it? I am wondering, if this might be a problem if I have to put some test in place for my controllers.

推荐答案

对于带有Web API(和/或MVC)的应用程序,我已经大量使用以下代码组织. (请注意,由于它是基于某些软件包的旧版本,因此可能有点过时了,但是您无需过多的工作就可以对其进行修改...)

I have used the following code organization quite a lot for apps with Web API (and/or MVC). (note that it may be a bit outdated, as it is based on old versions of some packages, but you should be able to adapt it without too much work ...)

您将需要一些软件包,您应该可以从名称空间中猜测它们,但最重要的是,安装WebActivatorEx软件包,该软件包提供了一种使代码在应用程序生命周期的不同时刻运行的方法.

You will need quite a few packages, that you should be able to guess from the namespaces, but most importantly, install the WebActivatorEx package which provides a way to have code running at different moment of the app lifecycle

我们的Global.asax.cs最终看起来像这样:

Our Global.asax.cs ended up looking like this :

    public class WebApiApplication : System.Web.HttpApplication
    {
        // rely on the fact that AppPreStart is called before Application_Start
        private static readonly ILogger Logger = Log.ForContext<WebApiApplication>();

        public override void Init()
        {
            base.Init();
        }

        protected void Application_Start()
        {
            // WARNING :  Some code runs even before this method ... see AppPreStart

            Logger.Debug("In Application_Start");
            // Mvc (must be before)
            AreaRegistration.RegisterAllAreas(); 
            // Web API
            // ... snip ...     
            // some DependencyInjection config ...
            // ... snip ...  
            // MVC
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            Logger.Information("App started !");
        }


        protected void Application_End(object sender, EventArgs e)
        {
            Logger.Debug("In Application_End");
            ApplicationShutdownReason shutdownReason = System.Web.Hosting.HostingEnvironment.ShutdownReason;
            Logger.Information("App is shutting down (reason = {@shutdownReason})", shutdownReason);

            // WARNING : Some code runs AFTER Application_End ... see AppPostShutDown
        }
    }

,然后是App_Start文件夹下的几个类(其中一些您可以忽略:P):

and then several classes under the App_Start folder (some of which you can just ignore :P ) :

  • AppPreStart.cs
using XXX;
using Serilog;


[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(AppPreStart), nameof(AppPreStart.PreApplicationStart))]
namespace XXX
{
    /// <summary>
    /// This runs even before global.asax Application_Start (see WebActivatorConfig)
    /// </summary>
    public class AppPreStart
    {
        public static void PreApplicationStart()
        {
            LogConfig.Configure();
            var logger = Log.ForContext<AppPreStart>();
            logger.Information("App is starting ...");

            // ... snip ...
            // very early things like IoC config, AutoMapper config ...
            // ... snip ...

            logger.Debug("Done with AppPreStart");
        }
    }
}

  • AppPostShutDown.cs
    • AppPostShutDown.cs
    • using XXX;
      using Serilog;
      
      [assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(AppPostShutDown), nameof(AppPostShutDown.PostApplicationShutDown))]
      namespace XXX
      {
          /// <summary>
          /// This runs even before global.asax Application_Start (see WebActivatorConfig)
          /// </summary>
          public class AppPostShutDown
          {
              private static ILogger Logger = Log.ForContext<AppPostShutDown>();
      
              public static void PostApplicationShutDown()
              {
                  Logger.Debug("PostApplicationShutDown");
      
                  // ... snip ...
                  // very late things like IoC dispose ....
                  // ... snip ...
      
                  // force flushing the last "not logged" events
                  Logger.Debug("Closing the logger! ");
                  Log.CloseAndFlush();
              }
          }
      }
      

      • LogConfig.cs
        • LogConfig.cs
        • using Serilog;
          using Serilog.Events;
          using SerilogWeb.Classic;
          using SerilogWeb.Classic.Enrichers;
          using SerilogWeb.Classic.WebApi.Enrichers;
          
          namespace XXX
          {
              public class LogConfig
              {
                  static public void Configure()
                  {
                      ApplicationLifecycleModule.LogPostedFormData = LogPostedFormDataOption.OnlyOnError;
                      ApplicationLifecycleModule.FormDataLoggingLevel = LogEventLevel.Debug;
                      ApplicationLifecycleModule.RequestLoggingLevel = LogEventLevel.Debug;
          
                      var loggerConfiguration = new LoggerConfiguration().ReadFrom.AppSettings()
                              .Enrich.FromLogContext()
                              .Enrich.With<HttpRequestIdEnricher>()
                              .Enrich.With<UserNameEnricher>()
                              .Enrich.With<HttpRequestUrlEnricher>()
                              .Enrich.With<WebApiRouteTemplateEnricher>()
                              .Enrich.With<WebApiControllerNameEnricher>()
                              .Enrich.With<WebApiRouteDataEnricher>()
                              .Enrich.With<WebApiActionNameEnricher>()
                          ;
          
                      Log.Logger = loggerConfiguration.CreateLogger();
                  }
              }
          }
          

          ,然后从Web.config中读取Log配置的可变部分,该部分在AppSettings中具有以下键:

          and then read the variable parts of the Log configuration from Web.config that has the following keys in AppSettings :

              <!-- SeriLog-->
              <add key="serilog:level-switch:$controlSwitch" value="Information" />
              <add key="serilog:minimum-level:controlled-by" value="$controlSwitch" />
              <add key="serilog:enrich:with-property:AppName" value="XXXApp" />
              <add key="serilog:enrich:with-property:AppComponent" value="XXXComponent" />
              <add key="serilog:enrich:with-property:Environment" value="Dev" />
              <add key="serilog:enrich:with-property:MachineName" value="%COMPUTERNAME%" />
              <add key="serilog:using:Seq" value="Serilog.Sinks.Seq" />
              <add key="serilog:write-to:Seq.serverUrl" value="http://localhost:5341" />
              <add key="serilog:write-to:Seq.apiKey" value="xxxxxxxxxxx" />
              <add key="serilog:write-to:Seq.controlLevelSwitch" value="$controlSwitch" />
          

          (然后我们进行了Web.config转换,将其转换为用于生产的令牌化"文件

          (and then we had Web.config transforms to turn it into a "tokenized" file for production

          Web.Release.config

              <!-- SeriLog-->
              <add key="serilog:enrich:with-property:Environment" value="__Release_EnvironmentName__"
                   xdt:Transform="Replace" xdt:Locator="Match(key)"/>
          
              <add key="serilog:write-to:Seq.serverUrl" value="__app_serilogSeqUrl__"
                   xdt:Transform="Replace" xdt:Locator="Match(key)"/>
              <add key="serilog:write-to:Seq.apiKey" value="__app_serilogApiKey__"
                   xdt:Transform="Replace" xdt:Locator="Match(key)"/>
          

          此配置中最重要的部分是:

          Some of the most important parts of this configuration is :

          • 尽快配置记录器
          • 最后请致电Log.CloseAndFlush();,以确保所有日志事件都已存储/推送
          • 添加Serilog的Enrich.FromLogContext()以及SerilogWeb.ClassicSerilogWeb.WebApi的一些浓缩器,它们可能超级有用.
          • 登录到正确支持结构化日志记录的日志服务器(写入文件有很多弊端)...我们使用了 Seq 并对此感到非常高兴(将其本地安装在每台开发机上,然后在生产环境中使用集中式实例).它支持搜索/查询和仪表板以及动态日志级别控制.
          • configure your logger as soon as possible
          • call Log.CloseAndFlush(); at the very end to be sure all your log events are stored/pushed
          • add Enrich.FromLogContext() from Serilog, and some enrichers from SerilogWeb.Classic and SerilogWeb.WebApi, they can turn out to be super useful.
          • logging to a log server that properly supports structured logging (writing to files just has too many drawbacks) ... we used Seq and were very very happy about it (installed locally on every dev machine, and then a centralized instance in production). It supports searching/querying and dashboards and also dynamic log level control.

          这篇关于在WebApi2上使用Serilog的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆