1、介绍
1.1、概述
1.2、工作流
2、配置
2.1、基本配置
2.2、配置特性
2.3、appSettings文件配置
2.4、.config文件配置
3、数据上下文
4、附加器appender配置
4.1、Log4Net内置附加器
5、格式化输出layouts
5.1、格式化布局PatternLayout
6、参考
Log4net是.Net下一个非常优秀的功能强大的开源日志记录组件,它可以将日志分不同的等级,以不同的格式,输出到不同的媒介,在运行时启用日志记录,而无需修改应用程序二进制文件。Log4net可以使用独立的XML配置文件配置,也可以嵌入到别的.config配置文件,它 可以监视其配置文件的更改并动态应用配置器所做的更改。 日志级别、附加程序、布局以及几乎所有其他内容都可以在运行时进行调整。 在许多情况下,可以在不终止相关进程的情况下诊断应用程序问题。 在调查已部署应用程序的问题时,这可能是一个非常有价值的工具。
下图转载自 闫宝平的博客 ,一眼就能看明白Log4Net工作流过程,我这里就不赘述了,需要的可以看他这篇文章 log4net工作原理(1) 。
Log4net 具有三个主要组件:loggers(记录器)、repository(储存库)、appenders(附加器)和layouts(布局)。这四种类型的组件协同工作,使开发人员能够根据消息类型和级别记录消息,并在运行时控制这些消息的格式和报告位置。另外还有两个辅助组件:Appender Filters(过滤器)和Object Renderers(对象渲染器)。Appender Filters(过滤器)使用不同附加程序上定义的过滤器链来完成更复杂和自定义的事件过滤。Object Renderers(对象渲染器)根据用户指定的标准呈现日志消息的内容。
loggers(记录器): 与应用程序需要交互的主要组件,它用来产生日志消息。产生的日志消息并不直接显示,还要预先经过Layout的格式化处理后才会输出。Logger提供了多种方式来记录一个日志消息,你可以在你的应用程序里创建多个Logger,每个实例化的Logger对象都被log4net框架作为命名实体(named entity)来维护。这意味着为了重用Logger对象,你不必将它在不同的类或对象间传递,只需要用它的名字为参数调用就可以了。log4net框架使用继承体系,继承体系类似于.NET中的名字空间。也就是说,如果有两个logger,分别被定义为a.b.c和a.b,那么我们说a.b是a.b.c的祖先。每一个logger都继承了祖先的属性。 Log4net框架定义了一个ILog接口,所有的logger类都必须实现这个接口。如果你想实现一个自定义的logger,你必须首先实现这个接口。在ILog的接口中有五种不同的方法
void Debug(object message); void Info(object message); void Warn(object message); void Error(object message); void Fatal(object message);
跟踪一个应用程序,这五种方法是Logger对象设置的不同日志优先级别 ALL、DEBUG、INFO、WARN、ERROR、FATAL、OFF 。
repository(储存库): 日志存储库被认为是高级功能。对于大多数用户来说,默认行为应该足够了。Log4net 支持日志存储库。存储库是唯一命名的。每个存储库都是一个(ILoggerRepository)。多个程序集可以链接到同一个存储库。默认情况下,每个进程(更准确地说是每个 AppDomain)有一个日志存储库。这扩展到加载到进程中的所有程序集,并允许它们共享一个配置。存储库的配置只需要完成一次,通常在应用程序的入口点,以编程方式或使用配置属性。可以使用LogManager.CreateRepository 方法创建命名的日志存储库。可以使用 LogManager.GetRepository方法检索存储库。以这种方式创建的存储库需要以编程方式配置。
appenders(附加器): 一个好的日志框架应该能够产生多目的地的输出。比如说输出到控制台或保存到一个日志文件。log4net 能够很好的满足这些要求。它使用一个叫做Appender的组件来定义输出介质。正如名字所示,这些组件把它们附加到Logger日志组件上并将输出传递到输出流中。你可以把多个Appender组件附加到一个日志对象上。 Log4net框架提供了几个Appender组件。关于log4net提供的Appender组件的完整列表可以在log4net框架的帮助手册中找到。有了这些现成的Appender组件,一般来说你没有必要再自己编写了。但是如果你愿意,可以从log4net.Appender.AppenderSkeleton类继承。
layouts(布局): Layout 组件用于向用户显示最后经过格式化的输出信息。输出信息可以以多种格式显示,主要依赖于我们采用的Layout组件类型。可以是线性的或一个XML文件。Layout组件和一个Appender组件一起工作。API帮助手册中有关于不同Layout组件的列表。一个Appender对象,只能对应一个Layout对象。要实现你自己的Layout类,你需要从log4net.Layout.LayoutSkeleton类继承,它实现了ILayout接口。
Appender Filters(过滤器): 一个Appender 对象缺省地将所有的日志事件传递到输出流。Appender的过滤器(Appender Filters) 可以按照不同的标准过滤日志事件。在log4net.Filter的名字空间下已经有几个预定义的过滤器。使用这些过滤器,你可以按照日志级别范围过滤日志事件,或者按照某个特殊的字符串进行过滤。你可以在API的帮助文件中发现更多关于过滤器的信息。
Object Renderers(对象渲染器): 根据用户指定的标准呈现日志消息的内容。例如,如果您经常需要记录 Oranges,这是您当前项目中使用的一种对象类型,那么您可以注册一个 OrangeRenderer ,每当需要记录一个橙色时就会调用它。对象渲染遵循类层次结构。例如,假设橙子是水果,如果您注册一个 FruitRenderer,那么包括橙子在内的所有水果都将由FruitRenderer渲染 ,当然除非您注册了一个特定于橙子的 OrangeRenderer。对象渲染器必须实现 log4net.ObjectRenderer.IObjectRenderer 接口。请注意,DebugFormat、 InfoFormat、WarnFormat、 ErrorFormat和FatalFormat方法不使用 ObjectRenderers。
Log4Net通过代码配置需要消耗大量精力且还不灵活,目前只支持XML编写配置文件,还支持立即修改后自动更新到系统里。使用Log4Net之前需要Nuget引入 log4net 2.0 . 14 包。 如果在Asp.NETCore项目还需要Nuget引入 Microsoft.Extensions.Logging.Log4Net.AspNetCore 6.1 . 0 包。
看看下面一个使用系统预设控制台日志的配置使用案例。
1 using log4net; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 8 namespace Demo13_Log4Net.BaseConfig 10 public class Student 11 { 12 public string Name { get; set; } 13 public int Age { get; set; } 14 private static readonly ILog _log = LogManager.GetLogger(typeof(Student)); 15 public void DoIt() 16 { 17 _log.Debug("Student:public void DoIt()"); 18 } 19 } 类Student1 using log4net; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 8 namespace Demo13_Log4Net.BaseConfig 10 public class BaseConfigMain 11 { 12 private static readonly ILog _log = LogManager.GetLogger(typeof(BaseConfigMain)); 13 public static void Test1() 14 { 15 //使用系统预设的控制台基本配置 16 log4net.Config.BasicConfigurator.Configure(); 17 _log.Info($"进入 {AppDomain.CurrentDomain.GetType().FullName} 方法"); 18 Student stu = new Student(); 19 stu.DoIt(); 20 _log.Info($"退出 {AppDomain.CurrentDomain.GetType().FullName} 方法"); 21 } 22 } 案例代码BaseConfigMain上例中的配置我们可以写成配置文件 BaseConfig.log4net ,然后使用 XmlConfigurator.Configure(new System.IO.FileInfo(xmlFile)); 读取配置文件。
1 using log4net; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 8 namespace Demo13_Log4Net.BaseConfig 10 public class Student 11 { 12 public string Name { get; set; } 13 public int Age { get; set; } 14 private static readonly ILog _log = LogManager.GetLogger(typeof(Student)); 15 public void DoIt() 16 { 17 _log.Debug("Student:public void DoIt()"); 18 } 19 } 类Student1 <log4net> 2 <!-- 新增一个控制台类型的附加器A1配置 --> 3 <appender name="A1" type="log4net.Appender.ConsoleAppender"> 4 <!-- A1使用PatternLayout布局格式 --> 5 <layout type="log4net.Layout.PatternLayout"> 6 <conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" /> 7 </layout> 8 </appender> 10 <!-- 设置根记录器为DEBUG,使用A1作为附加器 --> 11 <root> 12 <level value="DEBUG" /> 13 <appender-ref ref="A1" /> 14 </root> 15 </log4net>配置文件BaseConfig.log4net1 using log4net; 2 using log4net.Config; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 9 namespace Demo13_Log4Net.BaseConfig 10 { 11 public class BaseConfigMain 12 { 13 #region 案例2、配置文件代替默认系统控制台配置 14 private static readonly ILog _log2 = LogManager.GetLogger(typeof(BaseConfigMain)); 15 public static void Test2() 16 { 17 var xmlFile = AppDomain.CurrentDomain.BaseDirectory+ @"BaseConfig\BaseConfig.log4net"; 18 XmlConfigurator.Configure(new System.IO.FileInfo(xmlFile)); 19 _log2.Info($"进入 {AppDomain.CurrentDomain.GetType().FullName} 方法"); 20 Student stu = new Student(); 21 stu.DoIt(); 22 _log2.Info($"退出 {AppDomain.CurrentDomain.GetType().FullName} 方法"); 23 } 24 #endregion 25 } 案例代码BaseConfigMain配置记录器过滤等级,改配置文件为 BaseConfigWARN.log4net ,注意对过滤器的设置 <logger name="Demo13_Log4Net.BaseConfig.Student"> ,修改如下。
1 using log4net; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 8 namespace Demo13_Log4Net.BaseConfig 10 public class Student 11 { 12 public string Name { get; set; } 13 public int Age { get; set; } 14 private static readonly ILog _log = LogManager.GetLogger(typeof(Student)); 15 public void DoIt() 16 { 17 _log.Debug("Student:public void DoIt()"); 18 } 19 } 类Student1 <log4net> 2 <!-- 新增一个控制台类型的附加器A1配置 --> 3 <appender name="A1" type="log4net.Appender.ConsoleAppender"> 4 <!-- A1使用PatternLayout布局格式 --> 5 <layout type="log4net.Layout.PatternLayout"> 6 <conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" /> 7 </layout> 8 </appender> 10 <!-- 设置根记录器为DEBUG,使用A1作为附加器 --> 11 <root> 12 <level value="DEBUG" /> 13 <appender-ref ref="A1" /> 14 </root> 16 <!-- 名为Demo13_Log4Net.BaseConfig.Student的记录器日志等级调整为WARN --> 17 <logger name="Demo13_Log4Net.BaseConfig.Student"> 18 <level value="WARN" /> 19 </logger> 20 </log4net>配置文件BaseConfigWARN.log4net1 using log4net; 2 using log4net.Config; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 9 namespace Demo13_Log4Net.BaseConfig 10 { 11 public class BaseConfigMain 12 { 13 #region 案例3、配置文件修改日志过滤等级 14 private static readonly ILog _log3 = LogManager.GetLogger(typeof(BaseConfigMain)); 15 public static void Test3() 16 { 17 var xmlFile = AppDomain.CurrentDomain.BaseDirectory + @"BaseConfig\BaseConfigWARN.log4net"; 18 XmlConfigurator.Configure(new System.IO.FileInfo(xmlFile)); 19 _log3.Info($"进入 {AppDomain.CurrentDomain.GetType().FullName} 方法"); 20 Student stu = new Student(); 21 stu.DoIt(); 22 _log3.Info($"退出 {AppDomain.CurrentDomain.GetType().FullName} 方法"); 23 } 24 #endregion 25 } 案例代码BaseConfigMain下面案例是同事使用多个记录器的。
1 using log4net; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 8 namespace Demo13_Log4Net.BaseConfig 10 public class Student 11 { 12 public string Name { get; set; } 13 public int Age { get; set; } 14 private static readonly ILog _log = LogManager.GetLogger(typeof(Student)); 15 public void DoIt() 16 { 17 _log.Debug("Student:public void DoIt()"); 18 } 19 } 类Student1 <log4net> 2 <appender name="Console" type="log4net.Appender.ConsoleAppender"> 3 <layout type="log4net.Layout.PatternLayout"> 4 <conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" /> 5 </layout> 6 </appender> 8 <appender name="RollingFile" type="log4net.Appender.RollingFileAppender"> 9 <file value="Test.log" /> 10 <appendToFile value="true" /> 11 <maximumFileSize value="100KB" /> 12 <maxSizeRollBackups value="2" /> 14 <layout type="log4net.Layout.PatternLayout"> 15 <conversionPattern value="%level %thread %logger - %message%newline" /> 16 </layout> 17 </appender> 19 <root> 20 <level value="DEBUG" /> 21 <appender-ref ref="Console" /> 22 <appender-ref ref="RollingFile" /> 23 </root> 24 </log4net>配置文件MultipleAppendersConfig.log4net1 using log4net; 2 using log4net.Config; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 9 namespace Demo13_Log4Net.BaseConfig 10 { 11 public class BaseConfigMain 12 { 13 #region 案例4、同时多个记录器工作 14 private static readonly ILog _log4 = LogManager.GetLogger(typeof(BaseConfigMain)); 15 public static void Test4() 16 { 17 var xmlFile = AppDomain.CurrentDomain.BaseDirectory + @"BaseConfig\MultipleAppendersConfig.log4net"; 18 XmlConfigurator.Configure(new System.IO.FileInfo(xmlFile)); 19 _log4.Info($"进入 {AppDomain.CurrentDomain.GetType().FullName} 方法"); 20 Student stu = new Student(); 21 stu.DoIt(); 22 _log4.Info($"退出 {AppDomain.CurrentDomain.GetType().FullName} 方法"); 23 } 24 #endregion 25 } 案例代码BaseConfigMain1 var xmlFile = AppDomain.CurrentDomain.BaseDirectory + @"BaseConfig\MultipleAppendersConfig.log4net"; //绝对路径 2 XmlConfigurator.Configure(new System.IO.FileInfo(xmlFile)); //不监视配置文件改变 3 //XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(xmlFile)); //这是读取配置并监视配置文件改变代码里读取配置文件上面的案例里Log4Net的配置文件都是通过代码读取的 XmlConfigurator.Configure(new System.IO.FileInfo(xmlFile)); ,其实使用 XmlConifguratorAttribute 在项目的AssemblyInfo.cs文件里配置,举几个使用案例:
[assembly: log4net.Config.XmlConfigurator(Watch = true)] //监视默认的配置文件,App.exe.config [assembly: log4net. Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)] //监视配置文件,App.exe.log4net [assembly: log4net. Config.XmlConfigurator(ConfigFile = "log4net.config")] //使用配置文件log4net.config,不监视改变。注意log4net.config文件的目录,BS程序在站点目录//下,CS则在应用程序启动目录下,如调试时在/bin/Debug下,一般将文件属性的文件输出目录调为//始终复制即可 [assembly: log4net. Config.XmlConfigurator()] //使用配置文件log4net.config,不监视改变 最后介绍一下 XmlConifguratorAttribute 有三个属性:
ConfigFile: 配置文件的名字,文件路径相对于应用程序目录(AppDomain.CurrentDomain.BaseDirectory)。ConfigFile属性不能和ConfigFileExtension属性一起使用。 ConfigFileExtension: 配置文件的扩展名,文件路径相对于应用程序的目录。ConfigFileExtension属性不能和ConfigFile属性一起使用。 Watch: 如果将Watch属性设置为true,就会监视配置文件。当配置文件发生变化的时候,就会重新加载。 注意:如果ConfigFile和ConfigFileExtension都没有设置,则使用应用程序的配置文件App.config(Web.config)。
方法1:直接在项目的AssemblyInfo.cs文件里写 [assembly: log4net.Config.XmlConfigurator(Watch = true)] ,把配置写在appSettings的 <log4net></log4net> 节点里。
方法2:另外写好 *.log4net 的配置文件,然后在appSettings文件里面导入,使用下面的代码:
<appSettings> <add key="log4net.Config" value="log4net.config"/> <add key="log4net.Config.Watch" value="True"/> </appSettings>除了上面的导入配置文件方式,Log4Net的配置文件还可以写入 MyApp.exe.config 或 Web.config 的文件,然后用 System.Configuration API 读取,这种方式不支持监视配置文件改动,我这里就介绍一下,不做过多讲解。
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <configSections> 4 <!-- log4net使用类型System.Configuration.IgnoreSectionHandler. 这是一个内置类,表示将采用另一种读取配置部分的方法 --> 5 <section name="log4net" type="System.Configuration.IgnoreSectionHandler" /> 6 </configSections> 7 <log4net> 8 <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" > 9 <layout type="log4net.Layout.PatternLayout"> 10 <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" /> 11 </layout> 12 </appender> 13 <root> 14 <level value="INFO" /> 15 <appender-ref ref="ConsoleAppender" /> 16 </root> 17 </log4net> 18 </configuration>配置文件样例MyApp.exe.config or Web.config1 [assembly: log4net.Config.XmlConfigurator(Watch = true)] //监视默认的配置文件,App.exe.config在项目的AssemblyInfo.cs文件里配置读取日志系统通常会用在分布式多线程的应用程序上,常常是不同的线程处理不同的客户端,每个线程都使用单独的日志记录器,这种方式会大大增加日志记录器的系统开销,Log4net 支持不同类型的上下文日志记录和不同范围的上下文,对不同线程上的日志使用同一个记录器并对每个线程进行唯一标记,这大大减少系统的开销。
Log4Net的数据上下文有4中类型:全局(log4net.GlobalContext)、线程(log4net.ThreadContext)、逻辑线程(log4net.LogicalThreadContext)和事件(log4net.Core.LoggingEvent )。他们都是静态类的形式存在于我们的程序中,在日志事件中所有上下文的值被组合在一起,在较低范围的值会覆盖较高范围。
10 { 11 public string UserName { get; set; } 12 public string Password { get; set; } 13 public string Nikename { get; set; } 14 public int Outtime { get; set; } //冻结标识 15 public decimal Balance { get; set; } //账户余额 16 //Log4Net日志打印对象的时候会自动调用 17 public override string ToString() 18 { 19 return string.Format("UserName:{0},Password:{1},Nikename:{2},Balance:{3}", UserName, Password, Nikename, Balance); 20 } 21 } 类UserInfo1 <log4net> 2 <appender name="Console" type="log4net.Appender.ConsoleAppender"> 3 <layout type="log4net.Layout.PatternLayout"> 4 <conversionPattern value="%5level [%thread] (%file:%line)【%property{user}】 - %message%newline" /> 5 </layout> 6 </appender> 7 <root> 8 <level value="DEBUG" /> 9 <appender-ref ref="Console" /> 10 </root> 11 </log4net>配置文件Log4NetContexts.log4net1 using log4net; 2 using log4net.Config; 3 using log4net.Core; 4 using System; 5 using System.Collections.Generic; 6 using System.Linq; 7 using System.Text; 8 using System.Threading; 9 using System.Threading.Tasks; 11 namespace Demo13_Log4Net.Log4NetContexts 12 { 13 public class Log4NetContextsMain 14 { 15 private static ILog _log = LogManager.GetLogger(typeof(Log4NetContextsMain)); 16 public static void Test1() 17 { 18 var xmlFile = AppDomain.CurrentDomain.BaseDirectory + @"Log4NetContexts\Log4NetContexts.log4net"; 19 XmlConfigurator.Configure(new System.IO.FileInfo(xmlFile)); 21 var userInfo1 = new UserInfo() { UserName = "admin1", Password = "88888888", Nikename = "BigBox777", Balance = 100000m }; 22 var userInfo2 = new UserInfo() { UserName = "admin2", Password = "88888888", Nikename = "BigBox888", Balance = 0m }; 23 var userInfo3 = new UserInfo() { UserName = "admin3", Password = "88888888", Nikename = "BigBox999", Balance = 1m }; 24 GlobalContext.Properties["user"]=userInfo1; 25 _log.Info($"程序开始···"); 26 for (int i = 0; i < 2; i++) 27 { 28 Thread thread = new Thread(() => 29 { 30 ThreadContext.Properties["user"] = userInfo2; 31 _log.Info($"Thread开始···"); 32 for (int j = 0; j < 2; j++) 33 { 34 Task task = new Task(() => { 35 LogicalThreadContext.Properties["user"] = userInfo3; 36 _log.Info($"Task开始···"); 37 Thread.Sleep(1000); 38 _log.Info($"Task结束···"); 39 }); 40 task.Start(); 41 } 42 _log.Info($"Thread结束···"); 43 }); 44 thread.Start(); 45 } 46 _log.Info($"程序结束···"); 47 } 48 } 案例代码Log4NetContextsMainLog4Net内置了很多附加器,也可以手动配置将日志存储到各种不同的数据库中,下面我们主要来介绍一下:
1 <appender name="AspNetTraceAppender" type="log4net.Appender.AspNetTraceAppender" > 2 <layout type="log4net.Layout.PatternLayout"> 3 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 4 </layout> 5 </appender>配置AspNetTraceAppender,低于WARN级写入System.Web.TraceContext.Write方法,是WARN或更高写入 System.Web.TraceContext.Warn方法1 <appender name="BufferingForwardingAppender" type="log4net.Appender.BufferingForwardingAppender" > 2 <bufferSize value="100"/> 3 <appender-ref ref="ConsoleAppender" /> 4 </appender>配置BufferingForwardingAppender以100条消息为单位传递到ConsoleAppender,不够100条不传递1 <appender name="BufferingForwardingAppender" type="log4net.Appender.BufferingForwardingAppender" > 2 <bufferSize value="512" /> 3 <lossy value="true" /> 4 <evaluator type="log4net.Core.LevelEvaluator"> 5 <threshold value="WARN"/> 6 </evaluator> 7 <appender-ref ref="ConsoleAppender" /> 8 </appender>配置BufferingForwardingAppender,LevelEvaluator阈值WARN表示只记录级别为WARN或更高级别的消息,缓存512条,未发送的消息将被丢弃1 <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> 2 <mapping> 3 <level value="ERROR" /> 4 <foreColor value="White" /> 5 <backColor value="Red, HighIntensity" /> 6 </mapping> 7 <layout type="log4net.Layout.PatternLayout"> 8 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 9 </layout> 10 </appender>配置ColoredConsoleAppender将消息记录到控制台1 <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> 2 <mapping> 3 <level value="ERROR" /> 4 <foreColor value="White" /> 5 <backColor value="Red, HighIntensity" /> 6 </mapping> 7 <mapping> 8 <level value="DEBUG" /> 9 <backColor value="Green" /> 10 </mapping> 11 <layout type="log4net.Layout.PatternLayout"> 12 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 13 </layout> 14 </appender>配置ColoredConsoleAppender显示如何为多个级别着色1 <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> 2 <layout type="log4net.Layout.PatternLayout"> 3 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 4 </layout> 5 </appender>配置ConsoleAppender将消息记录到控制台1 <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> 2 <target value="Console.Error" /> 3 <layout type="log4net.Layout.PatternLayout"> 4 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 5 </layout> 6 </appender>配置ConsoleAppender如何将日志消息定向到控制台错误流1 System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
解决问题log4net:ERROR Could not create Appender [ColoredConsoleAppender] of type [log4net.Appender.ColoredCo1 <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" > 2 <layout type="log4net.Layout.PatternLayout"> 3 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 4 </layout> 5 </appender>配置EventLogAppender使用AppDomain.FriendlyName的事件源记录到本地计算机上的应用程序事件日志1 <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" > 2 <applicationName value="MyApp" /> 3 <layout type="log4net.Layout.PatternLayout"> 4 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 5 </layout> 6 </appender>配置EventLogAppender使用特定事件Source1 <appender name="FileAppender" type="log4net.Appender.FileAppender"> 2 <file value="log-file.txt" /> 3 <appendToFile value="true" /> 4 <layout type="log4net.Layout.PatternLayout"> 5 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 6 </layout> 7 </appender>配置FileAppender将消息写入文件,文件名log-file.txt,该文件将被附加而不是覆盖1 <appender name="FileAppender" type="log4net.Appender.FileAppender"> 2 <file value="${TMP}\log-file.txt" /> 3 <appendToFile value="true" /> 4 <encoding value="unicodeFFFE" /> 5 <layout type="log4net.Layout.PatternLayout"> 6 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 7 </layout> 8 </appender>配置FileAppender使用环境变量TMP配置要写入的文件名,还指定了用于写入文件的编码1 <appender name="FileAppender" type="log4net.Appender.FileAppender"> 2 <file value="${TMP}\log-file.txt" /> 3 <appendToFile value="true" /> 4 <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> 5 <layout type="log4net.Layout.PatternLayout"> 6 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 7 </layout> 8 </appender>配置FileAppender使用允许多个进程写入同一个文件的最小锁定模型1 <appender name="FileAppender" type="log4net.Appender.FileAppender"> 2 <file value="${TMP}\log-file.txt" /> 3 <appendToFile value="true" /> 4 <lockingModel type="log4net.Appender.FileAppender+InterProcessLock" /> 5 <layout type="log4net.Layout.PatternLayout"> 6 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 7 </layout> 8 </appender>配置FileAppender附加程序以使用“进程间”锁定模型1 <appender name="ForwardingAppender" type="log4net.Appender.ForwardingAppender" > 2 <threshold value="WARN"/> 3 <appender-ref ref="ConsoleAppender" /> 4 </appender>配置ForwardingAppender,案例ConsoleAppender使用WARN阈值装饰,意思是无论其级别如何ConsoleAppender的被记录,但指向ForwardingAppender的只在其级别为WARN或更高时才会传递给ConsoleAppender1 <appender name="ManagedColoredConsoleAppender" type="log4net.Appender.ManagedColoredConsoleAppender"> 2 <mapping> 3 <level value="ERROR" /> 4 <foreColor value="White" /> 5 <backColor value="Red" /> 6 </mapping> 7 <layout type="log4net.Layout.PatternLayout"> 8 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 9 </layout> 10 </appender>配置ManagedColoredConsoleAppender将消息记录到控制台,示例显示如何突出显示错误消息1 <appender name="ManagedColoredConsoleAppender" type="log4net.Appender.ManagedColoredConsoleAppender"> 2 <mapping> 3 <level value="ERROR" /> 4 <foreColor value="DarkRed" /> 5 </mapping> 6 <mapping> 7 <level value="WARN" /> 8 <foreColor value="Yellow" /> 9 </mapping> 10 <mapping> 11 <level value="INFO" /> 12 <foreColor value="White" /> 13 </mapping> 14 <mapping> 15 <level value="DEBUG" /> 16 <foreColor value="Blue" /> 17 </mapping> 19 <layout type="log4net.Layout.PatternLayout"> 20 <conversionPattern value="%date %-5level %-20.20logger: %message%newline"/> 21 </layout> 22 </appender>配置ManagedColoredConsoleAppender显示如何为多个级别着色1 <appender name="NetSendAppender" type="log4net.Appender.NetSendAppender"> 2 <threshold value="ERROR" /> 3 <server value="SQUARE" /> 4 <recipient value="nicko" /> 5 <layout type="log4net.Layout.PatternLayout"> 6 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 7 </layout> 8 </appender>配置NetSendAppender将消息传递到特定用户的屏幕,指定了级别错误的阈值,示例将消息传递给机器SQUARE上的用户nicko1 <appender name="OutputDebugStringAppender" type="log4net.Appender.OutputDebugStringAppender" > 2 <layout type="log4net.Layout.PatternLayout"> 3 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 4 </layout> 5 </appender>配置OutputDebugStringAppender将日志消息写入OutputDebugString API1 <appender name="RemotingAppender" type="log4net.Appender.RemotingAppender" > 2 <sink value="tcp://localhost:8085/LoggingSink" /> 3 <lossy value="false" /> 4 <bufferSize value="95" /> 5 <onlyFixPartialEventData value="true" /> 6 </appender>配置RemotingAppender将日志事件传递到指定的Sink,示例中Sink为tcp://localhost:8085/LoggingSink,缓存以95个事件块的形式传递,OnlyFixPartialEventData允许附加生成速度非常慢的日志事件属性(如调位置信息)1 <appender name="RemotingAppender" type="log4net.Appender.RemotingAppender" > 2 <sink value="tcp://localhost:8085/LoggingSink" /> 3 <lossy value="true" /> 4 <bufferSize value="200" /> 5 <onlyFixPartialEventData value="true" /> 6 <evaluator type="log4net.Core.LevelEvaluator"> 7 <threshold value="ERROR"/> 8 </evaluator> 9 </appender>配置RemotingAppender仅在记录级别为ERROR或更高级别的事件时才传递事件,传递200个缓存的事件,未传递的将被丢弃1 <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> 2 <file value="log.txt" /> 3 <appendToFile value="true" /> 4 <rollingStyle value="Size" /> 5 <maxSizeRollBackups value="10" /> 6 <maximumFileSize value="100KB" /> 7 <staticLogFileName value="true" /> 8 <layout type="log4net.Layout.PatternLayout"> 9 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 10 </layout> 11 </appender>配置RollingFileAppender以写入文件log.txt,StaticLogFileName指定文件名,RollingStyle滚动类型,MaxSizeRollBackups最多将保留数,MaximumFileSize文件大小1 <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> 2 <file value="logfile" /> 3 <appendToFile value="true" /> 4 <rollingStyle value="Date" /> 5 <datePattern value="yyyyMMdd-HHmm" /> 6 <layout type="log4net.Layout.PatternLayout"> 7 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 8 </layout> 9 </appender>配置RollingFileAppender日期期间滚动日志文件,示例每分钟滚动一次,DatePattern更改滚动周期,“yyyyMMdd”的日期模式将每天滚动1 <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> 2 <file value="logfile" /> 3 <appendToFile value="true" /> 4 <rollingStyle value="Composite" /> 5 <datePattern value="yyyyMMdd" /> 6 <maxSizeRollBackups value="10" /> 7 <maximumFileSize value="1MB" /> 8 <layout type="log4net.Layout.PatternLayout"> 9 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 10 </layout> 11 </appender>配置RollingFileAppender只保留周期内滚动日志文件最后10MB的大小1 <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> 2 <file value="logfile.txt" /> 3 <appendToFile value="false" /> 4 <rollingStyle value="Size" /> 5 <maxSizeRollBackups value="-1" /> 6 <maximumFileSize value="50GB" /> 7 <layout type="log4net.Layout.PatternLayout"> 8 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 9 </layout> 10 </appender>配置RollingFileAppender每次程序执行时滚动一次日志文件,appendToFile为false不覆盖现有文件,maxSizeRollBackups为-1不限备份文件数量,文件大小为50GB,单次运行期间超过限制会滚动1 <log4net> 2 <appender name="Console" type="log4net.Appender.ConsoleAppender"> 3 <layout type="log4net.Layout.PatternLayout"> 4 <conversionPattern value="%date{yyyy年MMM月dd日 HH:mm:ss,fff}%5level [%thread] (%file:%line)【%property{user}】 - %message%newline" /> 5 </layout> 6 </appender> 8 <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender"> 9 <authentication value="Basic" /> 10 <to value="wangmin915@126.com" /> 11 <!--接受邮件的邮箱--> 12 <from value="wongmin2015@163.com" /> 13 <!--发送邮件的邮箱--> 14 <username value="wongmin2015@163.com" /> 15 <!--发送邮件的邮箱--> 16 <password value="aiwoma" /> 17 <!--为客户端授权码--> 18 <smtpHost value="smtp.163.com" /> 19 <!--服务器地址--> 20 <subject value="test logging message" /> 21 <!--日志消息--> 22 <bufferSize value="200" /> 23 <lossy value="true" /> 24 <evaluator type="log4net.Core.LevelEvaluator"> 25 <threshold value="WARN"/> 26 </evaluator> 27 <layout type="log4net.Layout.PatternLayout"> 28 <conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" /> 29 </layout> 30 </appender> 32 <root> 33 <level value="ALL" /> 34 <appender-ref ref="SmtpAppender" /> 35 <appender-ref ref="Console" /> 36 </root> 37 </log4net>配置SmtpAppender电子邮件1 <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender"> 2 <to value="to@domain.com" /> 3 <from value="from@domain.com" /> 4 <subject value="test logging message" /> 5 <smtpHost value="SMTPServer.domain.com" /> 6 <bufferSize value="512" /> 7 <lossy value="true" /> 8 <evaluator type="log4net.Core.LevelEvaluator"> 9 <threshold value="WARN"/> 10 </evaluator> 11 <layout type="log4net.Layout.PatternLayout"> 12 <conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" /> 13 </layout> 14 </appender>配置SmtpAppender通过SMTP电子邮件传递日志事件,To、From、Subject和SmtpHost 是必需参数,LevelEvaluator阈值WARN将为每个WARN或更高的消息发送邮件,邮件将包含512个缓存消息,未发送的消息将被丢弃1 <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender"> 2 <to value="to@domain.com" /> 3 <from value="from@domain.com" /> 4 <subject value="test logging message" /> 5 <smtpHost value="SMTPServer.domain.com" /> 6 <bufferSize value="512" /> 7 <lossy value="false" /> 8 <layout type="log4net.Layout.PatternLayout"> 9 <conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" /> 10 </layout> 11 </appender>配置SmtpAppender传递电子邮件中的所有消息,每封电子邮件有 512 ( BufferSize ) 消息1 <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender,log4net"> 2 <to value="to@domain.com" /> 3 <from value="from@domain.com" /> 4 <subject value="test logging message" /> 5 <smtpHost value="SMTPServer.domain.com" /> 6 <bufferSize value="512" /> 7 <lossy value="false" /> 8 <evaluator type="log4net.Core.LevelEvaluator,log4net"> 9 <threshold value="WARN" /> 10 </evaluator> 11 <layout type="log4net.Layout.PatternLayout,log4net"> 12 <conversionPattern value="%property{log4net:HostName} :: %level :: %message %newlineLogger: %logger%newlineThread: %thread%newlineDate: %date%newlineNDC: %property{NDC}%newline%newline" /> 13 </layout> 14 </appender>配置SmtpAppender显示了邮件消息的更详细的格式布局1 <appender name="SmtpPickupDirAppender" type="log4net.Appender.SmtpPickupDirAppender"> 2 <to value="to@domain.com" /> 3 <from value="from@domain.com" /> 4 <subject value="test logging message" /> 5 <pickupDir value="C:\SmtpPickup" /> 6 <bufferSize value="512" /> 7 <lossy value="true" /> 8 <evaluator type="log4net.Core.LevelEvaluator"> 9 <threshold value="WARN"/> 10 </evaluator> 11 <layout type="log4net.Layout.PatternLayout"> 12 <conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" /> 13 </layout> 14 </appender>配置SmtpPickupDirAppender通过SMTP电子邮件传递日志,To、From、Subject和PickupDir是必需参数,示例显示如何仅交付重要事件1 <appender name="TraceAppender" type="log4net.Appender.TraceAppender"> 2 <layout type="log4net.Layout.PatternLayout"> 3 <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 4 </layout> 5 </appender>配置TraceAppender将消息记录到System.Diagnostics.Trace系统1 <appender name="UdpAppender" type="log4net.Appender.UdpAppender"> 2 <localPort value="8080" /> 3 <remoteAddress value="224.0.0.1" /> 4 <remotePort value="8080" /> 5 <layout type="log4net.Layout.PatternLayout, log4net"> 6 <conversionPattern value="%-5level %logger [%property{NDC}] - %message%newline" /> 7 </layout> 8 </appender>配置UdpAppender将事件发送到指定RemotePort上的RemoteAddress1 <layout type="log4net.Layout.DynamicPatternLayout"> 2 <param name="Header" value="%newline**** Trace Opened Local: %date{yyyy-MM-dd HH:mm:ss.fff} UTC: %utcdate{yyyy-MM-dd HH:mm:ss.fff} ****%newline"/> 3 <param name="Footer" value="**** Trace Closed %date{yyyy-MM-dd HH:mm:ss.fff} ****%newline"/> 4 </layout>配置DynamicPatternLayout动态图案布局,与不会在每次调用时重新评估的静态PatternLayout相比,DynamicPatternLayout确实会在每次调用时重新评估模式。例如,它允许在页眉和/或页脚中包含当前的DateTime,而静态PatternLayout不可能经常我们不仅希望在附加器里自定义输出目标,还希望自定义输出格式,这需要使用Layout与附加程序关联来实现,附加程序复制将格式化的输出发送到目的地,Layout负责格式化记录日志。常用的PatternLayout就是标准log4net发行版的一种布局,看下面表格
<appender name="Console" type="log4net.Appender.ConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%5level [%thread] (%file:%line)【%property{user}】 - %message%newline" /> </layout> </appender>这是一个PatternLayout布局的案例, %5level [%thread] (%file:%line)【%property{user}】 - %message%newline 这是一种混合转换输出模式,由普通文本文字和表达式组成,表达式都以百分号 (%) 开头,后跟可选的格式修饰符和转换模式名称。正常情况下按转换模式输出全内容就可以了,有的特殊情况需要用歌声修饰符限定输出内容的长度等格式。请注意,文本和转换说明符之间没有明确的分隔符,模式解析器在读取转换字符时知道何时到达转换说明符的末尾。
用于在 %aspnet-cache 的情况下输出所有缓存项,或在用作%aspnet-cache{key}时仅输出一个命名项
此模式不适用于 Compact Framework 或 Client Profile 程序集。
用于在 %aspnet-context 的情况下输出所有上下文项或在用作%aspnet-context{key}时仅输出一个命名项
此模式不适用于 Compact Framework 或 Client Profile 程序集。
用于在 %aspnet-request 的情况下输出所有请求参数,如果用作%aspnet-request{key} 则只输出一个命名参数
此模式不适用于 Compact Framework 或 Client Profile 程序集。
用于在 %aspnet-session 的情况下输出所有会话项,如果用作%aspnet-session{key} ,则仅输出一个命名项
此模式不适用于 Compact Framework 或 Client Profile 程序集。
用于在本地时区输出日志记录事件的日期。要以通用时间输出日期,请使用%utcdate模式。日期转换说明符后面可以跟括在大括号之间的日期格式说明符。例如,%date{HH:mm:ss,fff}或 %date{dd MMM yyyy HH:mm:ss,fff}。如果没有给出日期格式说明符,则假定为 ISO8601 格式(Iso8601DateFormatter)。
日期格式说明符采用与ToString(string) 的时间模式字符串相同的语法。
为了获得更好的结果,建议使用 log4net 日期格式化程序。这些可以使用字符串“ABSOLUTE”、“DATE”和“ISO8601”之一来指定 AbsoluteTimeDateFormatter、 DateTimeDateFormatter和分别 指定Iso8601DateFormatter。例如, %date{ISO8601}或%date{ABSOLUTE}。
这些专用日期格式化程序的性能明显优于ToString(string)。
用于输出随日志消息传入的异常。
如果异常对象存储在日志记录事件中,它将被呈现到带有尾随换行符的模式输出中。如果没有异常,则不会输出任何内容,也不会添加尾随换行符。通常在异常之前放置一个换行符并将异常作为模式中的最后一个数据。
用于输出发出记录请求的文件名。
警告生成呼叫者位置信息非常慢。除非执行速度不是问题,否则应避免使用它。
请参阅下面有关呼叫者位置信息可用性的说明。
用于输出当前活动用户的用户名(Principal.Identity.Name)。
警告生成来电者信息非常慢。除非执行速度不是问题,否则应避免使用它。
用于输出产生日志事件的调用者的位置信息。
位置信息取决于 CLI 实现,但通常由调用方法的完全限定名称后跟调用者源文件名和括号之间的行号组成。
位置信息可能非常有用。但是,它的生成速度极慢。除非执行速度不是问题,否则应避免使用它。
请参阅下面有关呼叫者位置信息可用性的说明。
用于输出日志事件的级别。
用于输出发出记录请求的行号。
警告生成呼叫者位置信息非常慢。除非执行速度不是问题,否则应避免使用它。
请参阅下面有关呼叫者位置信息可用性的说明。
用于输出记录事件的记录器。记录器转换说明符可以选择后跟 精度说明符,即括号中的十进制常量。
如果给出了精度说明符,则只会打印记录器名称最右边的相应数量的组件。默认情况下,记录器名称被完整打印。
例如,对于记录器名称“abc”,模式 %logger{2}将输出“bc”。
用于输出与日志事件关联的应用程序提供的消息。
MDC(ThreadContext.Properties 的旧名称)现在是组合事件属性的一部分。支持此模式是为了兼容性,但等效于property。
用于输出发出日志请求的方法名称。
警告生成呼叫者位置信息非常慢。除非执行速度不是问题,否则应避免使用它。
请参阅下面有关呼叫者位置信息可用性的说明。
输出平台相关的行分隔符或字符。
此转换模式提供与使用不可移植行分隔符字符串(例如“\n”或“\r\n”)相同的性能。因此,它是指定行分隔符的首选方式。
用于输出与生成日志事件的线程关联的 NDC(嵌套诊断上下文)。
用于输出事件特定属性。查找的键必须在大括号内指定,并直接跟在模式说明符之后,例如%property{user}将包括由字符串“user”作为键的属性中的值。必须单独指定要包含在日志中的每个属性值。记录器或附加器将属性添加到事件中。默认情况下,log4net:HostName属性设置为最初记录事件的机器的名称。
如果没有指定键,例如%property ,那么所有键和它们的值都打印在一个逗号分隔的列表中。
事件的属性是从许多不同的上下文中组合而成的。这些按搜索顺序在下面列出。
- 事件属性
- 该事件具有可以设置的属性。这些属性仅特定于此事件。
- 线程属性
- 在当前线程上设置 的属性。这些属性由该线程上记录的所有事件共享。
- 全局属性
- 全局设置的属性。这些属性由 AppDomain 中的所有线程共享。
用于输出日志事件的堆栈跟踪堆栈跟踪级别说明符可以用大括号括起来。例如,%stacktrace{level}。如果没有给出堆栈跟踪级别说明符,则假定为 1
输出使用格式:type3.MethodCall3 > type2.MethodCall2 > type1.MethodCall1
此模式不适用于 Compact Framework 程序集。
用于输出日志事件的堆栈跟踪堆栈跟踪级别说明符可以用大括号括起来。例如,%stacktracedetail{level}。如果没有给出堆栈跟踪级别说明符,则假定为 1
输出使用格式:type3.MethodCall3(type param,...) > type2.MethodCall2(type param,...) > type1.MethodCall1(type param,...)
此模式不适用于 Compact Framework 程序集。
用于输出从应用程序启动到创建日志事件所经过的毫秒数。
用于输出生成日志事件的线程的名称。如果没有名称可用,则使用线程号。
用于输出发出日志请求的调用者的完全限定类型名称。此转换说明符可以选择后跟精度说明符,即括号中的十进制常量。
如果给出了精度说明符,则只打印类名最右边的相应数量的组件。默认情况下,类名以完全限定的形式输出。
例如,对于类名“log4net.Layout.PatternLayout”,模式%type{1}将输出“PatternLayout”。
警告生成调用者类信息很慢。因此,除非执行速度不是问题,否则应避免使用它。
请参阅下面有关呼叫者位置信息可用性的说明。
用于输出当前活动用户的 WindowsIdentity。
警告生成调用方 WindowsIdentity 信息非常慢。除非执行速度不是问题,否则应避免使用它。
用于以通用时间输出日志记录事件的日期。日期转换说明符后面可以跟括在大括号之间的日期格式说明符。例如,%utcdate{HH:mm:ss,fff}或 %utcdate{dd MMM yyyy HH:mm:ss,fff}。如果没有给出日期格式说明符,则假定为 ISO8601 格式(Iso8601DateFormatter)。
日期格式说明符采用与ToString(string) 的时间模式字符串相同的语法。
为了获得更好的结果,建议使用 log4net 日期格式化程序。这些可以使用字符串“ABSOLUTE”、“DATE”和“ISO8601”之一来指定 AbsoluteTimeDateFormatter、 DateTimeDateFormatter和分别 指定Iso8601DateFormatter。例如, %utcdate{ISO8601}或%utcdate{ABSOLUTE}。
这些专用日期格式化程序的性能明显优于ToString(string)。
转换模式名称表 转换模式名称 影响 相当于appdomain appdomain 用于输出生成日志事件的 AppDomain 的友好名称。 aspnet-cache aspnet-context aspnet-request aspnet-session 相当于记录器 相当于类型 class 相当于类型 相当于迄今为止 exception 相当于文件 identity 相当于位置 相当于线 location level logger 相当于消息 相当于方法 message method 相当于换行符 newline 相当于水平,小写 相当于财产,大写 properties 相当于财产 property 相当于时间戳 stacktrace stacktracedetail 相当于线程 timestamp thread 等同于身份 username utcdate 相当于用户名 相当于ndc 相当于mdc 序列 %% 输出一个百分号。