[2core]Log和Log4net的配置使用

一、准备

尽管在asp.net core中几乎把所有能DI化的技术、知识和概念都依赖注入,不过本人还是想不让自己的项目那么DI化,完全没有必要“为了DI而DI”。这篇文章记录日志在asp.net core中的使用,以应用实战为主,不讲那么多大道理。

在asp.net core中框架提供了四种日志输出方式,即Console日志、Debug日志、EventSource日志和EventLog日志。前两种比较容易理解,EventSource提供程序写入名称为 Microsoft-Extensions-Logging 的跨平台事件源,EventLog提供程序将日志输出发送到 Windows 事件日志。本文主要分析记录Console日志、Debug日志和Log4net日志的使用(前两种无法输出到文件)。

日志类型
Trace=0,Debug=1,Information=2,Warning=3,Error=4,Critical=5,None=6

日志等级

None > Critical > Error > Warning > Information > Debug > Trace

 

 

 

二、实战

1.Console日志和Debug日志

1.1.准备
       a)打开VS2022,创建Asp.net core WebApi项目
       b)删除简化Program类代码,如下:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();


var app = builder.Build();
app.MapControllers();


app.Run();

1.2.依赖注入模式

1.2.1.Console日志

         a)通过nuget工具安装依赖包。
               1.Microsoft.Extensions.Logging:基础包
               2.Microsoft.Extensions.Logging.Console:输出日志到控制台程序包
         b)在Program文件中,配置日志。

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddLogging(logBuilder =>
{
    logBuilder.AddConsole();
});

var app = builder.Build();
app.MapControllers();


app.Run();

         c)修改测试文件WeatherForecastController的方法Get。

 public IEnumerable<WeatherForecast> Get()
        {
            _logger.LogTrace("LogTrace");
            _logger.LogDebug("LogDebug");
            _logger.LogInformation("LogInformation");
            _logger.LogWarning("LogWarning");
            _logger.LogError("LogError");
            _logger.LogCritical("LogCritical");

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }

         d)通过VS运行调试程序,查看输出结果。
                 LogInformation
                 LogWarning
                 LogError
                 LogCritical

             不出意外会输出上述四行结果,Why?请用1.4小节中配置文件,替换掉默认的配置信息就好。

1.2.2.Debug日志

         a)通过nuget工具安装依赖包。
              Microsoft.Extensions.Logging.Debug:输出日志到Debug程序包

         b)在Program文件中,配置日志。

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddLogging(logBuilder =>
{
    logBuilder.AddConsole();
    logBuilder.AddDebug();
});

var app = builder.Build();
app.MapControllers();


app.Run();

         d)通过VS运行调试程序,此时就可以在VS的“输出”窗口中,看到日志的输出信息了。

1.2.3.小节

         通过上述操作,你已经能够以依赖注入的方式使用框架内置的日志。如果你从.net framework升级到.net core的程序员,以及你理解DI/IOC的原理,不难看出所谓的依赖注入就是魔法糖。

 

1.3.工厂模式

在asp.net core中,不仅可以通过AddLogging()方法实现日志的配置和启用,还可以通过日志工厂进行操作。
使用日志工厂方式,appsettings.json配置文件中的日志配置数据就无效了,而以编写代码的方式设置日志输出等级就生效了。

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
var loggerFactory = LoggerFactory.Create(logBuilder =>
{
    logBuilder.ClearProviders();
    logBuilder.AddConsole();
    logBuilder.AddDebug();
    logBuilder.SetMinimumLevel(LogLevel.Trace);
});
ILogger _logger = loggerFactory.CreateLogger<Program>();
_logger.LogTrace("LogTrace");
_logger.LogDebug("LogDebug");
_logger.LogInformation("LogInformation");
_logger.LogWarning("LogWarning");
_logger.LogError("LogError");
_logger.LogCritical("LogCritical");


var app = builder.Build();
app.MapControllers();


app.Run();

 

1.4.配置文件

特别提示,asp.net core项目中,配置文件的日志配置数据的优先级要高于程序中编写代码,仅限于依赖注入模式。

{
  "Logging": {
    "Console": {
      "LogLevel": {
        "Default": "Trace",
        "Microsoft": "Warning",
        "Microsoft.Hosting.Lifetime": "Information"
      }
    },
    "Debug": {
      "LogLevel": {
        "Default": "Trace",
        "Microsoft": "Warning",
        "Microsoft.Hosting.Lifetime": "Information"
      }
    },
    "EventSource": {
      "LogLevel": {
        "Microsoft": "Warning"
      }
    },
    "EventLog": {
      "LogLevel": {
        "Microsoft": "Warning"
      }
    },
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

 

1.5.总结

通过上述两种方式,实现了日志输出到Console和Debug,但是框架并没有提供输出到硬盘文件的程序包,所以需要借助第三方的程序包实现将日志输出到文件的需求。

 

2.Log4net日志

不能把日志输出到文件中或写入到日志系统里,是无法保证系统安全稳定运行以及快速定位查找问题的,所以一定要实现在程序部署运行中,将日志输出到硬盘文件或专门的日志系统里的需求,所以此处用到了Log4net程序包。

2.1.依赖注入和工厂模式

在asp.net core中,使用log4net还是比较容易的,主要分为三步:第一安装程序包,第二设置配置文件,第三通过代码启用,如下:

2.1.1.安装程序包

         1.log4net:基础包
         2.Microsoft.Extensions.Logging.Log4Net.AspNetCore:适配AspNetCore程序的软件包
2.1.2.配置文件

         1.特别说明:a)配置文件中<configuration>节点需要去掉;b)配置文件中包含了两种配置,一种适用于AspNetCore,一种是传统.net framework模式。
         2.配置文件内容:注意配置文件要输出到根目录,因为程序包默认就是从根目录查找加载。

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
    <!--DIOC日志附加介质-->
    <!--根配置-->
    <root>
        <!--日志级别: NONE > FATAL > ERROR > WARN > INFO > DEBUG > ALL -->
        <priority value="ALL"/>
        <level value="ALL"/>
        <appender-ref ref="DiocAppender" />
    </root>
    <!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
    <appender name="DiocAppender" type="log4net.Appender.RollingFileAppender">
        <!--日志输出到exe程序这个相对目录下-->
        <param name="File" value="logs\\diocs\\" />
        <!--输出的日志不会覆盖以前的信息-->
        <param name="AppendToFile" value="true" />
        <!--备份文件的个数-->
        <param name="MaxSizeRollBackups" value="50" />
        <!--最小锁定模型以允许多个进程可以写入同一个文件-->
        <param name="MaxFileSize" value="10240" />
        <!--当前日志文件的最大大小-->
        <param name="lockingModel"  type="log4net.Appender.FileAppender+MinimalLock" />
        <!--是否使用静态文件名-->
        <param name="StaticLogFileName" value="false" />
        <!--日志文件名-->
        <param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
        <!--文件创建的方式,这里是以Date方式创建-->
        <param name="RollingStyle" value="Date" />
        <!--输出级别在INFO和ERROR之间的日志-->
        <filter type="log4net.Filter.LevelRangeFilter">
            <param name="LevelMin" value="ALL" />
            <param name="LevelMax" value="FATAL" />
        </filter>
        <!--信息日志布局-->
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
        </layout>
    </appender>

    <!--错误日志类-->
    <logger name="logerror">
        <!--日志类的名字-->
        <level value="ALL" />
        <!--定义记录的日志级别-->
        <appender-ref ref="ErrorAppender" />
    </logger>
    <!--信息日志类-->
    <logger name="loginfo">
        <!--日志类的名字-->
        <level value="ALL" />
        <!--定义记录的日志级别-->
        <appender-ref ref="InfoAppender" />
    </logger>
    <!--错误日志附加介质-->
    <!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
    <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
        <!--日志输出到exe程序这个相对目录下-->
        <param name="File" value="logs\\errors\\" />
        <!--输出的日志不会覆盖以前的信息-->
        <param name="AppendToFile" value="true" />
        <!--备份文件的个数-->
        <param name="MaxSizeRollBackups" value="50"/>
        <!--最小锁定模型以允许多个进程可以写入同一个文件-->
        <param name="MaxFileSize" value="10240" />
        <!--当前日志文件的最大大小-->
        <param name="lockingModel"  type="log4net.Appender.FileAppender+MinimalLock" />
        <!--是否使用静态文件名-->
        <param name="StaticLogFileName" value="false" />
        <!--日志文件名-->
        <param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
        <!--文件创建的方式,这里是以Date方式创建-->
        <param name="RollingStyle" value="Date" />
        <!--错误日志布局-->
        <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="[%t]异常类:%c [%x] 异常信息:%m%n"  />
        </layout>
    </appender>
    <!--信息日志附加介质-->
    <!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
    <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
        <!--日志输出到exe程序这个相对目录下-->
        <param name="File" value="logs\\infos\\" />
        <!--输出的日志不会覆盖以前的信息-->
        <param name="AppendToFile" value="true" />
        <!--备份文件的个数-->
        <param name="MaxSizeRollBackups" value="50" />
        <!--最小锁定模型以允许多个进程可以写入同一个文件-->
        <param name="MaxFileSize" value="10240" />
        <!--当前日志文件的最大大小-->
        <param name="lockingModel"  type="log4net.Appender.FileAppender+MinimalLock" />
        <!--是否使用静态文件名-->
        <param name="StaticLogFileName" value="false" />
        <!--日志文件名-->
        <param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
        <!--文件创建的方式,这里是以Date方式创建-->
        <param name="RollingStyle" value="Date" />
        <!--信息日志布局-->
        <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%m%n"  />
        </layout>
    </appender>
</log4net>

 

2.1.3.程序代码

         a)依赖注入模式

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddLogging(logBuilder =>
{
    logBuilder.AddConsole();
    logBuilder.AddDebug();
    logBuilder.AddLog4Net();
});

var app = builder.Build();
app.MapControllers();


app.Run();

 

         b)工厂模式

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
var loggerFactory = LoggerFactory.Create(logBuilder =>
{
    logBuilder.ClearProviders();
    logBuilder.AddConsole();
    logBuilder.AddDebug();
    logBuilder.AddLog4Net();
    logBuilder.SetMinimumLevel(LogLevel.Trace);
});
ILogger _logger = loggerFactory.CreateLogger<Program>();
_logger.LogTrace("LogTrace");
_logger.LogDebug("LogDebug");
_logger.LogInformation("LogInformation");
_logger.LogWarning("LogWarning");
_logger.LogError("LogError");
_logger.LogCritical("LogCritical");


var app = builder.Build();
app.MapControllers();


app.Run();

 

2.2.传统模式

说实话,俺是一个比较纯粹的人,不太喜欢黑魔法,所以使用传统方式记录日志,我更加喜欢。传统方式记录日志的过程没有改变,简单记录一下使用过程:

a)设置配置文件,操作如上,此处不再赘述。

b)创建Log4Writer类

    public class Log4Writer
    {
        private static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("loginfo");
        private static readonly log4net.ILog logerror = log4net.LogManager.GetLogger("logerror");
        public static void WriteLog(string info)
        {
            if (loginfo.IsInfoEnabled)
            {
                loginfo.Info(info);
            }
        }

        public static void WriteLog(string info, Exception ex)
        {
            if (logerror.IsErrorEnabled)
            {
                logerror.Error(info, ex);
            }
        }
    }

 

c)创建Log4Helper类

    public class LogHelper
    {
        private static object _objLocker = new object();
        private static bool _isConfigure = false;
        public static void Configure()
        {
            if (!_isConfigure)
            {
                lock (_objLocker)
                {
                    if (!_isConfigure)
                    {
                        _isConfigure = true;
                        log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("log4net.config"));
                    }
                }
            }
        }
    }

 

d)在Program中启用log4net

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

var app = builder.Build();
app.MapControllers();


jks.core.test.log.LogHelper.Configure();

app.Run();

 

e)使用测试

public IEnumerable<WeatherForecast> Get()
        {

            Log4Writer.WriteLog("aaaaaaaaaaaaaaaaaaaaaaa");


            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }

 

2.3.特别说明

很多同学可能会问,为什么使用log4net,而不是其他第三方日志程序包?

第一,因为.net framework时就在用;第二,就是因为它比较独立;第三,我不仅仅需要将日志写入到硬盘文件里,还需要写入到专门的日志系统,且日志内容设计了固定的结构。

简单的说,使用日志工具记录日志到硬盘文件是次要的,记录到专门的日志系统才是主要的、核心的。

 

三、总结

通过上述内容的分析、实验和记录,应该能够在使用asp.net core中使用日志了吧?以及如何从.net framework升级到.net core。

好了,就此结束。

 

程序源码:https://gitee.com/kinbor/jks.core.test.log

posted @ 2022-12-09 15:38  oO归客Oo  阅读(270)  评论(0编辑  收藏  举报