工作中,在排查线上问题时,有以下场景在不重新部署或重启服务的情况下,需要动态调整线上日志级别

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" 表示不匹配该级别以下的



log4j2和logback动态修改日志级别工具类的更多相关文章

  1. Logback动态修改日志级别

    https://blog.csdn.net/totally123/article/details/78931287

  2. log4j2动态修改日志级别及拓展性使用

    一.供参考的完整日志配置 <?xml version="1.0" encoding="UTF-8"?> <!-- 配置LoggerConfig ...

  3. SpringBoot系列十一:SpringBoot整合Restful架构(使用 RestTemplate 模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别)

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot整合Restful架构 2.背景 Spring 与 Restful 整合才是微架构的核心,虽然在整 ...

  4. springboot动态修改日志级别+权限认证

    1. springboot动态修改日志级别+权限认证 1.1. 需求 网上找到的动态修改日志级别的方式,基本都是没有权限验证的,或者特地关闭权限验证,但也没给出加上验证的解决方式 修改日志等级也是一个 ...

  5. [C#] 将NLog输出到RichTextBox,并在运行时动态修改日志级别过滤

    作者: zyl910 一.缘由 NLog是一个很好用的日志类库.利用它,可以很方便的将日志输出到 调试器.文件 等目标,还支持输出到窗体界面中的RichTextBox等目标. 而且它还支持在运行时修改 ...

  6. Spring Boot动态修改日志级别

    1. pom中引入 org.springframework.boot       spring-boot-starter-actuator 2. 发送POST请求: 地址: http://[服务地址] ...

  7. 动态调整日志级别思路&实现

    引言 上篇文章 性能调优--小小的 log 大大的坑 已将详细的介绍了高并发下,不正确的使用日志姿势,可能会导致服务性能急剧下降问题.文末也给各位留下了解决方案--日志级别动态调整. 本文将详细介绍& ...

  8. springboot2整合logback.xml动态修改日志打印级别

    今天找bug烦到了,生产上的日志级别不能修改,非常不利于排查问题,于是想到了动态修改日志打印级别, 因为上一周把项目升级成springboot2,并且使用logback.xml管理日志打印,所以修改也 ...

  9. Log4cpp配置文件及动态调整日志级别的方法

    一.log4cpp概述 Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它的优点如下: 提供应用程序运行上下文,方便跟踪调试: 可扩展的.多种方式记录日志,包括命令 ...

随机推荐

  1. List实体类、DataTable与xml互转

    序列化常用Attribute讲解说明 [XmlRootAttribute("MyCity", Namespace="abc.abc", IsNullable=f ...

  2. PHP笔记03

    PHP表单 获取表单数据 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  3. 吴裕雄--天生自然C++语言学习笔记:C++ 指针

    每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址. #include <iostream> using namesp ...

  4. 吴裕雄--天生自然C++语言学习笔记:C++ 运算符

    运算符是一种告诉编译器执行特定的数学或逻辑操作的符号.C++ 内置了丰富的运算符,并提供了以下类型的运算符: 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 杂项运算符 算术运算符 下表显示 ...

  5. Elasticsearch 教程

    章节 Elasticsearch 基本概念 Elasticsearch 安装 Elasticsearch 使用集群 Elasticsearch 健康检查 Elasticsearch 列出索引 Elas ...

  6. NumPy 基于已有数据创建数组

    原文:Python Numpy 教程 章节 Numpy 介绍 Numpy 安装 NumPy ndarray NumPy 数据类型 NumPy 数组创建 NumPy 基于已有数据创建数组 NumPy 基 ...

  7. es6 part 1 //const let

    1. let 命令 ES6 新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. { let a = 10; var b = 1; } a // ...

  8. hadoop的文件操作整理java

    package dada; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; im ...

  9. UVA - 116 Unidirectional TSP (单向TSP)(dp---多段图的最短路)

    题意:给一个m行n列(m<=10, n<=100)的整数矩阵,从第一列任何一个位置出发每次往右,右上或右下走一格,最终到达最后一列.要求经过的整数之和最小.第一行的上一行是最后一行,最后一 ...

  10. C语言预处理理论2

    C语言预处理理论1.头文件包含(1)#include <>和#include ""区别:<>专门用来包含系统提供的头文件(就是系统自带的,不是程序员自己写的 ...