如何动态改变日志级别 选择日志级别

前言
关于日志级别大部分项目可能都设置为info级别当然也可能有一些追求性能或者说包含很多敏感信息的项目直接将级别设置为warn或者error这时候如果项目中出现一些未知异常需要用到很详细的日志信息此时如果项目中没有动态改变日志级别的机制排查问题将很棘手
日志系统
我们常用的一些日志系统包括
Log4j2
Logback
JavaUtilLogging
我们想动态改变日志的级别前提是这些日志系统都支持我们直接设置日志等级当然这些系统提供了很简单的接口
Log4j2
LoggerContextloggerContextLoggerContextLogManagergetContextfalseLoggerConfigloggerConfigloggerContextgetConfigurationgetLoggersgetrootloggerConfigsetLevellevel
Logback
LoggerContextloggerContextLoggerContextLoggerFactorygetILoggerFactoryLoggerloggerloggerContextgetLoggerrootchqoslogbackclassicLoggerloggersetLevellevel
JavaUtilLogging
LoggerloggerLoggergetLoggerrootloggersetLevellevel
当然除了上面直接设置日志级别的方式也有可以动态加载配置文件的方式同样也可以在配置文件中动态改变日志级别以logback为例
LoggerContextlcLoggerContextLoggerFactorygetILoggerFactoryFileexternalConfigFilenewFilelogbackxmlJoranConfiguratorconfiguratornewJoranConfiguratorconfiguratorsetContextlclcresetconfiguratordoConfigureexternalConfigFileLocation
【如何动态改变日志级别 选择日志级别】上面简单介绍了一下每种日志系统都是如何去设置日志级别的最关键的是设置完之后可以实时生效立马可以看到我们想要的日志有了这些下面其实就是通过何种方式去改变日志级别的问题了
如何动态改变级别
如何去动态改变级别最简单的方式就是对外提供一个接口给定一个日志级别作为参数实时变更或者通过配置中心的方式另外其实像SpringBoot这些主流的框架本身也提供了动态修改的功能下面可以具体看一下是如何实现的以logback为例
自定义接口
自定义一个给定日志级别的接口外部直接通过调用接口来改变级别
RequestMappingvaluelogLevellogLevelpublicStringchangeLogLevelPathVariablelogLevelStringlogLeveltryLoggerContextloggerContextLoggerContextLoggerFactorygetILoggerFactoryLoggerloggerloggerContextgetLoggerrootchqoslogbackclassicLoggerloggersetLevelLevelvalueOflogLevelcatchExceptioneloggererrorchangeLogLevelerrorereturnfailreturnsuccess
想要改变日志级别直接请求如下地址即可设置一个debug的级别这种方式虽然比较简单但是如果节点很多的话操作起来就很麻烦当然也可以汇总所有节点路径一次操作触发所有节点的请求其实最好的办法应该是类似发布订阅的方式发布者会给所有订阅者都发送一个更改日志级别的通知有新的节点只要成为订阅者即可这种方式其实就是现在主流的配置中心的方式
配置中心
配置中心的目的其实就是把一些会经常变动的参数集中保存起来某个系统启动时去配置中心获取相关的参数同时会对这些参数进行监听后面在配置中心里面改变参数的值会实时推送给相关系统这样系统就可以在不重启的情况下就更新了配置利用现有的一些中间件我们就能很快实现一个配置中心比如Zookeeper提供了对某个Node进行监听的功能MQ和Redis都有发布订阅的功能所以用来实时推送变更再好不过了
Zookeeper方式
可以直接使用PathChildrenCache用来监听子节点的CHILDADDEDCHILDUPDATEDCHILDREMOVED事件这样如果在Zookeeper服务端对节点的值就行更新客户端会触发以上三个事件
privatevoidwatcherPathStringpathPathChildrenCachecachenewPathChildrenCacheclientpathtruecachestartStartModePOSTINITIALIZEDEVENTcachegetListenableaddListenernewPathChildrenCacheListenerOverridepublicvoidchildEventCuratorFrameworkclientPathChildrenCacheEventeventthrowsExceptionswitcheventgetTypecaseCHILDADDEDbreakcaseCHILDUPDATEDStringlogLevelnewStringeventgetDatagetData日志级别更新处理breakcaseCHILDREMOVEDbreakdefaultbreak
MQ方式
MQ一般都有Queue和Topic方式Topic方式其实就是订阅发布模式所有的集群节点可以订阅某个Topic这样发布端发送更新日志级别的消息其他订阅节点都能收到
日志等级TopicprivatefinalStringTOPICLOGLEVELprivatevoidwatcherPathsthrowsJMSExceptionTopictopicsessioncreateTopicTOPICMessageConsumerconsumersessioncreateConsumertopicconsumersetMessageListenernewMessageListenerOverridepublicvoidonMessageMessagemessageTextMessagetmTextMessagemessageStringlogLeveltmgetText日志级别更新处理
Redis方式
Redis其实除了缓存的功能也提供了类似MQ的发布订阅的模式集群节点通过订阅一个channel发布端通过此channel来发布消息
privatevoidwatcherPathsthrowsJMSExceptionjedissubscribenewJedisPubSubOverridepublicvoidonMessageStringchannelStringmessageStringlogLevelmessage日志级别更新处理LOGLEVEL
SpringBoot内置
SpringBoot20之后可以通过actuator动态调整日志级别主要是通过暴露loggers这个endpoint来实现具体步骤如下
需要引入actuator
orgspringframeworkboot
springbootstarteractuator

暴露loggers
在applicationproperties中添加如下配置
managementendpointswebexposureincludeloggers
查看日志级别
启动服务可以通过查看当前项目每个包的日志级别
levelsOFFERRORWARNINFODEBUGTRACEloggersROOTconfiguredLevelINFOeffectiveLevelINFO
动态修改日志级别
发送POST请求到包路径
需要在body中指定configuredLevel参数比如修改整个项目日志级别为error关于SpringBoot内部是如何实现动态改变日志级别的可以查看其实现核心类LoggersEndpoint
EndpointidloggerspublicclassLoggersEndpointprivatefinalLoggingSystemloggingSystemWriteOperationpublicvoidconfigureLogLevelSelectorStringnameNullableLogLevelconfiguredLevelAssertnotNullnameNamemustnotbeemptythisloggingSystemsetLogLevelnameconfiguredLevel
具体通过LoggingSystem来对日志系统动态改变级别上面也介绍了主流使用的日志系统SpringBoot也都支持这些系统这是一个抽象类具体实现类
JavaLoggingSystem
Log4J2LoggingSystem
LogbackLoggingSystem
NoOpLoggingSystem
分别对应了几种日志系统这几个类内部其实也是调用上面介绍的方法去改变日志级别当然SpringBoot自动会识别出当前使用的是哪个日志系统然后使用哪个LoggingSystem
总结
大部分公司其实更多的还是使用配置中心的方式来动态改变日志级别这种方式更加灵活而且配置中心已经成为很多公司的标配组件不光用来改变日志级别所有有可能改变的参数都可以使用
感谢关注
可以关注回滚吧代码第一时间阅读文章持续更新专注Java源码架构算法和面试

    推荐阅读