log4j2和logback動態修改日志級別工具類


工作中,在排查線上問題時,有以下場景在不重新部署或重啟服務的情況下,需要動態調整線上日志級別

1、線上有些日志打印過多干擾有用的日志,需要動態修改線上日志記錄器的打印日志級別,調高一些日志級別,打印出更少的干擾日志

2、由於線上日志級別打印的相關有用日志太少,需要動態修改線上日志記錄器的打印日志級別,調低一些日志級別,打印出更多的有用日志

   本文的兩個工具類使用的版本如下:

----------------logback---------------------

 <dependency>
   <groupId>ch.qos.logback</groupId>
   <artifactId>logback-core</artifactId>
   <version>1.1.8</version>
</dependency>
-----------------log4j2--------------------
<dependency>

   <groupId>org.springframework.boot</groupId>

   <artifactId>spring-boot-starter-log4j2</artifactId>

   <version>1.5.12.RELEASE</version>

</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>2.7</version>
 </dependency>

-----------------Log4j2Controller-------------------------

@Api(tags = "Log4j2Controller",description = "Log4j2控制類")
@RestController
@RequestMapping("/log/control")
public class Log4j2Controller {
private static final Logger logger = LoggerFactory.getLogger(Log4j2Controller.class);

@RequestMapping(value = "/getLoglevel", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json;charset=UTF-8")
public Level getLoglevel(@RequestParam(value="package") String packageName) throws Exception {//package 指定修改日志級別的包路徑 ,如 org.mybatis
logger.info("getLoglevel packageName is {}",packageName);
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
return ctx.getLogger(packageName).getLevel();
}

@RequestMapping(value = "/setLoglevel", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json;charset=UTF-8")
public String setLoglevel(@RequestParam("loglevel") String logLevel, @RequestParam(value="package") String packageName) throws Exception {

logger.info("setLoglevel packageName is {},logLevel is {}",packageName,logLevel);
try{
Configurator.setLevel(packageName,Level.valueOf(logLevel));
}catch (Exception e){
logger.error("Exception setLoglevel packageName is {},logLevel is {}",packageName,logLevel,e);
return "fail";
}
return "success";
}
@RequestMapping(value = "/setRootLoglevel", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json;charset=UTF-8")
public String setRootLoglevel(@RequestParam("loglevel") String logLevel) throws Exception {
logger.info("setRootLoglevel ,logLevel is {}",logLevel);
try {
//設置根記錄器
Configurator.setRootLevel(Level.valueOf(logLevel));
}catch (Exception e){
logger.error("Exception setRootLoglevel ,logLevel is {}",logLevel,e);
return "fail";
}
return "success";
}
@RequestMapping(value = "/testLoglevel", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json;charset=UTF-8")
public String testLoglevel() throws Exception {
logger.debug("current log level is debug..........debug...");
logger.info("current log level is info.........info......");
logger.warn("current log level is warn.......warn.......");
logger.error("current log level is error.......error.......");

return "success";
}
}


-----------------LogbackController-------------------------
@Api(tags = "LogbackController",description = "logback控制類")
@RestController
@RequestMapping("/log/control")
public class LogbackController {
private static Logger logger = LoggerFactory.getLogger(LogbackController.class);

@RequestMapping(value = "/getLoglevel", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json;charset=UTF-8")
public Level getLoglevel(@RequestParam(value="package") String packageName) throws Exception {//package 指定修改日志級別的包路徑 ,如 org.mybatis
logger.info("getLoglevel packageName is {}",packageName);
LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
return loggerContext.getLogger(packageName).getLevel();
}

@RequestMapping(value = "/setLoglevel", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String setLoglevel(@RequestParam("loglevel") String logLevel, @RequestParam(value="package") String packageName) throws Exception {
logger.info("setLoglevel packageName is {},logLevel is {}",packageName,logLevel);
try{
LoggerContext loggerContext =(LoggerContext)LoggerFactory.getILoggerFactory();
loggerContext.getLogger(packageName).setLevel(Level.valueOf(logLevel));
}catch (Exception e){
logger.error("Exception packageName is {},logLevel is {}",packageName,logLevel,e);
return "fail";
}
return "success";
}

@RequestMapping(value = "/setRootLoglevel", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String setRootLoglevel(@RequestParam("loglevel") String logLevel) throws Exception {
logger.info("setRootLoglevel ,logLevel is {}",logLevel);
try{
LoggerContext loggerContext =(LoggerContext)LoggerFactory.getILoggerFactory();
//設置全局日志級別
ch.qos.logback.classic.Logger logger=loggerContext.getLogger("root");
logger.setLevel(Level.toLevel(logLevel));
}catch (Exception e){
logger.error("Exception setRootLoglevel,logLevel is {}",logLevel,e);
return "fail";
}
return "success";
}

@RequestMapping(value = "/testLoglevel", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String testLoglevel() throws Exception {
logger.debug("current log level is debug..........debug...");
logger.info("current log level is info.........info......");
logger.warn("current log level is warn.......warn.......");
logger.error("current log level is error.......error.......");

return "success";
}
}

備注:
1、logback和log4j2也有其它方式動態修改日志,但需要有方案或權限修改線上部署服務器的修改權限
比如logback.xml中
的configuration標簽有<configuration scan="true" scanPeriod="60 seconds" debug="false">這種配置,
其中的scan如果設置為true的話,項目在啟動后就會默認每一分鍾自動掃描配置文件,如果有改變則重新加載,而我們還可以設置自動掃描的時間間隔屬性scanPeriod,可以設置成30秒或者5分鍾。
現在只要在logback.xml中添加一個屬性,以后可以直接在服務器上修改logback.xml中root的level屬性或者直接替換整個logback.xml文件,然后過會項目的日志輸出級別就會改變了,不需要再重啟項目。
2、本文主要介紹代碼動態修改線上日志級別
3、log4j2遇到的坑,如果把某個logger的日志級別修改成debug,日志文件一直不會打印,但控制台會正常打印。
經排查是log4j2.xml中appender的過濾級別配置導致的,如下:
修改前:
<Filters>
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
 修改后:
<Filters>

<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
</Filters>

簡單對比說明:
onMatch和onMismatch都有三個屬性值:Accept、DENY和NEUTRAL
onMatch="ACCEPT" 表示匹配該級別及以上
onMatch="DENY" 表示不匹配該級別及以上
onMatch="NEUTRAL" 表示該級別及以上的,由下一個filter處理,如果當前是最后一個,則表示匹配該級別及以上
onMismatch="ACCEPT" 表示匹配該級別以下
onMismatch="NEUTRAL" 表示該級別及以下的,由下一個filter處理,如果當前是最后一個,則不匹配該級別以下的
onMismatch="DENY" 表示不匹配該級別以下的








免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM