• Serilog 记录日志


    Serilog 记录日志

    Serilog是.net里面非常不错的记录日志的库,另外一个我认为比较好的Log库是NLog。

    在我个人的asp.net web api 2 基础框架(Github地址)里,我原来使用的是NLog,但是由于好奇心,我决定使用Serilog代替Nlog。

    安装:

    首先安装 Serilog,通过Package Manager Console或者Nuget管理窗口进行安装:

    PM> Install-Package Serilog

    然后安装 Serilog的Sinks,所谓Sink就是记录Log的途径,比如在控制台输出,在Debug窗口输出,输出到文件,输出到数据库等等。

    这里有一个列表,列出了所有的Sink:https://github.com/serilog/serilog/wiki/Provided-Sinks

    由于我使用的是asp.net web api 2.2 (.Net Framework 4.6+),所以我的项目里面暂时不需要用到Console,所以不安装官方教程的Serilog.Sinks.Literate。

    但是我需要在VS的Debug窗口显示Log,所以安装Serilog.Sinks.Debug

    通过Package Manager Console或者Nuget管理窗口进行安装:

    PM> Install-Package Serilog.Sinks.Debug

    我还需要输出到文件和Sql Server数据库,所以再安装 Serilog.Sinks.RollingFile 和 Serilog.Sinks.MSSqlServer

    通过Package Manager Console或者Nuget管理窗口进行安装:

    PM> Install-Package Serilog.Sinks.RollingFile
    PM> Install-Package Serilog.Sinks.MSSqlServer

    这些都安装完了之后,我们开始配置。

    配置:

    在Web项目里,我建立了一个配置类:

    复制代码
       public class SerilogConfiguration
        {
            public static void CreateLogger()
            {
            // 这一部分是配置Sql Server的Sink const string connectionString = AppSettings.DefaultConnection; // 数据库连接字符串 const string tableName = "Logs"; // 表名 var columnOptions = new ColumnOptions // 自定义字段 { AdditionalDataColumns = new Collection<DataColumn> { new DataColumn {DataType = typeof (string), ColumnName = "User"}, new DataColumn {DataType = typeof (string), ColumnName = "Class"}, } };
           // Sql Server的表中加入Json格式Log Event的数据字段 columnOptions.Store.Add(StandardColumn.LogEvent);
           // 输出模板,Sql Server不能用这个 const string outputTemplate = "[{Timestamp:HH:mm:ss.FFF} {Level}] {Message} ({SourceContext:l}){NewLine}{Exception}"; Serilog.Log.Logger = new LoggerConfiguration() .MinimumLevel.Verbose() // 所有Sink的最小记录级别 .Enrich.WithProperty("SourceContext", null) //加入属性SourceContext,也就运行时是调用Logger的具体类 .Enrich.FromLogContext() //动态加入属性,主要是针对上面的自定义字段User和Class,当然也可以随时加入别的属性。 .WriteTo.Debug( outputTemplate: outputTemplate) // 写到VS Output 窗口 .WriteTo.RollingFile("logs\{Date}.log", shared: true, restrictedToMinimumLevel: LogEventLevel.Debug, outputTemplate: outputTemplate) // 写到文件,每天一个,最小记录级别是Debug,文件格式是 yyyyMMdd.log
             // 记录到Sql Server,最小级别是Information .WriteTo.MSSqlServer(connectionString, tableName, columnOptions: columnOptions, autoCreateSqlTable: true, restrictedToMinimumLevel: LogEventLevel.Information) .CreateLogger(); } }
    复制代码

    配置创建完之后赋值给Serilog.Log.Logger,它是一个静态变量。

    要在进行IOC配置之前调用这个配置类。

    注意,记录到Sql server那行配置,我设定的是自动创建表autoCreateSqlTable: true,但是如果创建后,这部分配置(Sql Server Sink)有更改,就需要把生成的表删掉,再让它重新自动建立一个,否则就无法再记录到Sql Server里面了。

    Serilog的级别一共有6个,Verbose - Debug - Information - Warning - Error - Fatal,详见其文档。

    配置IOC

    因为我的框架都是使用依赖注入模式的,所以Serilog配置完之后,我们要进行IOC的配置,我使用的是Autofac(非常好的库),它可以自动Dispose配置的类,如果这个类实现了IDisposable接口的话,例如Serilog。

    首先安装Serilog的Autofac集成库:

    PM> Install-Package AutofacSerilogIntegration

    然后到AutofacWebapiConfig.cs进行配置:

    builder.RegisterLogger(autowireProperties: true);

    非常的简单,就一句话。

    依赖注入

    配置完IOC,我们可以注入Serilog的ILogger进行使用,我们把它注入到Service层的CommonService里而不是所有的Controller里,这样就不用改太多代码。

    复制代码
    namespace LegacyApplication.Services.Core
    {
        public interface ICommonService
        {
            IUploadedFileRepository UploadedFileRepository { get; }
            IDepartmentRepository DepartmentRepository { get; }
            ILogger Log { get; }
        }
    
        public class CommonService : ICommonService
        {
            public IUploadedFileRepository UploadedFileRepository { get; }
            public IDepartmentRepository DepartmentRepository { get; }
            public ILogger Log { get; }
    
            public CommonService(
                IUploadedFileRepository uploadedFileRepository,
                IDepartmentRepository departmentRepository,
                ILogger log)
            {
                UploadedFileRepository = uploadedFileRepository;
                DepartmentRepository = departmentRepository;
                Log = log;
            }
        }
    }
    复制代码

    然后在所有Controller的父类里,就可以获取到ILogger了。

     View Code

    在这个Controller父类(ApiControllerBase.cs)里,继续封装一些Log的方法,以便所有的派生Controller可以简单的使用:

    复制代码
    #region Logging
    
            [NonAction]
            protected void LogByLevel(LogEventLevel level, string msg)
            {
                using (LogContext.PushProperty("Class", GetType().FullName)) // 对应于自定义的字段,对Sql server起作用, IDisposable
                using (LogContext.PushProperty("User", CurrentUserName))
                {
                    Log.Write(level, $"{msg} (by {CurrentUserName}, at {Now:yyyy-MM-dd HH:mm:ss.FFF})");
                }
            }
    
            [NonAction]
            protected void LogVerbose(string msg)
            {
                LogByLevel(LogEventLevel.Verbose, msg);
            }
    
            [NonAction]
            protected void LogDebug(string msg)
            {
                LogByLevel(LogEventLevel.Debug, msg);
            }
    
            [NonAction]
            protected void LogInformation(string msg)
            {
                LogByLevel(LogEventLevel.Information, msg);
            }
    
            [NonAction]
            protected void LogWarning(string msg)
            {
                LogByLevel(LogEventLevel.Warning, msg);
            }
    
            [NonAction]
            protected void LogError(string msg)
            {
                LogByLevel(LogEventLevel.Error, msg);
            }
    
            [NonAction]
            protected void LogFatal(string msg)
            {
                LogByLevel(LogEventLevel.Fatal, msg);
            }
    
            #endregion
    复制代码

    其中:

    using (LogContext.PushProperty("Class", GetType().FullName))
    using (LogContext.PushProperty("User", CurrentUserName))

    这部分是针对Serilog的Sql Server配置的自定义字段部分。

    全局异常记录

    针对asp.net web api 2,我使用了自定义的全局异常记录类:MyExceptionLogger.cs

    GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new MyExceptionLogger());
    GlobalConfiguration.Configuration.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());
    复制代码
    namespace LegacyStandalone.Web.MyConfigurations.Exceptions
    {
        public class MyExceptionLogger : ExceptionLogger
        {
            public override void Log(ExceptionLoggerContext context)
            {
    #if DEBUG
                Trace.TraceError(context.ExceptionContext.Exception.ToString());
    #endif
                using (LogContext.PushProperty("Class",
                    context.ExceptionContext.ControllerContext.ControllerDescriptor.ControllerType))
                using (LogContext.PushProperty("User",
                    context.RequestContext.Principal.Identity.Name))
                {
                    LogException(context.ExceptionContext.Exception);
                }
            }
    
            private void LogException(Exception ex)
            {
                if (ex != null)
                {
                    LogException(ex.InnerException);
                    Serilog.Log.Logger.Error(ex.ToString());
                }
            }
        }
    }
    复制代码

    在这里我使用的是静态版本的Serilog的Logger。

    问题

    经使用测试,输出到Debug窗口和Sql Server数据库是没有问题的,但是在asp.net web api 2项目的开发环境里一直无法输出到文件,我新建立了一个web api项目也是如此,但是在控制台应用却没有问题,今天晚些时候我将继续研究并解决这个问题。

     
    分类: .Net Classic
  • 相关阅读:
    程序员第一定律:关于技能与收入
    JS注册/移除事件处理程序
    关于程序猿,你不知道的15件事
    .NET后台输出js脚本的方法
    新项目经理必读:分析什么是项目经理
    项目如何开始:怎样和客户一起搞定需求
    【转】为什么程序员讨厌修改静态检查问题
    js的with语句使用方法
    软件版本号 详解
    PHP记忆碎片2投票汇总
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/7643400.html
Copyright © 2020-2023  润新知