常用方式
Log4j2的等级有FATAL,ERROR,WARN,INFO,DEBUG,TRACE,另外还有全开全关的非登记ALL,OFF。
输出不同级别的log信息
//【1】创建实例。等同与LogManager.getLogger(MyServlet.class);可以logger.getName()来验证。这个名字就是log的category,每个类应该有自己的log实例
private static final Logger log = LogManager.getLogger();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
if(request.getParameter("action") == null)
log.error("No action specified."); //【2】输出error级别的log
else
log.info("action {}",action); //【2】输出info级别的log,采用{}作为参数填入。
}
跟踪方法的输入参数和返回结果
private int test(String s1,String s2){输出结果为:
log.entry(s1,s2);
log.traceEntry("Parameters:{} {}",s1,s2);
log.debug("s1={}, s2={}",s1,s2);
return log.traceExit(4);
}
17:08:39.969 [http-nio-8080-exec-4] [TRACE] LoginServlet test(LoginServlet.java:66) - Enter params(hello, world)
17:08:39.973 [http-nio-8080-exec-4] [TRACE] LoginServlet test(LoginServlet.java:67) - Enter Parameters:hello world
17:08:39.974 [http-nio-8080-exec-4] [DEBUG] LoginServlet test(LoginServlet.java:68) - s1=hello, s2=world
17:08:39.974 [http-nio-8080-exec-4] [TRACE] LoginServlet test(LoginServlet.java:69) - Exit with(4)
退出时关闭
在Log4j2的2.6版本开始引入shutdown(),在2.6中,如果web app卸载时没有进行shutdown(),tomcat会发布内存泄漏风险的告警,如下:六月 28, 2017 11:10:56 上午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads
警告: The web application [customer-support] appears to have started a thread named [Log4j2-TF-3-Scheduled-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
java.lang.Thread.run(Unknown Source)
有两种方式可以解决。
【方式一】收到安全退出,完成资源释放,执行shutdown()
【方式二】进入log-web的jar包,由其协助log4j2自动完成
//在ServletContextListener中关闭Log
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent sce) {
LogManager.shutdown();
}
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>${log4j.version}</version></dependency>
自定义level
Level具有优先级别(越小越高)以及Level名字。我们先来查看一下:logger.info("FATAL :" + Level.FATAL.intLevel() + "," + Level.FATAL.name());
logger.info("ERROR :" + Level.ERROR.intLevel() + "," + Level.ERROR.name());
logger.info("WARN :" + Level.WARN.intLevel() + "," + Level.WARN.name());
logger.info("INFO :" + Level.INFO.intLevel() + "," + Level.INFO.name());
logger.info("DEBUG :" + Level.DEBUG.intLevel() + "," + Level.DEBUG.name());
logger.info("TRACE :" + Level.TRACE.intLevel() + "," + Level.TRACE.name());
14:16:46.408 [localhost-startStop-1] [INFO ] GlobalListener:43 - FATAL :100,FATAL
14:16:46.408 [localhost-startStop-1] [INFO ] GlobalListener:44 - ERROR :200,ERROR
14:16:46.408 [localhost-startStop-1] [INFO ] GlobalListener:45 - WARN :300,WARN
14:16:46.408 [localhost-startStop-1] [INFO ] GlobalListener:46 - INFO :400,INFO
14:16:46.408 [localhost-startStop-1] [INFO ] GlobalListener:47 - DEBUG :500,DEBUG
14:16:46.408 [localhost-startStop-1] [INFO ] GlobalListener:48 - TRACE :600,TRACE
步骤一:自定义Level
public class CustomLevels {
public static final Level CONFIG = Level.forName("CONFIG", 350);
public static final Level NOTICE = Level.forName("NOTICE", 450);
public static final Level DIAG = Level.forName("DIAG", 550);
}
步骤二:设置自定义的level
public void initLogger() {
Configurator.setLevel("CONFIG", CustomLevels.CONFIG);
Configurator.setLevel("NOTICE", CustomLevels.NOTICE);
Configurator.setLevel("DIAG", CustomLevels.DIAG);
}
步骤三:使用自定义的level
logger.log(CustomLevels.CONFIG, "Config customer logger.");
logger.log(CustomLevels.NOTICE,"NOTICE TEST");
logger.info(logger.isEnabled(CustomLevels.DIAG));
输出为:
14:39:13.833 [ContainerBackgroundProcessor[StandardEngine[Catalina]]] [CONFIG] GlobalListener:42 - Config customer logger.
14:39:13.842 [ContainerBackgroundProcessor[StandardEngine[Catalina]]] [NOTICE] GlobalListener:43 - NOTICE TEST
14:39:13.843 [ContainerBackgroundProcessor[StandardEngine[Catalina]]] [INFO] GlobalListener:44 - false
使用MARKER
相关配置。如果是动作是NEUTRAL,则表示继续往下匹配,如果一直没有匹配出来,就是ACCEPT。<logger name="cn.wei.flowingflying" level="info" additivity="false">
<appender-ref ref="WroxFileAppender" />
<appender-ref ref="Console">
<MarkerFilter marker="MARKER_CONSOLE" onMatch="ACCEPT" onMismatch="DENY" />
</appender-ref>
</logger>
代码如下
logger.trace(MarkerManager.getMarker("MARKER_CONSOLE"), "Hello, TRACE");
logger.debug(MarkerManager.getMarker("MARKER_CONSOLE"), "Hello, DEBUG");
logger.info(MarkerManager.getMarker("MARKER_CONSOLE"), "Hello, INFO");
ThreadContext
在上文提到%X{key},可以显示ThreadContext该key的值。当web访问的用户量很大时,log很多,我们需要区分哪些是某个request下引发的log。例如,我们希望知道是那个用户在进行操作。
步骤1:代码定义LoggingFilter
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
//1)定义loggerFilter
FilterRegistration.Dynamic registration = context.addFilter(
"loggingFilter", new LoggingFilter()
);
registration.addMappingForUrlPatterns(
EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE,
DispatcherType.FORWARD, DispatcherType.ERROR),
false, "/*"
);
//2)定义其他的Filter
... ...
}
步骤2:实现LoggingFilter,设置ThreadContext中map的值
public class LoggingFilter implements Filter {
/**
* 我们为每个ThreadContext增加一个id作为其唯一标识,并在Thread结束后全部清空。
* 如果一个请求存在跳转,就可能多次经过这个doFilter()。
* 在最外面那级,clear设置为true,并设置id和username,并在最外一级结束时清空数据。
* 其实id对我们没太多意义,使用%t才看线程名字即可,可以只设置username。
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException,ServletException{
boolean clear = false;
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();
}
}
}
... ...
}
步骤3:在log中显示username和id
<pattern>%d{HH:mm:ss.SSS} [%t] %X{id} %X{username} [%-5level] %c{1}(%M):%L %msg%n</pattern>
相关链接: 我的Professional Java for Web Applications相关文章