log4j2中文手册.doc_第1页
log4j2中文手册.doc_第2页
log4j2中文手册.doc_第3页
log4j2中文手册.doc_第4页
log4j2中文手册.doc_第5页
已阅读5页,还剩65页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Log4j2使用手册一Log4j2介绍Log4j1.x 被广泛应用于应用程序,但是近年发展明显放缓,因为要维持较老java版本的使用,使得log4j1.x 的发展更困难。而作为其代替品, slf4j/logback 做出了许多必要改进,为什么还需要log4j2? 主要有以下几个原因 :(1) Log4j2被设计用作审计日志框架, log4j 和logback 在重载配置时,都会丢失日志时间,而log4j2不会。Logback中appenders中的异常对于应用来说是不可见的,log4j2可以配置异常向应用渗透。(2) Log4j2 包含基于 LMAX Disruptor library 的下一代无锁 Asynchronous Loggers ,在多线程环境下, Asynchronous Loggers 相比slf4j / logback 提高了10倍以上的吞吐量,并且有着更低的延时。(3) Log4j2的插件机制,使得在不需要修改框架的情况下,通过添加 Appenders,Filters,Layouts,Lookups 轻松扩展框架。(4) 简单的插件配置,无需指定具体类名即可在configuration 中配置插件。(5) 支持自定义日志级别,可以在代码或者 configuration 中自定义日志级别。(6) 支持lambda表达式,java8的应用可以在请求日志级别启用时使用 lambda表达式懒构建一个日志消息,不需要显示的日志级别检查,使得代码更简洁。(7) 支持消息对象,消息允许支持有趣和复杂的结构,传递到日志记录系统,并且可以高效的操作。用户可以自由创建消息类型和 编写Layouts, Filters and Lookups 来操作这些消息。(8) Log4j1在Appenders 上支持 Filters。 logback增加了 TurboFilters,允许在日志事件在处理前进行过滤。Log4j2可以配置 Filters 在Logger后者Appender 前运行。(9) 许多Logback的Appenders 不接受Layout,并且只能按照固定格式发送日志数据。大部分 log4j2 接收Layout配置,允许日志数据按照任何所需格式传输。(10) Log4j1与logback 的 Layouts 是返回一个String 类型,这可能导致一些编码问题。Log4j2使用了简单的方式:返回一个 byte 数组。这以为着Layouts 可以用在几乎任何appenders ,而不仅仅是 写入OutputStream。(11) Syslog appender 支持 TCP与UDP,以及BSD syslog 和 RFC5424格式。(12) Log4j2 得益于java5的并发支持,将锁的可能降到最低水平。Log4j1 有已知的死锁问题,Logback也需要使用synchronization 来保持在相当高的锁级别。(13) Apache 开源二Log4j2架构1. Log4j2类图应用程序调用Log4j API 时需要向LogManager 传入一个特定的名称来获取一个Logger实例。LogManager 会定位一个合适的 LoggerContext然后从中获取 Logger 。如果 Logger必须新建,那么与之关联的 LoggerConfig 遵守如下规则 : (1)与Logger名称完全相同。(2)父Logger 的名称。(3)Root LoggerConfig 。LoggerConfig 对象是根据 configuration 配置中的Logger 声明创建的。LoggerConfig 又与处理LogEvents 的 LoggerConfig 关联。2. 日志层次logging API 相比于 纯粹的System.out.println 最重要的不同是 : logging API 可以禁用一些log语句输出的同时允许其他一些语句块输出。这种能力建立在开发者按照一定规则将日志分类的基础上。Log4j1.x 的层次关系是通过 Loggers 之间的关系保持的。而 Log4j2.x 是通过 LoggerConfig 对象来维持这种层次关系的。Loggers 与 LoggerConfigs 都是带名称的实体。Logger名称是大小写敏感的,并且符合如下命名层级规则:一个LoggerConfig 的名字是另外一个 LoggerConfig 名字 加上 . 和一些后缀字符。 那么这个 LoggerConfig 是另外的 LoggerConfig 的子类。 类似于 java 的 package 路径。 例如 : 一个 名称为 com.foo的 LoggerConfig 是 一个名称为 com.foo.Bar 的LoggerConfig 的父类。类似的, “java” 是java.util的父类和 java.util.Vector 的祖先类 。 开发人员对这样的命名方案应该很熟悉。Root LoggerConfig 居于 LoggerConfig 分层的顶层。Root LoggerConfig 总是存在于每个 LoggerConfig的层次中 。任何一个与rootLoggerConfig相关联的Logger可以通过如下方式获得:Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);也可以用如下简便方式:Logger logger = LogManager.getRootLogger();其他的 Logger 可以使用 LogManager.getLogger 的静态方法根据传入的名称获得。3. LoggerContextLoggerContext 作为日志系统的锚点(用于根据日志名称定位日志输出信息的Logger),在不同的环境中,一个应用系统中可能存在多个有效的 LoggerContexts,4. Configuration每个 LoggerContext有一个有效的Configuration。 Configuration包括所有的 Appenders,上下文过滤器,LoggerConfigs 与 包含StrSubstitutor的引用信息。在配置重载期间,两个Configuration共存,一旦所有的 Logger重定向到新的Configuration,旧的Configuration将停用和丢弃。5. LoggerLoggers 是调用 LogManager.getLogger 静态方法创建的。Logger 本身不直接执行动作。它只有一个名称,并于一个LoggerConfig相关联。它继承自AbstractLogger ,当 configuration 被修改时,Loggers将关联修改后的 LoggerConfig,从而改变这个 Loggers的行为。获取Loggers:使用相同的名称调用 LogManager.getLogger 方法,总是返回完全相同的Logger对象。例如:Logger x = LogManager.getLogger(wombat);Logger y = LogManager.getLogger(wombat);X和y 指向完全相同的 Logger 对象。Log4j 配置环境通常是在应用程序初始化时完成的。最好的方式是读取配置文件。Log4j很容易通过类名来命名,这可以在每个类初始化的时候完成Logger的初始化,Logger 的名称就等于类的完整路径,这是一个定义Logger的简单有效的方式。当为日志文件输出具有 Logger 名称的日志时,这种命名策略可以很容易看出一个 日志消息的来源。当然这只是一种比较常见的日志命名方式,log4j并没有对此进行限制,开发人员可以按照需求进行命名。因为使用类名命名 Logger是一个习惯用法。一个便利的方法是使用LogManager.getLogger() 来获取类的全路径名称的 Logger。目前为止,使用类名来作为Logger 的名称是最好的方式。6. LoggerConfig当Logger对象在 logging configuration 中被定义时,LoggerConfig对象同时被创建。LoggerConfig包含一组Filters 来过滤传递到 Appenders 的LogEvent。LoggerConfig使用一组Appenders用来处理这些事件。Log LevelsLoggerConfigs 被分配一个日志级别,包括 : TRACE, DEBUG, INFO, WARN, ERROR, FATAL 。 Log4j2 也支持自定义日志级别,另一种获得更多日志粒度的方式是使用 Markers 。Log4j1 与logback 都有日志级别继承的概念。在Log4j2中,因为 Loggers 和LoggerConfigs是2个不同的对象,所以这个概念的实现有所不同。但是因为每个Loggers都关联一个相应的 LoggerConfig, 所以最终效果是相同的。如果一个 root LoggerConfig 没有配置日志级别,将分配一个默认级别。Logger NameAssigned LoggerConfigLoggerConfig LevelLogger LevelrootrootDEBUGDEBUGXrootDEBUGDEBUGX.YrootDEBUGDEBUGX.Y.ZrootExample 1在 Example1 中, 仅配置了root logger 与其日志级别,所有的Loggers 都会引用root LoggerConfig ,并使用其日志级别。Logger NameAssigned LoggerConfigLoggerConfig LevelLevelrootrootDEBUGDEBUGXXERRORERRORX.YX.YINFOINFOX.Y.ZX.Y.ZWARNWARNExample 2在Example2中, 每个Logger 都有其对应的 LoggerConfig和相应的日志级别。Logger NameAssigned LoggerConfigLoggerConfig LevelLevelrootrootDEBUGDEBUGXXERRORERRORX.YXERRORERRORX.Y.ZX.Y.ZWARNWARNExample 3在 Example3 中,Logger root,X和X.Y.Z 都有与名称完全匹配的LoggerConfig配置,而 Logger X.Y 没有与其命名匹配的 LoggerConfig,所以使用拥有最长匹配度的 X 的LoggerConfig。Logger NameAssigned LoggerConfigLoggerConfig LevellevelrootrootDEBUGDEBUGXXERRORERRORX.YXERRORERRORX.Y.ZXERRORERRORExample 4Example 4 中,root与X 各自有一个与名称完全匹配的 LoggerConfig ,而 X.Y与X.Y.Z 没有与名称完全匹配的 LoggerConfig, 所以使用与其名称有最长匹配度的 X 的LoggerConfig。Logger NameAssigned LoggerConfigLoggerConfig LevellevelrootrootDEBUGDEBUGXXERRORERRORX.YX.YINFOINFOX.YZXERRORERRORExample 5Example 5 中 root.X, 与X.Y 有与名字完全匹配的 LoggerConfig, 而 X.YZ 将与X 相匹配而不是 X.Y , 因为路径匹配时按照 . 进行分割和匹配的。 Logger NameAssigned LoggerConfigLoggerConfig LevelLevelrootrootDEBUGDEBUGXXERRORERRORX.YX.YERRORX.Y.ZX.YERRORExample 6Example 6 中, X.Y 与 X.Y.Z 都没有配置相应的日志级别, 所以他们从 Logger X中继承了日志级别 。下面的表格展示了 logEvent(垂直方向) 与 LoggerConfig(水平方向) 的过滤方式:Event LevelLoggerConfig LevelTRACEDEBUGINFOWARNERRORFATALOFFALLYESYESYESYESYESYESNOTRACEYESNONONONONONODEBUGYESYESNONONONONOINFOYESYESYESNONONONOWARNYESYESYESYESNONONOERRORYESYESYESYESYESNONOFATALYESYESYESYESYESYESNOOFFNONONONONONONO7. FilterLog4j2 提供了 Filters, 可以 应用于 控制权传递到 LoggerConfig 之前,控制权传递到LoggerConfig 之后 但是在调用 Appenders 之前,控制权在传递到 LoggerConfig之后,但是在调用一个指定的 Appender 之前。 类似于防火墙的处理方式,每个 Filters可以返回三个结果的其中之一。Accept,DenyNeutral 。Accept 意味着 不会再调用其他Filters了,LogEvent 将被执行。Deny 意味着 立即忽略这个 LogEvent, 并将这个 LogEvent 的控制权交还给它调用者。Neutral 指LogEvent将传递给其他Filters, 如果没有别的Filters了,那么这个LogEvent将被执行。尽管一个 LogEvent 可能被一个Filter接收,但是这个LogEvent仍然没有被日志记录下来,发生这种情况的场景可能是LogEvent被 pre-LoggerConfig Filter 接收了,但是却被 LoggerConfig 拒绝了,或者被所有的 Appenders 拒绝了。8. Appender由logger的不同来决定一个loggingrequest是被禁用还是启用只是log4j2的情景之一。log4j2还允许将loggingrequest中log信息打印到不同的目的地中。在log4j2的世界里,不同的输出位置被称为Appender。目前,Appender可以是console、文件、远程socket服务器、ApacheFlume、JMS以及远程UNIX系统日志守护进程,数据库。 一个Logger可以绑定多个不同的Appender。可以通过调用当前Configuration的addLoggerAppender 方法为Logger增加一个 Appender。如果不存在一个与Logger名称相对应的LoggerConfig,那么相应的LoggerConfig将被创建,并且新增加的Appender将被添加到此新建的LoggerConfig中。然后,所有的Loggers将会被通知更新自己的LoggerConfig引用(PS:一个Logger的LoggerConfig引用是根据名称的匹配长度来决定的,当新的LoggerConfig被创建后,会引发一轮配对洗牌)。某个logger 中被启用的logging request 将被转发到该Logger LoggerConfig相关联的的所有Appenders上,并且还会被转发到LoggerConfig的父级的Appenders上。换句话说,Appenders 将从LoggerConfig的层次结构中获得继承。例如,对LoggerConfigB来说,它的父级为A,A的父级为root。如果在root中定义了一个Appender为console,那么所有启用了的loggingrequest都会在console中打印出来。另外,如果LoggerConfigA定义了一个文件作为Appender,那么使用LoggerConfigA和LoggerConfigB的logger的loggingrequest都会在该文件中打印,并且同时在console中打印。如果想避免这种遗传效应的话,可以在configuration文件中做如下设置:additivity=false这样,就可以关闭Appender的遗传效应了。具体解释如下 :Appender AdditivityThe output of a log statement of LoggerLwill go to all the Appenders in the LoggerConfig associated withLand the ancestors of that LoggerConfig. This is the meaning of the term appender additivity.However, if an ancestor of the LoggerConfig associated with LoggerL, sayP, has the additivity flag set tofalse, thenLs output will be directed to all the appenders inLs LoggerConfig and its ancestors up to and includingPbut not the Appenders in any of the ancestors ofP.Loggers have their additivity flag set totrueby default.上面例子的详细表格解释如下:LoggerNameAddedAppendersAdditivityFlagOutput TargetsCommentrootA1not applicableA1The root logger has no parent so additivity does not apply to it.xA-x1, A-x2trueA1, A-x1, A-x2Appenders of x and root.x.ynonetrueA1, A-x1, A-x2Appenders of x and root. It would not be typical to configure a Logger with no Appenders.x.y.zA-xyz1trueA1, A-x1, A-x2, A-xyz1Appenders in x.y.z, x and root.securityA-secfalseA-secNo appender accumulation since the additivity flag is set tofalse.security.accessnonetrueA-secOnly appenders of security because the additivity flag in security is set tofalse.9. Layout通常,用户不止希望能定义log输出的位置,还希望可以定义输出的格式。这就可以通过将Appender与一个layout相关联来实现。Log4j中的 一个标准定义PatternLayout ,就允许用户使用一种类似C语言printf函数的打印格式,如%r%t%-5p%c-%m%n格式在真实环境下会打印类似如下的信息:176 main INFO org.foo.Bar - Locatednearestgasstation.第一个字段是启动的毫秒数,第二个字段是日志请求的线程号, 第三个字段是日志请求级别,第四个是与日志请求相关联的日志名称, 在“-” 之后的内容就是日志内容。Log4j 有各种不同的 Layouts, 例如 : JSON, XML, HTML, 和Syslog (including the new RFC 5424 version).其他一些 appenders 例如 database connectors 会使用指定的字段替代 特定的文本布局。同样重要的是,要使得log4j的日志消息内容符合用户指定的标准。,例如:在你的工程中,你需要一个 Oranges 类型的日志对象,你就可以创建一个 OrangeMessage, 可以接受Orange实例并且传递到log4j, Orange 对象就会被格式化为一个适当的字节数组。10. StrSubstitutor and StrLookupStrSubstitutor 类与 StrLookup 接口是来自 Apache Commons Lang , 并且被修改为支持 LogEvents 的运算。此外 来自 Apache Commons Configuration的 Interpolator类允许StrSubstitutor 运算来着多个 StrLookups 的变量,它也被修改支持 LogEvents的运算。Log4j2 提供了一种机制,可以使得configuration 引用 来自System Properties, the configuration file, the ThreadContext Map, StructuredData 中的变量。当 configuration 被加载或者 每个LogEvent 运行时, 这个变量将被解析。 如果这个日志组件可以处理这个变量。三Log4j2 APILog4j2 API 提供了应用程序使用的接口,也提供了创建一个日志实现所需的适配器组件,Log4j2 解耦了API 及其 实现之间的关系。这样做的目的是不允许有多个实现 。 一种可能的情况是 一个Log4j2的API对应多个实现,所以在应用中要使用 Log4j2 API 中的类和方法, 而不要使用具体的实现内容(1)Hello World!下面是一个hello world 的例子, 有一个从LogManager中获取的 名称为 HelloWorld 的Logger,接着,这个Logger打印了 Hello, World! 的日志消息。 当然,只有在configured中做了相应的配置, 这些内容才能打印出来。 1. import org.apache.logging.log4j.LogManager;2. import org.apache.logging.log4j.Logger;3. 4. public class HelloWorld 5. private static final Logger logger =LogManager.getLogger(HelloWorld);6. public static void main(String args) 7. (Hello, World!);8. 9. 调用方法 () 的输出会有所不同,主要取决于 configuration 的配置(2) Substituting Parameters日志记录的目的是要提供系统中发生的信息,这就要打印一些对象信息,在 Log4j1.x中, 可以通过这样来打印 :1. if (logger.isDebugEnabled() 2. logger.debug(Logging in user + user.getName() + with birthday + user.getBirthdayCalendar();3. 这样的代码感觉很繁琐,而且会检查2次日志级别,一次是 logger.isDebugEnabled ,另一次是 logger.debug 。在log4j2中更好的实现方式是 :logger.debug(Logging in user with birthday , user.getName(), user.getBirthdayCalendar();代码简洁了很多, 而且日志只有在debug打印的时候才会构建日志内容中的字符串。(3) Formatting Parameters类似于java 的Formatter , Formatter Loggers 可以提供简易的字符串格式化方式 :例如:1. public static Logger logger = LogManager.getFormatterLogger(Foo);2. 3. logger.debug(Logging in user %s with birthday %s, user.getName(), user.getBirthdayCalendar();4. logger.debug(Logging in user %1$s with birthday %2$tm %2$te,%2$tY, user.getName(), user.getBirthdayCalendar();5. logger.debug(Integer.MAX_VALUE = %,d, Integer.MAX_VALUE);6. logger.debug(Long.MAX_VALUE = %,d, Long.MAX_VALUE);要使用格式化日志,必须调用LogManagergetFormatterLogger 的方法。下面展示了例子中的结果内容 :1. 2012-12-12 11:56:19,633 main DEBUG: User John Smith with birthday java.util.GregorianCalendartime=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfoid=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZoneid=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=1995,MONTH=4,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=23,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?2. 2012-12-12 11:56:19,643 main DEBUG: User John Smith with birthday 05 23, 19953. 2012-12-12 11:56:19,643 main DEBUG: Integer.MAX_VALUE = 2,147,483,6474. 2012-12-12 11:56:19,643 main DEBUG: Long.MAX_VALUE = 9,223,372,036,854,775,807(4) Mixing Loggers with Formatter LoggersFormatter loggers 是用来控制细粒度的输出格式的。但是缺点是必须指定正确的类型,例如给 %d 格式化参数传递了 Integer 以外的类型,就会抛错。如果你主要使用 风格的参数, 但是偶尔要精确控制输出格式,可以使用 printf 方法:1. public static Logger logger = LogManager.getLogger(Foo);2. 3. logger.debug(Opening connection to ., someDataSource);4. logger.printf(Level.INFO, Logging in user %1$s with birthday %2$tm %2$te,%2$tY, user.getName(), user.getBirthdayCalendar();(5) Java 8 lambda support for lazy logging在2.4版本以后,Logger 支持了lambda 表达式,在请求日志级别启动的时候,可以懒加载的打印这些信息而不用去显式检查日志是否要打印。例如, 在以前版本中可能这样写 :1. / pre-Java 8 style optimization: explicitly check the log level2. / to make sure the expensiveOperation() method is only called if necessary3. if (logger.isTraceEnabled() 4. logger.trace(Some long-running operation returned , expensiveOperation();5. 在java8 中可以使用 lambda 表达式实现相同的效果,你可以不用显式的检查日志级别了:1. / Java-8 style optimization: no need to explicitly check the log level:2. / the lambda expression is not evaluated if the TRACE level is not enabled3. logger.trace(Some long-running operation returned , () - expensiveOperation();(6) Logger Names大部分日志实现使用为了使得 日志名称与日志配置匹配 使用一个分层的名称方案。在这个方案中Logger 的名称是由 . 分隔的, 非常类似于 java 包名的层次。 例如 : org.apache.logging 是 org.apache.logging.appender 与 org.apache.logging.filter 的父层。大多数情况下,应用命名他们的日志名称 是通过在 LogManager.getLogger 中传入当前类名实现的。因为这个用法太常见,Log4j2在入参为空或者传入为Null 的时候默认是提供当前类的名称。 例如, 下面的例子的 Logger 的名称都是 org.apache.test.MyTest1. package org.apache.test;2. 3. public class MyTest 4. private static final Logger logger =LogManager.getLogger(MyTest.class);5. 1. package org.apache.test;2. 3. public class MyTest 4. private static final Logger logger =LogManager.getLogger(MyTest.class.getName();5. 1. package org.apache.test;2. 3. public class MyTest 4. private static final Logger logger = LogManager.getLogger();5. 1. Flow TracingLogger 类提供了针对跟踪应用执行路径的很有用的方法 。这些方法可以从debug 日志中产生可以单独 过滤的logging events。以下情况鼓励使用这些方法:(1) 在不需要DEBUG的开发中帮助诊断问题(2) 在不需要DEBUG 的生产中帮助诊断问题。(3) 帮助新的开发人员在应用中学习使用。最常用的2个方法是 entry() 与 exit() 。 entry() 一般置于方法的开头,entry() 可以传入0-4 个参数,通常是传入方法变量, entry() 方法的日志级别是 TRACE ,并且使用了一个名为 ENTER 的 Marker。 这也是一个FLOW Markerexit() 放置在方法的结束或者方法的返回前,exit() 可以传入 1个参数或者不传入参数, 通常 void 方法不传入参数, 而返回一个Object的方法使用 exit(Object obj) 。 exit()方法使用 TRACE的日志级别,并且使用了一个名为 EXIT 的Marker 。throwing() 方法 一般在应用抛出一个不太可能处理的异常时使用。类似 RuntimeException 。 这个方法使用了 ERROR 的日志级别。catching() 方法使用在捕获一个异常,但是不会抛出的时候, 这个方法使用了 ERROR的日志级别。,下面的例子展示了这些方法的典型使用:1. package com.test;2. 3. import org.apache.logging.log4j.Logger;4. import org.apache.logging.log4j.LogManager;5. 6. import java.util.Random;7. 8. public class TestService 9. private Logger logger = LogManager.getLogger(TestService.class.getName();10. 11. private String messages = new String 12. Hello, World,13. Goodbye Cruel World,14. You had me at hello15. ;16. private Random rand = new Random(1);17. 18. public String retrieveMessage() 19. logger.entry();20. 21. String testMsg = getMessage(getKey();22. 23. return logger.exit(testMsg);24. 25. 26. public void exampleException() 27. logger.entry();28. try 29. String msg = messagesmessages.length;30. logger.error(An exception should have been thrown);31. catch (Exception ex) 32. logger.catching(ex);33. 34. logger.exit();35. 36. 37. public String getMessage(int key) 38. logger.entry(key);39. 40. String value = messageskey;41. 42. return logger.exit(value);43. 44. 45. private int getKey() 46. logger.entry();47. int key = rand.nextInt(messages.length);48. return logger.exit(key);49. 50. 测试程序的调用 :1. package com.test;2. 3. public class App 4. 5. public static void main( String args ) 6. TestService service = new TestService();7. service.retrieveMessage();8. service.retrieveMessage();9. service.exampleException();10. 11. 日志配置文件 :1. 2. 3. 4. 5. 6. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 2. Markers日志记录框架的主要目的之一是在需要的时候提供一种方法来生成调试和诊断信息。并且可以对这些信息进行过滤,以使不会压垮系统或者需要使用它的人,例如:应用需要打印 入口,出口,和分别执行的SQL语句,并且希望能够分开 查询和 更新语句 :1. import org.apache.logging.log4j.Logger;2. import org.apache.logging.log4j.LogManager;3. import java.util.Map;4. 5. public class MyApp 6. 7. private Logger logger = LogManager.getLogger(MyApp.class.getName();8. private static final Marker SQL_MARKER = MarkerManager.getMarker(SQL);9. private static final Marker UPD

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论