Log4j2 快速开始
1.配置
默认 Log4j2可以将自己配置为记录错误及更高级别日志,并将消息记录到控制台中。
【显示配置】1.检测log4j.configurationFile系统属性,如果属性存在,就从指定文件加载。
2.在类路径上寻找名为log4j2-test.json或log4j2-test.jsn,如果存在,就加载。
3.在类路径上寻找名为log4j2-test.xml
4.在类路径上寻找log4j2.json或log4j2.jsn
5.在类路径上寻找log4j2.xml
优先使用-test理由,执行单元测试,这两个文件都在类路径上。
2.级别
OFF
FATAL
ERROR
WARN
INFO
DEBUG
TRACE
ALL
【定义自己的级别】
public final class CustomLevels{
public static final Level CONFIG = Level.forName("CONFIG",350);
}
3.记录器或分类器
LogManager.getLogger 用完全限定类名 分类,不同类名的Logger可以设置不同级别。
4.日志存储器
……………………………………………………………………………………………………
【创建Log4j2配置文件】Log4j和Log42不兼容(XMLSchema、不接受properties配置)
1.适合测试环境的log4j2-test.xml
<!--默认status是OFF 没有显示配置直接写代码-->
<configuration status="WARN">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</appenders>
<loggers>
<!--root Logger Level默认是Error-->
<root level="debug">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
Log4j本身是通过StatusLogger特殊Logger完成记录自己出问题消息,应对创建的Socket Appender无法连接目标服务器诸如这样的情况。
2.开发环境的log4j2.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration status="WARN"> <appenders> <Console name="Console" target="SYSTEM_OUT"> <!--%logger用于输出类、方法、文件和日志消息 所在行号--> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <!--将日志输出到Tomcat logs 目录中--> <RollingFile name="WroxFileAppender" fileName="../logs/application.log" filePattern="../logs/application-%d{MM-dd-yyyy}-%i.log"> <PatternLayout> <!--%X{id}这个叫鱼标签,是ThreadContext中的属性--> <pattern>%d{HH:mm:ss.SSS} [%t] %X{id} %X{username} %-5level %c{36} %l: %msg%n</pattern> </PatternLayout> <Policies> <!--每10MB作为管辖 滚动条件--> <SizeBasedTriggeringPolicy size="10 MB" /> </Policies> <!--保持不超过4个备份日志文件--> <DefaultRolloverStrategy min="1" max="4" /> </RollingFile> </appenders> <loggers> <root level="warn"> <appender-ref ref="Console" /> </root> <!--com.wrox所有Logger 不可添加 additivity=false --> <logger name="com.wrox" level="info" additivity="false"> <appender-ref ref="WroxFileAppender" /> <!--不继承Console Appender--> <appender-ref ref="Console"> <!--在com.wrox层次的Logger只可以在包含了名为WROX_CONSOLES事件上将日志记录到Console--> <MarkerFilter marker="WROX_CONSOLE" onMatch="NEUTRAL" onMismatch="DENY" /> </appender-ref> </logger> <logger name="org.apache" level="info"> <appender-ref ref="WroxFileAppender" /> </logger> </loggers> </configuration>
3.在任何日志框架中都应该【为请求使用鱼标签】,这样就可以将属于相同请求中的日志消息进行分组。
ThreadContext存储当前线程属性,同一线程记录所有事件,如果许多并发web请求在执行,为请求分配唯一的鱼标签可以帮助我们识别特定请求的所有相关信息。
【鱼标签】是唯一的,如UUID。ThreadContext可以存储任何有用于区别日志事件的信息 比如用户名。
//过滤器支持多个派发器,可以单个请求执行多次 @WebFilter(urlPatterns = "/*", dispatcherTypes = { DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.FORWARD, DispatcherType.INCLUDE }) public class LoggingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { boolean clear = false; //%X{id} %X{username} if(!ThreadContext.containsKey("id")) { clear = true; ThreadContext.put("id", UUID.randomUUID().toString()); HttpSession session = ((HttpServletRequest)request).getSession(false); if(session != null) ThreadContext.put("username", (String)session.getAttribute("username")); } try { chain.doFilter(request, response); } finally { if(clear) ThreadContext.clearAll(); } } }
4.在java代码使用Logger
@WebServlet(name = "actionServlet", urlPatterns = "/files") public class ActionServlet extends HttpServlet { private static final Logger log = LogManager.getLogger(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request.getParameter("action"); if(action != null) { log.info("Received request with action {}.", action); String contents = null; switch(action) { case "readFoo": contents = this.readFile("../foo.bar", true); break; case "readLicense": contents = this.readFile("../LICENSE", false); break; default: contents = "Bad action " + action + " specified."; log.warn("Action {} not supported.", action); } if(contents != null) response.getWriter().write(contents); } else { log.error("No action specified."); response.getWriter().write("No action specified."); } } protected String readFile(String fileName, boolean deleteWhenDone) { log.entry(fileName, deleteWhenDone); try { byte[] data = Files.readAllBytes(new File(fileName).toPath()); log.info("Successfully read file {}.", fileName); return log.exit(new String(data)); } catch(IOException e) { log.error(MarkerManager.getMarker("WROX_CONSOLE"), "Failed to read file {}.", fileName, e); return null; } } }
5.在表现层记录日志(一般没有这个需求,表现层不应该有业务逻辑)
<%@ taglib prefix="log" uri="http://logging.apache.org/log4j/tld/log" %>
<log:entry />
<!DOCTYPE html>
<html>
<head>
<title>Test Logging</title>
</head>
<body>
<log:info message="JSP body displaying." />
Messages have been logged.
<log:info>JSP body complete.</log:info>
</body>
</html>
<log:exit />