背景

  在程序中,我们调试运行时信息,Log4Net是一个不错的解决方案。不知道是我用的不好,用到最后反而都不想看日志了。原因是因为我n个功能使用的默认的Logger来记录日志,这样以来,所有功能记录的信息都依赖同一个配置,于是所有的信息都在一个文件中,有时候查找起来,极其不方便。

  我想,能不能按照功能分类呢?如果通过配置不同的logger,然后功能根据不同的LoggerName加载Ilog实例,是可以做到。但由于这些功能的log配置差异性极小,也许仅仅就是文件名不同。于是想通过代码进行配置。

解决方案

  想来这样的需求应该也算正常,但经过查找,发现在log4j中有相关的咨询,但看不懂,只能自己下载log4net的源码,看看它的运行原理。

  如果我们需要通过配置不同的ILog,流程是这样的,首先要创建一个ILoggerRepository,通过它来进行日志等级的配置,和各种Appender,接着通过LogManager在ILoggerRepository获取一个Ilog对象,就可以写日志了。代码如下:

        public static ILog GetLogger(string repositoryName = "")
{
if (string.IsNullOrEmpty(repositoryName)) return LogManager.GetLogger("Defalut"); ILoggerRepository repository = null;
try
{
repository = LogManager.GetRepository(repositoryName);
}
catch (Exception) { } //找到直接返回ilog
if (repository != null)
return LogManager.GetLogger(repositoryName, "Defalut"); //未找到则创建,多线程下很有可能创建时,就存在了
try
{
repository = LogManager.CreateRepository(repositoryName);
}
catch (Exception)
{
repository = LogManager.GetRepository(repositoryName);
} //配置日志等级 读取Appsettings默认配置
var appSet = ConfigurationManager.AppSettings.AllKeys; //查找日志等级
const string logLevel = "LogLevel";
var hasSettings = Array.IndexOf(appSet, logLevel);
if (hasSettings > -)
{
var level = ConfigurationManager.AppSettings[logLevel].ToLower();
if (level == "all") repository.Threshold = Level.All;
else if (level == "debug") repository.Threshold = Level.Debug;
else if (level == "info") repository.Threshold = Level.Info;
else if (level == "warn") repository.Threshold = Level.Warn;
else if (level == "error") repository.Threshold = Level.Error;
else if (level == "fatal") repository.Threshold = Level.Fatal;
else if (level == "off") repository.Threshold = Level.Off;
}
else repository.Threshold = Level.All; //查找输出Appender
const string logAppender = "LogAppender";
hasSettings = Array.IndexOf(appSet, logAppender);
if (hasSettings > -)
{
var appenders = ConfigurationManager.AppSettings[logAppender].ToLower().Split(',');
foreach (var appender in appenders)
{
if (appender == "rollingfile") LoadRollingFileAppender(repository);
else if (appender == "console") LoadConsoleAppender(repository);
else if(appender == "trace") LoadTraceAppender(repository);
}
}
else LoadRollingFileAppender(repository); return LogManager.GetLogger(repositoryName, "Default");
}

  Log4net 会自动维护ILog和ILoggerRepository,所以不用保存,通过LogManger获取即可。但是我没有找到方法来查找指定的ILoggerRepository是否存在,所以在上述代码中通过try catch进行判断。由于我们是通过代码方式配置log4net,但仍旧希望通过配置来设置日志等级和输出类型,所以我选择在Appsettings文件中进行配置,一次配置,针对所有的ILoggerRepository都生效。之所以不是针对每一个功能进行配置,主要是由于配置麻烦,而且如果真要这么做,直接在log4net中配置不同的logger,通过loggername引用,可能会更好些。

日志维护

  于是接下来的问题是,如何删除日志?

  log4net可以配置RollingFileAppender,翻译过来是滚动文件。通过设置MaximumFileSize和MaxSizeRollBackups 2个参数可以完成这样的目的,该日志文件每达到一定大小就会产生一个新文件,文件最大总数则为MaxSizeRollBackups,但前提的是文件名一致。

  比如我们采用如下配置:

    <!--RollingFileAppender:输出到文件中-->
<appender name="SysAppender" type="log4net.Appender.RollingFileAppender">
<!--日志的路径-->
<file value="Logs/" />
<!--是否覆盖,默认是追加true-->
<appendToFile value="true"/>
<!--不占用日志文件进程-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<rollingStyle value="Composite"/>
<!--文件名称-->
<DatePattern value="yyyy-MM-dd HH'时.log'"></DatePattern>
<!--设置无限备份=-1 ,最大备份数为1000-->
<param name="MaxSizeRollBackups" value="1000"/>
<!--每个文件的大小-->
<param name="MaximumFileSize" value="500KB"/>
<!--名称是否可以更改 为false为可以更改-->
<param name="StaticLogFileName" value="false"/>
<layout type="log4net.Layout.PatternLayout">
<!--输出格式-->
<conversionPattern value="%n【记录时间】%date%n【描述】%message%n"/>
</layout>
</appender>

  效果则是 日志以小时为单位,每小时最大备份总数为1000,每到500kb后形成日志文件。当随着天数的增加,文件也开始变多,需要我们自己去清理。所以上述配置可以稍微改下:

    <!--RollingFileAppender:输出到文件中-->
<appender name="SysAppender" type="log4net.Appender.RollingFileAppender">
<!--日志的路径-->
<file value="Logs/日志.log" />
<!--是否覆盖,默认是追加true-->
<appendToFile value="true"/>
<!--不占用日志文件进程-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<rollingStyle value="Composite"/>
<!--文件名称-->
<DatePattern value="yyyy-MM-dd HH'时.log'"></DatePattern>
<!--设置无限备份=-1 ,最大备份数为1000-->
<param name="MaxSizeRollBackups" value="1000"/>
<!--每个文件的大小-->
<param name="MaximumFileSize" value="500KB"/>
<!--名称是否可以更改 为false为可以更改-->
<param name="StaticLogFileName" value="true"/>
<layout type="log4net.Layout.PatternLayout">
<!--输出格式-->
<conversionPattern value="%n【记录时间】%date%n【描述】%message%n"/>
</layout>
</appender>

  主要是设置了日志文件名,而且是静态名称,不允许更改。这样以来,日志文件最多只有1000个了,就不用手工维护了,你会看到这样的日志文件名:

  日志.log   日志.log.1  日志.log.2   ... 默认是文件名最后的数字越大,时间最老,所以查看新日志,主要是在 第一个文件名 中。

  另外提醒下:如果设置Appender使用了静态文件名,那么历史日志会被覆盖,而极其在意历史日志的应用,建议不要使用此方案,清理日志的话,还是老老实实写代码吧。

测试代码下载

Log4Net日志分类和自动维护的更多相关文章

  1. Log4net日志文件自动按月份存放和日志独占问题的解决

    让log4net日志文件自动按月份存放 log4net日志文件的作用还真不小,可以保存管理员.用户对数据库的任何操作,保存管理员和用户的登录记录,分析系统运行错误,所以不舍得随便将日志文件Delete ...

  2. 如何让Log4net日志文件按每月归成一个文件夹,StaticLogFileName参数的用法

    想要让Log4net日志(以下称日志)按每月自动归类为一个文件夹,为此,学习和修改了log4net.config文件.查了资料,重点是以下这些参数:      <param name=" ...

  3. LOG4NET日志配置及使用

    Log4net的安装 Install-Package log4net 1.先弄个日志记录的类 /// <summary> /// 使用LOG4NET记录日志的功能,在WEB.CONFIG里 ...

  4. log4net日志的配置及简单应用

    在程序运行中,往往会出现各种出乎开发人员意料的异常或者错误,所以,记录详细的程序运行日志信息,有利于开发人员和运维人员排查异常信息,提高工作效率.而本菜鸟在大神推荐和指导下使用log4net这一插件工 ...

  5. Log4net日志使用教程-控制台、文本、数据库三种记录方式

    一.log4net简介: 1. Log4net的优点: 几乎所有的大型应用都会有自己的用于跟踪调试的API.因为一旦程序被部署以后,就不太可能再利用专门的调试工具了.然而一个管理员可能需要有一套强大的 ...

  6. mysql日志分类

    mysql的日志分类: (1)错误日志:记录mysql服务的启动,运行,停止mysql服务时出现的问题 [mysqld] log_error=[/path/filename] (2)通用查询日志:记录 ...

  7. C# Log4Net 日志

    C#使用Log4Net记录日志 第一步:下载Log4Net            下载地址:http://logging.apache.org/log4net/download_log4net.cgi ...

  8. 如何在通用权限管理系统中集成log4net日志功能

    开发人员都知道,在系统运行中要记录各种日志,自己写一个日志功能,无论是在效率还是功能扩展上来说都不是很好,目前大多用的是第三方的日志系统,其中一个非常有名,用的最多的就是log4net.下面是关于这个 ...

  9. ASP.NET MVC4中加入Log4Net日志记录功能

    前言 在之前的.NET中,微软还没有提供过像样的日志框架,目前能用的一些框架比如Log4Net.NLog.CommonLogging等,虽然多多少少使用起来有点费劲,但这里还是简单分享一下Log4Ne ...

随机推荐

  1. C语言进阶——浮点数的秘密03

    浮点数在内存中的储存方式为:符号位 指数位 尾数 float和double类型的数据在计算机内部的表实方法是一样的,但是由于所占的存贮空间的不同,其分别能表示的数值范围和精度不同. 类型 f符号位 指 ...

  2. 基于itchat定制聊天机器人

    #coding=utf8import requestsimport itchat #key自己到图灵注册一个 KEY = '************************************** ...

  3. 我今天的收获,必备stadio 插件

    1.ADBWIFI 必须的,说不定你就用到了. 2.ADB Idea 必须 3.JavaDoc 4.Translation 5.Gradle Killer

  4. ListView, GirldList 等setCurrentItem 不立即刷新

    有时候,你调用了adapter的setCurrentItem,然后立马就去获得第一个view的坐标,那么你获取的不是最新的. 要知道程序的并行性.程序运行很快,所以,延迟200s去得到第一个view的 ...

  5. MySQL单表查询语句练习题

    /*1. 查询出部门编号为30的所有员工*/ /* 分析: 1). 列:没有说明要查询的列,所以查询所有列 2). 表:只一张表,emp 3). 条件:部门编号为30,即deptno=30 */ ; ...

  6. 三层还是DDD,ORM还是Ado.Net,何去何从?

    我本想把这个问题放到博问去,前几次有去博问问过之类的问题,无奈大神们可能都不屑回答别人的低级问题.所以放到随笔里,一方面把自己对ORM.架构的一些看法写下来抛砖引玉,另一方面最主要的是想寻求大神们指指 ...

  7. MySQL隐式转换测试

      Preface       There're various data type in MySQL such as number,string,date,time,lob,etc.The data ...

  8. SQL面试题:之一(难度:中等)

    SQL面试题:之一(难度:中等)

  9. linux ubuntu开启sshd

    which ssh #查看文件 sudo apt-get install ssh #安装ssh cd /etc/init.d #切换目录 ls -l | grep ssh #执行启动脚本 sudo s ...

  10. day06_02 元组

    1.0 元组 元组被称为只读列表,即数据可以被查询,但不能被修改,所以,列表的切片操作同样适用于元组.元素卸载小括号(())里,元素之间用逗号隔开. tup1 = () #空元组 tup2 = (20 ...