当前位置: 首页 > news >正文

记录一次日志告警随着nacos文件动态刷新而失效的问题

           事情是这样的:我把告警的配置修改成了随着nacos动态更新的,但是更新后日志异常告警却不打印了。刚开始怀疑是不是网络或者nacos配置的问题,经过复现发现是因为我每次修改完nacos动态配置后,我的日志组件TurboFilter 是基于日志logback,他不是spring的bean的方式加载的,而nacos的动态更新需要bean是spring的,当我在nacos更新后,日志组件没有动态加载导致失效了。

 

   我的原来的代码:

      

/*** 异常日志堆栈-用于非运行时异常的告警提示* @author fanht* @date 2022-03-21  17:28* @versio 1.0*/
@Component
public class MarketingLogFilter extends TurboFilter {/**rocketmq异常信息打印*/private static final String ROCKETMQ_ERROR = "rocketmq";@Resourceprivate SimpleBufferTriggerUtils simpleBufferTriggerUtils;@Resourceprivate OptionalAlarmUriUtils optionalAlarmUriUtils;@Resourceprivate DingdingAlarmUtil dingdingAlarmUtil;@Overridepublic FilterReply decide(Marker marker, Logger logger, Level level, String s, Object[] objects, Throwable throwable) {if(logger.getName().contains("rocketmq")){System.out.println("mq error:" + (Optional.of(logger).map(l->l.getName()).orElse(null))+ ",throwable:" + Optional.ofNullable(throwable).map(t->t.getMessage()).orElse(null));}if(dingdingAlarmUtil==null){dingdingAlarmUtil = ApplicationContext.getBean(DingdingAlarmUtil.class);}//todo 如果是非运行时异常 发送钉钉告警。排除运行时异常if(throwable != null && StringUtils.isNotEmpty(throwable.getMessage()) && level.equals(Level.ERROR)){if(optionalAlarmUriUtils == null){optionalAlarmUriUtils = ApplicationContext.getBean(OptionalAlarmUriUtils.class);}if(!optionalAlarmUriUtils.isExistUri(logger.getName())){if(simpleBufferTriggerUtils == null){simpleBufferTriggerUtils =  ApplicationContext.getBean(SimpleBufferTriggerUtils.class);}simpleBufferTriggerUtils.proceErrorAlarm(Tag.builder().applicationName(dingdingAlarmUtil.getApplicationName()).env(dingdingAlarmUtil.getEnv()).ip(IpUtil.initIp()).traceId(MDC.get(TraceUtils.TRACE_ID)).requestUri(logger.getName()).exMessage(JSONObject.toJSON(throwable.getMessage().length() >500 ?throwable.getMessage().substring(0,500).toString():throwable.getMessage()).toString()).build());}}else if(Level.ERROR.equals(level) && logger.getName().contains(ROCKETMQ_ERROR)){//如果是mq的异常 也要进行告警if(!optionalAlarmUriUtils.isExistUri(logger.getName())){String exMessage = Optional.ofNullable(s).orElse("") + Optional.ofNullable(objects).map(t->t[0]).orElse(null);simpleBufferTriggerUtils.proceErrorAlarm(Tag.builder().applicationName(dingdingAlarmUtil.getApplicationName()).env(dingdingAlarmUtil.getEnv()).ip(IpUtil.initIp()).requestUri(logger.getName()).traceId(MDC.get(TraceUtils.TRACE_ID)).exMessage(Optional.ofNullable(exMessage).map(t->t.length()>500?t.substring(0,500):t).orElse("")).build());}}//todo 如果接入kafka,则此处需要需要改为NEUTRAL,以防止kakfa的多次打印return FilterReply.NEUTRAL;}
}

 

         

 

 

      

Spring Cloud 的 Logging Refresh 会重建 Logback 上下文

当你调用 /actuator/refresh(或 Nacos 自动触发 refresh)时,Spring Cloud 会刷新 logging 相关配置(如 logging.level.*logging.file.name 等)。

而 Logback 的实现方式是:重建整个 LoggerContext

这意味着:

  • 原有的 LoggerContext 被关闭
  • 所有已注册的 AppenderTurboFilterLogger 都被清除
  • 创建一个新的 LoggerContext
  • 重新加载 logback-spring.xml

 

         

这就是为什么刷新后 decide() 完全不执行 —— filter 根本不在新上下文中。


✅ 解决方案:监听 LoggerContext 重建事件,自动重新注册

Logback 提供了 LoggerContextListener 机制,但更简单的方式是:监听 Spring 的 ApplicationEnvironmentPreparedEventContextRefreshedEvent 不行,因为 logging refresh 是独立的。

正确做法:监听 Logback 自身的 ContextResetEvent

但 Spring Boot 封装了 Logback,我们可以通过 监听 Spring 的 LoggingApplicationListener 行为 来间接处理。

不过最可靠、最通用的方法是:

每次 Logback 初始化时自动注册你的 TurboFilter

✅ 推荐方案:自定义 LoggerContextListener

创建一个 Logback 的 listener,在每次上下文初始化时注册 filter:

  

 最佳方案(不改 XML):

监听 RefreshScopeRefreshedEvent,并在新 LoggerContext 初始化后重新注册 TurboFilter

关键点:

  • Spring Cloud 在 /actuator/refresh 后会发布 RefreshScopeRefreshedEvent
  • 此时 Logback 的 LoggerContext 可能已经被重建
  • 我们可以在事件监听器中 重新获取当前 LoggerContext 并注册 filter

 

 

Component
public class TurboFilterReRegistrar {private final MarketingLogFilter marketingLogFilter;public TurboFilterReRegistrar(MarketingLogFilter marketingLogFilter) {this.marketingLogFilter = marketingLogFilter;}/*** 监听 Refresh 完成事件(包括 Nacos 配置刷新)*/@EventListenerpublic void handleRefresh(RefreshScopeRefreshedEvent event) {reRegisterTurboFilter();}/*** 也监听 Context Refreshed(兜底,确保启动时也注册)*/@EventListenerpublic void handleContextRefreshed(ContextRefreshedEvent event) {reRegisterTurboFilter();}private void reRegisterTurboFilter() {try {ILoggerFactory factory = LoggerFactory.getILoggerFactory();if (factory instanceof LoggerContext) {LoggerContext context = (LoggerContext) factory;// 检查是否已存在,避免重复注册(TurboFilter 没有 equals/hashCode,简单用类型判断)boolean alreadyRegistered = context.getTurboFilterList().stream().anyMatch(f -> f.getClass() == MarketingLogFilter.class);if (!alreadyRegistered) {context.addTurboFilter(marketingLogFilter);System.out.println("✅ Re-registered MarketingLogFilter after refresh");} else {// 如果已存在,可能是同一个实例,无需操作System.out.println("ℹ️ MarketingLogFilter already registered");}}} catch (Exception e) {System.err.println("❌ Failed to re-register TurboFilter: " + e.getMessage());e.printStackTrace();}}
}

 

http://www.jsqmd.com/news/160289/

相关文章:

  • Safeguard Global名义雇主EOR:2026助力出海企业快速合规雇佣加拿大员工 - 品牌2025
  • 2025-2026权威解析:如何选择LED显示屏厂家?这份推荐榜单值得参考 - 深度智识库
  • 企业微信开发:外部群消息推送的“三步走”逻辑
  • 防脱发洗发水哪个牌子好?十大防脱发洗发水推荐,解决脱发困扰 - 博客万
  • 大模型Agent vs Workflow:谁才是程序员的“躺平“救星?99%的人都选错了!
  • 森果云面试经历
  • 2025-2026兰州钢琴搬运公司TOP3最新推荐报告:甘肃蚂蚁搬家全链条保障 - 深度智识库
  • langchain4j 构建agent工作流
  • 卫星通信与物联网模组融合发展的新趋势
  • 【Java毕设全套源码+文档】基于springboot的特殊儿童家长教育能力提升平台设计与实现(丰富项目+远程调试+讲解+定制)
  • 别再只学技术了!AI产品经理转型第一课:用你最强的“需求洞察力”,理解大模型本质!
  • 普通人能进军网络安全行业吗?过来人手把手支招,帮你躲开这 5 个误区!
  • 2025最新!8个AI论文平台测评:本科生毕业论文写作痛点全解析
  • 2025年质量好的复合井盖公司推荐:双层井盖、变电站室外电缆沟盖板、复合井盖、复合树脂井盖、复合盖板、成品复合电缆沟盖板选择指南 - 优质品牌商家
  • 2026年采购决策:环境噪声自动监测系统推荐工厂/实力厂家推荐,优质供应商哪家好,哪个品牌好 - 品牌推荐大师1
  • 【Java毕设全套源码+文档】基于springboot的实验室开放管理系统设计与实现(丰富项目+远程调试+讲解+定制)
  • 大模型核心技术解析:Embedding原理与向量数据库!
  • MySQL EXPLAIN 执行计划分析:能否查看 JOIN 关联顺序
  • 2025年湖南工程师职称申报服务权威推荐榜:中级职称申报/筑励咨询职称申报/高级职称申报/高级工程师职称申报服务精选 - 品牌推荐官
  • 2025年绝缘曲臂高空作业车行业应用白皮书:绝缘斗臂高空作业车、绝缘曲臂高空作业车、绝缘直臂高空作业车、绝缘臂高空作业车选择指南 - 优质品牌商家
  • 0335-Tetris-渲染方块
  • 【Java毕设全套源码+文档】基于springboot的垃圾分类回收管理系统设计与实现(丰富项目+远程调试+讲解+定制)
  • 大模型应用工程师的真实薪资曝光:入行门槛、发展路径与2026年招聘趋势全解析!
  • 2025-2026长途搬家公司最新TOP3推荐出炉!甘肃蚂蚁搬家彰显专业实力 - 深度智识库
  • 计算机专业大学生必读:CTF 比赛值得打吗?一文讲透参赛要求与获奖好处!
  • 深入浅出解析具身智能:技术栈、实践案例与代码实现
  • 2026年宁夏银川GEO AI优化公司最新综合实力调研排行
  • 学习通越过手机客户端限制考试/作业
  • 2025年防火槽式桥架怎么选?这份优质厂家推荐榜单请收好 - 深度智识库
  • 【Java毕设源码分享】基于springboot+vue的家政预约平台的设计与实现(程序+文档+代码讲解+一条龙定制)