运行环境下动态修改日志级别

    调试能力是程序员能力重要组成部分,而日志几乎可以说是我们调试的根本,通过分析日志我们可以了解程序的运行情况,可以分析出那个环节出现问题。

    但是调试日志过多,很多无用的日志信息占了95%,甚至更高。严重影响我们的视线、严重影响我们定位相关日志记录、严重影响我们的工作效率。

    特别是在测试环境下(测试环境一般都是编译好的,不能像开发环境一样顺畅的、方便的使用断点),修改日志级别需要不停的启动或重新部署服务器。这个时候我们需要动态的改变日志的级别。

    我的做法是:把不相关的代码日志级别设置为warn甚至error.把当前业务的代码日志级别设置为debug或info这就需要动态的修改日志的级别(修改日志配合,然后重新部署也可以,不过效率太低)。

    首先是log4j动态修改日志级别,这个很简单,直接看我的代码(log4j.jsp),使用jsp也是方便我随时copy,随时根据需要修改。

<%@page import="Java.util.Enumeration"%>
<%@page import="org.apache.log4j.Logger"%>
<%@page import="org.apache.commons.lang3.StringUtils"%>
<%@page import="org.apache.log4j.Level"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.Iterator"%>
<%@page import="java.util.Collection"%>
<%@page import="java.util.Arrays"%>
<%@page import="java.util.Collections"%>
<%@page import="org.apache.log4j.LogManager"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
//需要修改的日志名称和级别
String logName = request.getParameter("logName");
String level = request.getParameter("level");
//传递了参数
if(StringUtils.isNotEmpty(logName)&&StringUtils.isNotEmpty(level)){
	system.out.println(logName.trim());
	Level l = Level.toLevel(level);
	System.out.println(l);
	Logger logger = LogManager.getLogger(logName.trim());
	logger.setLevel(l);//修改日志级别
	System.out.println(logger.getLevel());
}
//获取所有的日志
Enumeration<Logger> loggers = LogManager.getCurrentLoggers();
//分类存放,方便页面展示
ArrayList<Logger> debugs = new ArrayList();
ArrayList<Logger> infos = new ArrayList();
ArrayList<Logger> warns = new ArrayList();
ArrayList<Logger> errors = new ArrayList();
while(loggers.hasMoreElements()){
	Logger logger = loggers.nextElement();
	Level l = logger.getLevel();
	int i = logger.getLevel().toInt();
	if(i<=Level.ERROR.toInt()){
		errors.add(logger);
		continue;
	}
	if(i<=Level.WARN.toInt()){
		warns.add(logger);
		continue;
	}
	if(i<=Level.INFO.toInt()){
		infos.add(logger);
		continue;
	}
	if(i<=Level.DEBUG.toInt()){
		debugs.add(logger);
		continue;
	}
}
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>log4j</title>
<style type="text/css">
.title{
height: 25px;
background-color: #ccc;
color: #000;
font-weight: bold;
padding-left: 20px;
margin-bottom: 2px;
}
</style>
</head>
<body>
<form action="" style="padding-left: 50px;line-height: 30px;">
	日志名称:<input name="logName" style="width: 500px;"><br/>
	日志级别:<select name="level">
	<option>debug</option>
	<option>info</option>
	<option>warn</option>
	<option>error</option>
	</select><br/>
	<input type="submit" value="https://my.oschina.net/u/1244507/blog/修改日志级别">
</form>
<div class="title">debug</div>
<%
for(int i=0;i<debugs.size();i++ ){
	Logger logger = debugs.get(i);
	out.println(logger.getName()+"</br>");
}
%>

<div class="title">info</div>
<%
for(int i=0;i<infos.size();i++ ){
	Logger logger = infos.get(i);
	out.println(logger.getName()+"</br>");
}
%>

<div class="title">warn</div>
<%
for(int i=0;i<warns.size();i++ ){
	Logger logger = warns.get(i);
	out.println(logger.getName()+"</br>");
}
%>

<div class="title">error</div>
<%
for(int i=0;i<errors.size();i++ ){
	Logger logger = errors.get(i);
	out.println(logger.getName()+"</br>");
}
%>
</body>
</html>

再来看log4j2,代码如下:

<%@page import="com.c503.sc.base.entity.SysLoginParaEntity"%>
<%@page import="org.springframework.web.context.support.WebApplicationContextUtils"%>
<%@page import="org.springframework.context.ApplicationContext"%>
<%@page import="com.c503.sc.system.service.ILoginService"%>
<%@page import="com.alibaba.fastjson.JSON"%>
<%@page import="com.c503.sc.utils.cache.ICache"%>
<%@page import="com.c503.sc.utils.cache.CacheManager"%>
<%@page import="com.c503.sc.system.utils.CacheManagerFactory"%>
<%@page import="org.apache.commons.lang3.StringUtils"%>
<%@page import="org.apache.logging.log4j.Level"%>
<%@page import="java.util.ArrayList"%>
<%@page import="org.apache.logging.log4j.core.Logger"%>
<%@page import="java.util.Iterator"%>
<%@page import="java.util.Collection"%>
<%@page import="java.util.Arrays"%>
<%@page import="java.util.Collections"%>
<%@page import="org.apache.logging.log4j.core.LoggerContext"%>
<%@page import="org.apache.logging.log4j.LogManager"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
//需要修改的日志名称和级别
String logName = request.getParameter("logName");
String level = request.getParameter("level");
if(StringUtils.isNotEmpty(logName)&&StringUtils.isNotEmpty(level)){
	//传递了参数
	System.out.println(logName.trim());
	Level l = Level.toLevel(level);
	System.out.println(l);
	//注意此Logger为org.apache.logging.log4j.core.Logger (实现)
	//一般我们使用的是 org.apache.logging.log4j.Logger	(接口),接口没有setLevel方法
	Logger logger = (Logger)LogManager.getLogger(logName.trim());
	logger.setLevel(l);
	System.out.println(logger.getLevel());
}
/* 同样的道理,获取所有的日志,先要获取上下文,再获取所有的日志
 * 此处获取日志上线文为org.apache.logging.log4j.core.LoggerContext(实现)
 * 一般我们使用的是org.apache.logging.log4j.spi.LoggerContext (接口),接口没有getLoggers方法
 */
LoggerContext logContext = (LoggerContext)LogManager.getContext();
//获取所有日志
Collection<Logger> loggers = logContext.getLoggers();
Iterator<Logger> it = loggers.iterator();
//分类存放,方便页面展示
ArrayList<Logger> debugs = new ArrayList();
ArrayList<Logger> infos = new ArrayList();
ArrayList<Logger> warns = new ArrayList();
ArrayList<Logger> errors = new ArrayList();
for(;it.hasNext(); ){
	Logger logger = (Logger) it.next();
	int i = logger.getLevel().intLevel();
	if(i<=Level.ERROR.intLevel()){
		errors.add(logger);
		continue;
	}
	if(i<=Level.WARN.intLevel()){
		warns.add(logger);
		continue;
	}
	if(i<=Level.INFO.intLevel()){
		infos.add(logger);
		continue;
	}
	if(i<=Level.DEBUG.intLevel()){
		debugs.add(logger);
		continue;
	}
}
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>log4j2</title>
<style type="text/css">
.title{
height: 25px;
background-color: #ccc;
color: #000;
font-weight: bold;
padding-left: 20px;
margin-bottom: 2px;
}
</style>
</head>
<body>
<form action="" style="padding-left: 50px;line-height:30px;">
	日志名称:<input name="logName" style="width: 500px;"><br/>
	日志级别:<select name="level">
	<option>debug</option>
	<option>info</option>
	<option>warn</option>
	<option>error</option>
	</select><br/>
	<input type="submit" value="https://my.oschina.net/u/1244507/blog/修改日志级别">
</form>
<div class="title">debug</div>
<%
for(int i=0;i<debugs.size();i++ ){
	Logger logger = debugs.get(i);
	out.println(logger.getName()+"</br>");
}
%>

<div class="title">info</div>
<%
for(int i=0;i<infos.size();i++ ){
	Logger logger = infos.get(i);
	out.println(logger.getName()+"</br>");
}
%>

<div class="title">warn</div>
<%
for(int i=0;i<warns.size();i++ ){
	Logger logger = warns.get(i);
	out.println(logger.getName()+"</br>");
}
%>

<div class="title">error</div>
<%
for(int i=0;i<errors.size();i++ ){
	Logger logger = errors.get(i);
	out.println(logger.getName()+"</br>");
}
%>
</body>
</html>

log4j2要比log4j复杂一点

当然最后,也再着重提示一下这个代码的使用场景和存在的问题

使用场景:

第一、开发环境:几乎没必要

第二、测试环境:建议在问题不好定位,日志太多的情况下使用

第三、生产环境:不要使用,很危险

存在的问题:动态修改日志级别,会导致我日志输出的内容减少,很多时候我们的日志是输出到不同的目标(控制台、文件、数据库),这样一修改,就会导致所有的日志输出目标的日志减少,特别是在生产环境。宁愿效率低一点,也要保证日志的完整性,这样才能保证可追溯性。

 

赞 (0) 评论 分享 ()