1、概述log4net是.Net下一个非常优秀的开源日志记录组件。log4net记录日志的功能非常强大。它可以将日志分不同的等级,以不同的格式,输出到不同的媒介。本文主要是介绍如何在Visual Studio2008中使用log4net快速创建系统日志,如何扩展以输出自定义字段。 2、一个简单的使用实例第一步:在项目中添加对log4net.dll的引用,这里引用版本是1.2.10.0。 第二步:程序启动时读取log4net的配置文件。 如果是CS程序,在根目录的Program.cs中的Main方法中添加: log4net.Config.XmlConfigurator.Configure(); 如果是BS程序,在根目录的Global.asax.cs(没有新建一个)中的Application_Start方法中添加: log4net.Config.XmlConfigurator.Configure(); 无论BS还是CS程序都可直接在项目的AssemblyInfo.cs文件里添加以下的语句: [assembly: log4net.Config .XmlConfigurator()] 也可以使用自定义的配置文件,具体请参见4.4 关联配置文件。 第三步:修改配置文件。如果是CS程序,则在默认的App.config文件(没有新建一个)中添加内容;如果是BS程序,则添加到Web.config文件中,添加内容一样,这里不再列出。 App.config文件添加内容如下: <?xmlversion="1.0"encoding="utf-8" ?> <configuration> <sectionname="log4net" type="log4net.Config.Log4NetConfigurationSect </configuration> 第四步:在程序使用。 log4net.ILog log = log4net.LogManager.GetLogger("testApp.Logging");//获取一个日志记录器 log.Info(DateTime.Now.ToString() + ": login success");//写入一条新log 这样就将信息同时输出到控制台和写入到文件名为"log-file.txt"的文件中,其中"log-file.txt"文件的路径是当前程序运行所在目录;也可以定义为绝对路径,配置如: <paramname="File"value="C:\log-file.txt" />就写入C盘根目录下log-file.txt文件中,具体使用技巧参见4.2.1。 本例的实现请参见8.6附件。 3、Log4net的主要组成部分3.1 AppendersAppenders用来定义日志的输出方式,即日志要写到那种介质上去。较常用的Log4net已经实现好了,直接在配置文件中调用即可,可参见上面配置文件例子;当然也可以自己写一个,需要从log4net.Appender.AppenderSkeleton类继承。它还可以通过配置Filters和Layout来实现日志的过滤和输出格式。 已经实现的输出方式有: AdoNetAppender将日志记录到数据库中。可以采用SQL和存储过程两种方式。 AnsiColorTerminalAppende AspNetTraceAppender BufferingForwardingAppen ConsoleAppender将日志输出到应用程序控制台。 EventLogAppender将日志写到Windows FileAppender 将日志输出到文件。 ForwardingAppender 发送日志事件到子Appenders。 LocalSyslogAppender 将日志写到local MemoryAppender 将日志存到内存缓冲区。 NetSendAppender将日志输出到Windows OutputDebugStringAppende RemoteSyslogAppender RemotingAppender通过.NET RollingFileAppender将日志以回滚文件的形式写到文件中。 SmtpAppender将日志写到邮件中。 SmtpPickupDirAppender将消息以文件的方式放入一个目录中,像IIS SMTP agent这样的SMTP代理就可以阅读或发送它们。 TelnetAppender客户端通过Telnet来接受日志事件。 TraceAppender将日志写到.NET UdpAppender将日志以无连接UDP数据报的形式送到远程宿主或用UdpClient的形式广播。 3.2 Filters使用过滤器可以过滤掉Appender输出的内容。过滤器通常有以下几种: DenyAllFilter阻止所有的日志事件被记录 LevelMatchFilter 只有指定等级的日志事件才被记录 LevelRangeFilter日志等级在指定范围内的事件才被记录 LoggerMatchFilter 与Logger名称匹配,才记录 PropertyFilter消息匹配指定的属性值时才被记录 StringMathFilter消息匹配指定的字符串才被记录 3.3 LayoutsLayout用于控制Appender的输出格式,可以是线性的也可以是XML。 一个Appender只能有一个Layout。 最常用的Layout应该是经典格式的PatternLayout,其次是SimpleLayout,RawTimeStampLayout和ExceptionLayout。然后还有IRawLayout,XMLLayout等几个,使用较少。Layout可以自己实现,需要从log4net.Layout.LayoutSkeleton类继承,来输出一些特殊需要的格式,在后面扩展时就重新实现了一个Layout。 SimpleLayout简单输出格式,只输出日志级别与消息内容。 RawTimeStampLayout 用来格式化时间,在向数据库输出时会用到。 样式如"yyyy-MM-dd HH:mm:ss" ExceptionLayout需要给Logger的方法传入Exception对象作为参数才起作用,否则就什么也不输出。输出的时候会包含Message和Trace。 PatterLayout使用最多的一个Layout,能输出的信息很多,使用方式可参见上面例子中的配置文件。PatterLayout的格式化字符串见文后附注8.1。 3.4 LoggersLogger是直接和应用程序交互的组件。Logger只是产生日志,然后由它引用的Appender记录到指定的媒介,并由Layout控制输出格式。 Logger提供了多种方式来记录一个日志消息,也可以有多个Logger同时存在。每个实例化的Logger对象对被log4net作为命名实体(Named Entity)来维护。log4net使用继承体系,也就是说假如存在两个Logger,名字分别为a.b.c和a.b。那么a.b就是a.b.c的祖先。每个Logger都继承了它祖先的属性。所有的Logger都从Root继承, Root本身也是一个Logger。 日志的等级,它们由高到底分别为: OFF > FATAL > ERROR > WARN > INFO > DEBUG 高于等级设定值方法(如何设置参见"配置文件详解")都能写入日志,Off所有的写入方法都不写到日志里,ALL则相反。例如当我们设成Info时,logger.Debug就会被忽略而不写入文件,但是FATAL, ERROR,WARN,INFO会被写入,因为他们等级高于INFO。 在具体写日志时,一般可以这样理解日志等级: FATAL(致命错误):记录系统中出现的能使用系统完全失去功能,服务停止,系统崩溃等使系统无法继续运行下去的错误。例如,数据库无法连接,系统出现死循环。 ERROR(一般错误):记录系统中出现的导致系统不稳定,部分功能出现混乱或部分功能失效一类的错误。例如,数据字段为空,数据操作不可完成,操作出现异常等。 WARN(警告):记录系统中不影响系统继续运行,但不符合系统运行正常条件,有可能引起系统错误的信息。例如,记录内容为空,数据内容不正确等。 INFO(一般信息):记录系统运行中应该让用户知道的基本信息。例如,服务开始运行,功能已经开户等。 DEBUG Logger实现的ILog接口,ILog定义了5个方法(Debug,Inof,Warn,Error,Fatal)分别对不同的日志等级记录日志。这5个方法还有5个重载。以Debug为例说明一下,其它的和它差不多。 ILog中对Debug方法的定义如下: void Debug(object message); void Debug(object message, Exception ex); 还有一个布尔属性: bool IsDebugEnabled { get; } 如果使用Debug(object message, Exception ex),则无论Layout中是否定义了%exception,默认配置下日志都会输出Exception。包括Exception的Message和Trace。如果使用Debug(object message),则日志是不会输出Exception。 最后还要说一个LogManager类,它用来管理所有的Logger。它的GetLogger静态方法,可以获得配置文件中相应的Logger: log4net.ILog log = log4net.LogManager.GetLogger("logger-name"); 3.5 Object Renders它将告诉logger如何把一个对象转化为一个字符串记录到日志里。(ILog中定义的接口接收的参数是Object,而不是String。) 例如你想把Orange对象记录到日志中,但此时logger只会调用Orange默认的ToString方法而已。所以要定义一个OrangeRender类实现log4net.ObjectRender.IObjectRender接口,然后注册它(我们在本文中的扩展不使用这种方法,而是直接实现一个自定义的Layout)。这时logger就会知道如何把Orange记录到日志中了。 3.6 RepositoryRepository主要用于日志对象组织结构的维护。 4、配置文件详解4.1 配置文件构成主要有两大部分,一是申明一个名为"log4net"的自定义配置节,如下所示: <sectionname="log4net" type="log4net.Config.Log4NetConfigurationSect 二是<log4net>节的具体配置,这是下面要重点说明的。 4.1.1<log4net>所有的配置都要在<log4net>元素里定义。 支持的属性:
支持的子元素:
4.1.2<root>实际上就是一个根logger,所有其它logger都默认继承它,如果配置文件里没有显式定义,则框架使用根日志中定义的属性。root元素没有属性。 支持的子元素:
4.1.3<logger>支持的属性:
支持的子元素:
4.1.4<appender>定义日志的输出方式,只能作为 log4net 的子元素。name属性必须唯一,type属性必须指定。 支持的属性:
支持的子元素:
实际上<appender>所能包含的子元素远不止上面4个。 4.1.5<layout>布局,只能作为<appender>的子元素。 支持的属性:
支持的子元素:
4.1.6<filter>过滤器,只能作为<appender>的子元素。 支持的属性:
支持的子元素:
4.1.7<param><param>元素可以是任何元素的子元素。 支持的属性:
支持的子元素:
4.2 <appender>配置 下面只对写入回滚文件与输出到数据库(这里使用SQL数据库)配置体会说一下,其他配置可参考官方网站:http://logging./log4net/release/config-examples.html 4.2.1写入回滚文件 <!--日志文件路径,"/"与"\"作用相同,到达的目录相同,文件夹不存在则新建--> <!--按文件大小方式输出时在这里指定文件名,并且当天的日志在下一天时在文件名后自动追加当天日期形成新文件。--> <!—按照日期形式输出时,直接连接元素DatePattern的value形成文件路径。此处使用这种方式--> <!--param的名称,可以直接查对应的appender类的属性名即可,这里要查的就是RollingFileAppender类的属性 --> <!—此处按日期产生文件夹,文件名固定。注意"的位置--> <!—这是按日期产生文件夹,并在文件名前也加上日期--> <!—这是先按日期产生文件夹,再形成下一级固定的文件夹—> 超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。 可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志--> <!--计数类型为1,2,3…--> <!—过滤设置,LevelRangeFilter为使用的过滤器。 --> <!—此处用继承了log4net.Layout.PatternLayout的自定义布局,TGLog.ExpandLayout2 为命名空间。%property{Operator}、%property{Action}是自定义的输出--> </appender> 注意这些配置属性有些是可选的,如果需要,一定要写正确,否则要么输出的不是自己想要的结果,要么干脆不输出任何信息。 4.2.1写入SQL数据库需要在相应的数据库中准备好一张表,创建语句如下: CREATE TABLE [Log] ( [ID] [int] IDENTITY (1, 1) NOT NULL , [Date] [datetime] NOT NULL , [Thread] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL , [Level] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL , [Logger] [varchar] (200) COLLATE Chinese_PRC_CI_AS NULL , [Operator] [int] NULL , [Message] [text] COLLATE Chinese_PRC_CI_AS NULL , [ActionType] [int] NULL , [Operand] [varchar] (300) COLLATE Chinese_PRC_CI_AS NULL , [IP] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL , [MachineName] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL , [Browser] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL , [Location] [text] COLLATE Chinese_PRC_CI_AS NULL , [Exception] [text] COLLATE Chinese_PRC_CI_AS NULL ) <appendername="ADONetAppender"type="log4net.Appender.ADONetAppender,log4net"> <!--BufferSize为缓冲区大小,只有日志记录超设定值才会一块写入到数据库--> <bufferSizevalue="10" /><!—或写为<param name="BufferSize" value="10" />--> <!--引用--> <connectionTypevalue="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <!--连接数据库字符串--> <connectionStringvalue="data source=.;initial catalog=Test;integrated security=false;persist security info=True;User ID=sa;Password=;" /> <!--插入到表Log--> <commandTextvalue="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Operator],[Message],[ActionType],[Operand],[IP],[MachineName],[Browser],[Location],[Exception]) VALUES (@log_date, @thread, @log_level, @logger,@operator, @message,@action_type,@operand,@ip,@machineName,@browser,@location,@exception)" /> <!—日志记录时间,RawTimeStampLayout为默认的时间输出格式--> <!—长度不可以省略,否则不会输出--> <!—设置为Int32时只有bufferSize的value<="1"才正确输出,没有找出原因。--> </appender> 注意: 向表中输出的字段不能多于数据表本身字段,而反之则可以,但这些多余字段一定使其可以为空,否则便写不到数据库; 输出字段的类型一定是对应数据表字段数据类型可以隐式转换的,而且长度也不能超过,否则也不能写入; 数据表字段设置尽量可以为空,这样可以避免一条日志记录存在空数据导致后面的日志都记录不了。 4.3<logger>的配置在配置文件<appender>中的配置好了输出的介质,格式,过滤方式,还要定义日志对象<logger>。 在框架的体系里,所有的日志对象都是根日志(root logger)的后代。 因此如果一个日志对象没有在配置文件里显式定义,则框架使用根日志中定义的属性。在<root>标签里,可以定义level级别值和Appender的列表。如果没有定义LEVEL的值,则缺省为DEBUG。可以通过<appender-ref>标签定义日志对象使用的Appender对象。<appender-ref>声明了在其他地方定义的Appender对象的一个引用。在一个logger对象中的设置会覆盖根日志的设置。而对Appender属性来说,子日志对象则会继承父日志对象的Appender列表。这种缺省的行为方式也可以通过显式地设定<logger>标签的additivity属性为false而改变。 <root>不显式申明时使用默认的配置。我觉得在使用时不定义<root>,自定义多个<logger>,在程序中记录日志时直接使用<logger>的name来查找相应的<logger>,这样更灵活一些。例如: <!--同时写两个文件和数据库--> <loggername="ReflectionLayout"> </logger> 4.4关联配置文件log4net默认关联的是应用程序的配置文件App.config(BS程序是Web.config),可以使用程序集自定义属性来进行设置。下面来介绍一下这个自定义属性: log4net.Config.XmlConifguratorAttribute XmlConfiguratorAttribute ConfigFile: 配置文件的名字,文件路径相对于应用程序目录 (AppDomain.CurrentDomain.BaseDirectory)。ConfigFile属性不能和ConfigFileExtension属性一起使用。 ConfigFileExtension: 配置文件的扩展名,文件路径相对于应用程序的目录。ConfigFileExtension属性不能和ConfigFile属性一起使用。 Watch: 如果将Watch属性设置为true,就会监视配置文件。当配置文件发生变化的时候,就会重新加载。 如果ConfigFile和ConfigFileExtension都没有设置,则使用应用程序的配置文件App.config(Web.config)。 可以在项目的AssemblyInfo.cs文件里添加以下的语句: [assembly: log4net.Config.XmlConfigurator(Watch = true)] //监视配置文件,App.exe.log4net。 [assembly: log4net. Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)] //使用配置文件log4net.config,不监视改变。注意log4net.config文件的目录,BS程序在站点目录//下,CS则在应用程序启动目录下,如调试时在\bin\Debug下,一般将文件属性的文件输出目录调为//始终复制即可 [assembly: log4net. Config.XmlConfigurator(ConfigFile = "log4net.config")] //使用配置文件log4net.config,不监视改变 [assembly: log4net. Config.XmlConfigurator()] 也可以在Global.asax的Application_Start里或者是Program.cs中的Main方法中添加,注意这里一定是绝对路径,如下所示: //这是在BS程序下,使用自定义的配置文件log4net.xml,使用Server.MapPath("~") + //@"\log4net.xml"来取得路径。 \log4net.xml为相对于站点的路径 // ConfigureAndWatch()相当于Configure(Watch = true) log4net.Config.XmlConfigurator.ConfigureAndWatch( new System.IO.FileInfo(Server.MapPath("~") + @"\log4net.xml")); //这是在CS程序下,可以用以下方法获得: string assemblyFilePath = Assembly.GetExecutingAssembly().Location; string assemblyDirPath = Path.GetDirectoryName(assemblyFilePath); string configFilePath = assemblyDirPath + " "; log4net.Config.XmlConfigurator.ConfigureAndWatch( newFileInfo(configFilePath)); 或直接使用绝对路径: //使用自定义的配置文件,直接绝对路径为:c:/log4net.config log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(@"c:/log4net.config")); 5、如何记录日志Log4net使用很方便,先申明一个封装类ILog的对象,如下: log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout"); 其中"ReflectionLayout"便是我们自定义的日志对象<logger>的name的值。 对应5个日志输出级别,log有5 个方法,每个方法都有两个重载,使用如下: try 如果我们需要输出的消息是要区别开来,不按一个字符串全部输出,就需要进行一些扩展了。 |
|