如何在compileInFn及MapGroupCompiler的compileInFn中输出日志信息?
解决compileInFn日志输出及序列化错误问题
嘿,我来帮你搞定这两个日志相关的问题,特别是你遇到的ContextAwareLogger序列化错误的麻烦~
一、从compileInFn中输出日志的基本方法
在compileInFn里输出日志的逻辑和常规代码一致,但这类编译器通常运行在分布式执行环境中,要特别注意序列化兼容性——毕竟你的编译器实例可能会被序列化后分发到不同节点执行。
常规操作步骤:
- 先确保引入了合适的日志依赖(比如SLF4J + 对应的实现包)
- 在编译器类中初始化日志实例,之后直接在
compileInFn方法里调用log.info()/log.debug()等方法即可
二、解决MapGroupCompiler中ContextAwareLogger的序列化错误
你遇到的序列化错误,核心原因是:你的Compiler类作为分布式任务组件,会被序列化传输到工作节点,但ContextAwareLogger的实例(或其内部依赖)没有实现Serializable接口,导致序列化失败。这里有两个可靠的解决方案:
方案1:将Logger标记为transient + lazy val
把日志实例声明为transient(告诉序列化框架跳过该字段),同时用lazy val延迟初始化,这样每个工作节点在第一次使用日志时会重新创建实例,彻底避免序列化问题:
class Compiler(context: DriverContext, compilerConf: CompilerConfig) extends MapGroupCompiler[IntermediateData] with CompileOut1To1Fn[IntermediateData] with LayerDefinitions { // 用transient + lazy val规避序列化问题 private transient lazy val log = new ContextAwareLogger(this.getClass) override def compileInFn(input: Iterator[IntermediateData]): Iterator[IntermediateData] = { // 在这里正常输出调试日志 log.debug("进入compileInFn,当前输入数据量:{}", input.size) // 你的业务逻辑处理... input } }
方案2:使用SLF4J静态Logger(更推荐)
如果ContextAwareLogger本身序列化问题较多,也可以换成SLF4J的标准静态Logger,静态成员不属于实例属性,不会被序列化,从根源解决问题:
import org.slf4j.LoggerFactory class Compiler(context: DriverContext, compilerConf: CompilerConfig) extends MapGroupCompiler[IntermediateData] with CompileOut1To1Fn[IntermediateData] with LayerDefinitions { private val log = LoggerFactory.getLogger(classOf[Compiler]) override def compileInFn(input: Iterator[IntermediateData]): Iterator[IntermediateData] = { log.info("compileInFn开始处理数据") // 你的业务逻辑处理... input } }
补充提醒
不管用哪种方案,都要确保日志配置文件(比如logback.xml/log4j.properties)已经正确部署到所有工作节点,这样日志才能正常输出到指定位置。
内容的提问来源于stack exchange,提问作者Karl Birkkar
相关产品推荐
相关产品推荐

