java项目运行时更改类或包的日志打印级别

因为新入职的公司日志打印比较多,有些与业务无关、排查问题的日志打印没有必要实时输出,日志打印多了还会影响到系统性能,所以写了这个可以在运行时实时更改日志的功能,这个是针对logback的,如果使用的是log4j,请看LogLeverChangeController 类的main方法中被注释掉的示例。


效果如下:

下图中树形列表显示出所有可以设置日志级别的包和类,下图选中了org.apache.commons.beanutils.BeanUtils这个类,树形列表上面实现了它的日志级别。

java项目运行时更改类或包的日志打印级别_第1张图片

从下拉选择框中选择WARN,点击修改按钮,将BeanUtils类的日志级别从info更改为warn:

java项目运行时更改类或包的日志打印级别_第2张图片

提示修改成功:

java项目运行时更改类或包的日志打印级别_第3张图片


直接贴实现代码:

spring controller类

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fintell.model.vo.BaseResponse;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;


/**
 * @author zqz  2018-06-27 12:02
 * 应用运行时动态更改logback的日志打印级别。
 * 
 * 一、指定某个类或包的日志打印级别,举个栗子:
 * 
 * 类:com.fintell.common.task.ConfigLoaderTask
 * 级别:WARN
 * http://xxxxx/log/level?level=WARN&target=com.fintell.common.task.ConfigLoaderTask
 * 
 * 二、指定整个应用的日志打印级别,慎用此功能,举个栗子:
 * 指定应用的日志级别为ERROR
 * http://xxxxx/log/level/all?level=ERROR
 * 
 */
@Controller
@RequestMapping(value = "/log")
public class LogLeverChangeController {
    private static Logger log = LoggerFactory.getLogger(LogLeverChangeController.class);

    private final static String PARAM_CHECH_LOG_LEVEL_ERROR = "请输入正确的日志级别:OFF、ERROR、WARN、INFO、DEBUG、TRACE、ALL;您输入的级别为:";
    private final static String PARAM_CHECH_LOG_TARGET_ERROR = "目标类或包不能为空";
    /**日志logger不存在提示信息**/
    private final static String LOGGER_NOT_EXIST_CHECK  = "日志logger不存在";
    /** logback日志级别*/
    private final static Set logLevelCheck = new HashSet();
    static{
    	logLevelCheck.add("OFF");
    	logLevelCheck.add("ERROR");
    	logLevelCheck.add("WARN");
    	logLevelCheck.add("INFO");
    	logLevelCheck.add("DEBUG");
    	logLevelCheck.add("TRACE");
    	logLevelCheck.add("ALL");
    }
    
    /**
     * 跳转到日志级别管理列表页面
     * @return
     */
    @RequestMapping(value = "/level/toList")
    public String goToLogLevelPage() {
    	return "log/logTree";
    }
    
    @RequestMapping(value = "/list")
    @ResponseBody
    public List listLogger() {
    	LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    	//获取应用中的所有logger实例  
		List loggerList = loggerContext.getLoggerList();
		List allLogger = new ArrayList();
		for(ch.qos.logback.classic.Logger logger : loggerList) {
			LogInfoVO info = new LogInfoVO();
			info.setLevel(logger.getEffectiveLevel().levelStr);
			info.setName(logger.getName());
			allLogger.add(info);
		}
    	return allLogger;
    }
    
    /**
     * 获取某个类或包的日志级别
     * @return
     */
    @RequestMapping(value = "/get/level")
    @ResponseBody
    public BaseResponse getLoggerLevel(@RequestParam(value="target", required=true) String target) {
    	if(target == null || "".equals(target)) {
    		return BaseResponse.getFailInstance(PARAM_CHECH_LOG_TARGET_ERROR);
    	}
    	LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    	ch.qos.logback.classic.Logger logger = loggerContext.getLogger(target);
    	if(logger!=null) {
    		LogInfoVO llc = new LogInfoVO();
    		llc.setName(logger.getName());
    		llc.setLevel(logger.getEffectiveLevel().levelStr);
    		return BaseResponse.getSuccessInstance(llc);
    	}
    	return BaseResponse.getFailInstance(LOGGER_NOT_EXIST_CHECK);
    }
    
    /**
     * 获取日志tree列表
     * @return
     */
    @RequestMapping(value = "/tree")
    @ResponseBody
    public BaseResponse listLoggerTree() {
    	LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    	//获取应用中的所有logger实例  
		List loggerList = loggerContext.getLoggerList();
		List allLogger = new ArrayList();
		for(ch.qos.logback.classic.Logger logger : loggerList) {
			LogInfoVO info = new LogInfoVO();
			info.setLevel(logger.getEffectiveLevel().levelStr);
			info.setName(logger.getName());
			allLogger.add(info);
		}
		ZtreeNodeVO root = null;
		try {
			root =this.getTree(allLogger);
		}catch(Exception e) {
			e.printStackTrace();
		}
		List nodes =  root.getChildren();
		return BaseResponse.getSuccessInstance(nodes);
    }
    
    /**
     * 设置某个类或某个包的日志输出级别
     * @param level    日志级别     只能取值:OFF、ERROR、WARN、INFO、DEBUG、TRACE、ALL
     * @param target   类或包名     
     * @return
     */
    @RequestMapping(value = "/level")
    @ResponseBody
    public BaseResponse changeLogLevel(/**@PathVariable("logLevel")**/
    		@RequestParam(value="level" , required=true) String level,
    		@RequestParam(value="target", required=true) String target) {
    	if(!checkLogLevel(level)) {
    		return BaseResponse.getFailInstance(PARAM_CHECH_LOG_LEVEL_ERROR+level);
    	}
    	if(target == null || "".equals(target)) {
    		return BaseResponse.getFailInstance(PARAM_CHECH_LOG_TARGET_ERROR);
    	}
    	LogLevelChangeVO llc =  this.setLevel(target, level);
    	return llc == null ? BaseResponse.getFailInstance(LOGGER_NOT_EXIST_CHECK) : BaseResponse.getSuccessInstance(llc);
    }
    
    /**
     * 设置整个系统的日志级别,慎用
     * @param level
     * @param target
     * @return
     */
    @RequestMapping(value = "/level/all")
    @ResponseBody
    public String changeAllLevel(
    		@RequestParam(value="level" , required=true) String level) {
    	if(!checkLogLevel(level)) {
    		return PARAM_CHECH_LOG_LEVEL_ERROR+level;
    	}
        return this.setLevel(level);
    }
    
    
    /**
     * 修改日志级别
     * @param target
     * @param level
     * @return
     */
    private LogLevelChangeVO setLevel(String target,String level) {
    	LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    	ch.qos.logback.classic.Logger logger = loggerContext.getLogger(target);
    	if(logger!=null) {
    		LogLevelChangeVO llc = new LogLevelChangeVO();
    		llc.setFullName(logger.getName());
    		llc.setBeforeLevel(logger.getEffectiveLevel().levelStr);
    		logger.setLevel(Level.valueOf(level));
    		llc.setAfterLevel(logger.getEffectiveLevel().levelStr);
    		return llc;
    	}
    	return null;
    }
    
    /**
     * 设置整个应用的日志级别,慎用此功能
     * @param level
     * @return
     */
    private String setLevel(String level) {
    	LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    	//获取应用中的所有logger实例  
		List loggerList = loggerContext.getLoggerList(); 
		 //返回设置结果
        StringBuilder sb = new StringBuilder();
        sb.append("修改前日志级别:\r\n");
		//遍历更改每个logger实例的级别
        for (ch.qos.logback.classic.Logger logger:loggerList){
        	//记录修改前的日志级别
        	this.recordLogLevel(sb, logger);
        	//设置日志级别
            logger.setLevel(Level.toLevel(level));
        }
        sb.append("修改后日志级别:\r\n");
        for(ch.qos.logback.classic.Logger logger:loggerList) {
        	//记录修改后的日志级别
        	this.recordLogLevel(sb, logger);
        }
        return sb.toString();
    }
    
    /**
     * 检查日志级别是否正确
     * @return  true 验证通过  false 验证未通过
     * **/
    private boolean checkLogLevel(String level) {
    	return level==null || !logLevelCheck.contains(level)?false:true;
    }
    
    /**
     * 构建树形结构
     * @param allLogger
     */
    private ZtreeNodeVO getTree(List allLogger) {
    	HashMap treeMap = new HashMap();
    	String fullName;
    	// 根节点
    	ZtreeNodeVO root = new ZtreeNodeVO();
    	for(LogInfoVO logger : allLogger) {
    		fullName = logger.getName();
    		//如果是一級節點
    		if(!fullName.contains(".")) {
    			// 如果節點已經存在,則跳過
    			if(treeMap.containsKey(fullName)) {
    				continue;
    			}
    			// 如果節點不存在
    			ZtreeNodeVO topNode = new ZtreeNodeVO();
    			topNode.setName(fullName);
    			topNode.setFullName(fullName);
    			root.addChild(topNode);
    			treeMap.put(fullName, topNode);
    			continue;
    		}
    		
    		// 如果非一级节点
    		String[] names = fullName.split("\\.");
    		// 父节点全名
    		String parentFullName ="";
    		ZtreeNodeVO paretnNode = null;
    		// 构建节点树
    		for(int i = 0 ,j = names.length ; i < j ; i++) {
    			ZtreeNodeVO node = treeMap.get(i==0?names[i]:parentFullName+"."+names[i]);
    			if(node == null) {
    				// 一级节点
    				if( i == 0 ) {
    					node = new ZtreeNodeVO();
    					node.setName(names[i]);
    					node.setFullName(names[i]);
    	    			// 添加到树中
    	    			root.addChild(node);
    	    			treeMap.put(names[i], node);
    				}else {
    					node = new ZtreeNodeVO();
    					node.setName(names[i]);
    					node.setFullName(parentFullName+"."+node.getName());
    	    			paretnNode.addChild(node);
    	    			treeMap.put(fullName, node);
    				}
    			}
    			// 供下次循环使用
    			if(i == j-1) {
    				parentFullName = "";
    				paretnNode = null;
    			}else {
    				parentFullName = node.getFullName();
    				paretnNode = node;
    			}
    		}
    	}
    	return root;
    }
    
    /**
     * 记录日志级别
     * @param sb
     * @param logger
     * @return
     */
    private StringBuilder recordLogLevel(StringBuilder sb,ch.qos.logback.classic.Logger logger) {
    	sb.append(logger.getName());
    	if(logger.getEffectiveLevel()!=null) {
    		sb.append(",EffectiveLevel=").append(logger.getEffectiveLevel().levelStr);
    	}
    	if(logger.getLevel()!=null) {
    		sb.append(",level=").append(logger.getLevel().levelStr);
    	}
    	sb.append("#\r\n");
    	return sb;
    }
    
    /**
     * test
     * @param args
     */
    public static void main(String[] args)  {  
        //logback
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();  
        //获取应用中的所有logger实例
        List loggerList = loggerContext.getLoggerList();  
        //遍历更改每个logger实例的级别
        for (ch.qos.logback.classic.Logger logger:loggerList){ 
        	System.out.print("name:"+logger.getName());
        	if(logger.getLevel()!=null)
        	System.out.print("\t getLevel:"+logger.getLevel().levelStr);
        	System.out.println("\t getEffectiveLevel:"+logger.getEffectiveLevel().levelStr);
            logger.setLevel(Level.toLevel("ALL"));  
        }
        
        /**
        //log4j  
        Enumeration enumeration = LogManager.getCurrentLoggers();  
        while (enumeration.hasMoreElements()){  
            org.apache.log4j.Logger logger = (org.apache.log4j.Logger) enumeration.nextElement();  
            logger.setLevel(org.apache.log4j.Level.toLevel("error"));  
        }  

        //log4j2  
        Collection notCurrentLoggerCollection = org.apache.logging.log4j.core.LoggerContext.getContext(false).getLoggers();  
        Collection currentLoggerCollection = org.apache.logging.log4j.core.LoggerContext.getContext().getLoggers();  
        Collection loggerCollection = notCurrentLoggerCollection;  
        loggerCollection.addAll(currentLoggerCollection);  
        for (org.apache.logging.log4j.core.Logger logger:loggerCollection){  
            logger.setLevel(org.apache.logging.log4j.Level.toLevel("error"));  
        }  
        **/
        log.info("info");  
        log.error("error");  
    }
    
    /**
     * 更改日志级别
     * @author zqz
     *
     */
    static class LogLevelChangeVO{
    	/**全名**/
    	private String fullName;
    	/**更改前的级别**/
    	private String beforeLevel;
    	/**更改后的级别**/
    	private String afterLevel;
		public String getFullName() {
			return fullName;
		}
		public void setFullName(String fullName) {
			this.fullName = fullName;
		}
		public String getBeforeLevel() {
			return beforeLevel;
		}
		public void setBeforeLevel(String beforeLevel) {
			this.beforeLevel = beforeLevel;
		}
		public String getAfterLevel() {
			return afterLevel;
		}
		public void setAfterLevel(String afterLevel) {
			this.afterLevel = afterLevel;
		}
    	
    }
    
    
    /**
     * 日志信息
     * @author zqz
     */
    static class LogInfoVO{
    	/**logger 名稱**/
    	private String name;
    	/**logger 級別**/
    	private String level;
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public String getLevel() {
			return level;
		}
		public void setLevel(String level) {
			this.level = level;
		}
    }
    
    
    /**
     * Ztree树形目录节点 
     * @author zqz
     */
    static class ZtreeNodeVO {
    	// 最后一级名称
    	private String name;
    	// 全路径名
    	private String fullName;
    	// 日志級別,注意不能取名为level,与Ztree中默认节点字段冲突
//    	private String type;
    	// 子节点列表
    	private List children= null;
    	// 图标
    	private String icon;
    	
    	
    	public void addChild(ZtreeNodeVO node) {
    		if(children ==null) {
    			children = new ArrayList();
    		}
    		children.add(node);
    	}
    	
    	public String getName() {
    		return name;
    	}
    	
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getFullName() {
    		return fullName;
    	}
    	public void setFullName(String fullName) {
    		this.fullName = fullName;
    	}
    	public List getChildren() {
    		return children;
    	}
    	public void setChildren(List children) {
    		this.children = children;
    	}
    	public String getIcon() {
    		return icon;
    	}
    	public void setIcon(String icon) {
    		this.icon = icon;
    	}
    }
}


jsp页面(树形列表使用ztree实现,下面代码没有导入样式文件,没有导入jquery,自己去找吧)


^_^   =   ^_^




你可能感兴趣的:(java)