log4*框架中,共享类的两个函数如何分文件输出日志并保留类级别控制?
解决方案:利用NDC/MDC实现按函数分流日志,保留类级别控制
针对你遇到的log4php(及其他log4*系列)日志分流需求,最优方案是使用NDC(嵌套诊断上下文)或MDC(映射诊断上下文),这是log4框架的标准特性,既能实现按函数分流日志,又能完整保留类级别的日志控制能力,且无需大幅修改现有代码。
为什么你的初步思路存在问题
- 方案一(每个类创建两个日志器):需要为每个共享类维护多份日志器实例,新增函数时还要同步修改类代码,维护成本极高,扩展性差。
- 方案二(函数日志器传入类):会丢失类级别的日志控制——类中使用的是函数的日志器,无法单独调整某个类的日志级别(比如想只降低DB类的日志等级,会影响所有使用该类的函数),不符合需求。
具体实现步骤(以NDC为例)
1. 修改函数代码,添加NDC上下文标记
在funcA()和funcB()的入口处推入NDC标记,退出时弹出(用finally确保即使异常也能清理上下文):
function funcA() { LoggerNDC::push('funcA'); try { // Do some funcA-ish stuff $db = new DB(); $data = $db->getData(); // Do some more funcA-ish stuff } finally { LoggerNDC::pop(); } } function funcB() { LoggerNDC::push('funcB'); try { // Do some funcB-ish stuff $db = new DB(); $data = $db->getData(); // Do some more funcB-ish stuff } finally { LoggerNDC::pop(); } }
2. 修改log4php配置文件,添加带过滤器的追加器
定义两个文件追加器,分别对应funcA.log和funcB.log,并通过NDC过滤器筛选日志;同时保留原有的类日志器配置,确保类级别日志控制有效:
<!-- 定义funcA专属追加器 --> <appender name="funcAFileAppender" class="LoggerAppenderFile"> <param name="file" value="funcA.log"/> <layout class="LoggerLayoutPattern"> <param name="conversionPattern" value="%d %-5p %c %x - %m%n"/> </layout> <!-- 只接受NDC标记为funcA的日志 --> <filter class="LoggerFilterNDC"> <param name="value" value="funcA"/> <param name="acceptOnMatch" value="true"/> </filter> </appender> <!-- 定义funcB专属追加器 --> <appender name="funcBFileAppender" class="LoggerAppenderFile"> <param name="file" value="funcB.log"/> <layout class="LoggerLayoutPattern"> <param name="conversionPattern" value="%d %-5p %c %x - %m%n"/> </layout> <!-- 只接受NDC标记为funcB的日志 --> <filter class="LoggerFilterNDC"> <param name="value" value="funcB"/> <param name="acceptOnMatch" value="true"/> </filter> </appender> <!-- 保留原有的类日志器配置,比如DB类 --> <logger name="DB"> <level value="debug"/> <!-- 依然可以单独控制DB类的日志级别 --> <appender-ref ref="funcAFileAppender"/> <appender-ref ref="funcBFileAppender"/> </logger> <!-- 根日志器配置(按需调整) --> <root> <level value="info"/> </root>
方案优势
- 无需修改共享类(如DB)的代码,原有的
getLogger()逻辑完全保留,类级别的日志级别控制不受影响。 - 日志分流逻辑由配置文件的过滤器实现,新增函数时只需添加NDC标记和对应的追加器配置,扩展性强。
- NDC是log4系列的标准特性,在log4j、log4perl等其他log4*框架中语法类似,迁移成本低。
可选方案:MDC
如果需要更灵活的键值对上下文,可以使用MDC替代NDC:
- 函数中用
LoggerMDC::put('function', 'funcA')标记,finally中用LoggerMDC::remove('function')清理。 - 配置文件中使用
LoggerFilterMDC过滤器,指定key="function"和value="funcA"即可。
内容的提问来源于stack exchange,提问作者livefree75
相关产品推荐
相关产品推荐

