You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在HDD就绪前用Logback缓冲日志消息并写入文件?

解决嵌入式设备Logback开机日志丢失问题

针对你遇到的HDD未就绪前日志丢失问题,以下是几种直接可行的解决方案,结合你的代码场景优先推荐内存缓冲+动态切换Appender的实现方式:

方案1:用CyclicBufferAppender临时缓冲,就绪后转存并切换

Logback内置的CyclicBufferAppender可在内存中缓冲指定数量的日志事件,等HDD就绪后,将缓冲日志写入FileAppender,再切换为文件输出作为主要日志通道。

实现步骤:

  1. 开机初始化阶段,先启动缓冲Appender作为临时输出:
// 开机时先初始化缓冲日志
fun initTemporaryLogger() {
    val lc = LoggerFactory.getILoggerFactory() as LoggerContext
    lc.reset()
    val root = lc.getLogger(Logger.ROOT_LOGGER_NAME)
    
    val bufferAppender = CyclicBufferAppender<ILoggingEvent>().apply {
        context = lc
        name = "bufferAppender"
        bufferSize = 1000 // 根据设备内存和日志量调整缓冲上限
        start()
    }
    root.addAppender(bufferAppender)
    
    // 保留原有日志级别配置
    lc.getLogger(DNSIncoming::class.java).level = Level.WARN
}
  1. 检测到HDD就绪后,在startLogger()中完成日志转存和Appender切换:
fun startLogger() {
    logger.debug("Starting HDD logger")
    val lc = LoggerFactory.getILoggerFactory() as LoggerContext
    val root = lc.getLogger(Logger.ROOT_LOGGER_NAME)
    
    try {
        // 初始化原有的FileAppender
        val logFileAppender = FileAppender<ILoggingEvent>().apply {
            context = lc
            name = "logFile"
            file = "/mnt/hdd/cz.myq.roger.ricoh/logs/logfile.log"
            encoder = PatternLayoutEncoder().apply {
                context = lc
                pattern = "%-12date{yyyy-MM-dd HH:mm:ss.SSS} %logger{12} %-5level - %msg%n"
                start()
            }
            isAppend = true
            rollingPolicy = TimeBasedRollingPolicy<ILoggingEvent>().apply {
                context = lc
                fileNamePattern = "/mnt/hdd/cz.myq.roger.ricoh/logs/logfile-%d{yyyy-MM-dd}.log.zip"
                maxHistory = 7
                setTotalSizeCap(FileSize.valueOf("100MB"))
            }.also {
                it.setParent(this)
                it.start()
            }
            start()
        }
        
        // 转存缓冲中的日志到文件
        val bufferAppender = lc.getAppender("bufferAppender") as CyclicBufferAppender<ILoggingEvent>
        bufferAppender.getCopyOfAllElements().forEach { logFileAppender.doAppend(it) }
        
        // 切换根Logger的Appender
        root.detachAppender(bufferAppender)
        root.addAppender(logFileAppender)
        
        // 清理缓冲Appender
        bufferAppender.stop()
    } catch (e: Exception) {
        logger.error("Error starting log", e)
    }
}

方案2:自定义缓冲Appender(灵活度更高)

如果需要更灵活的缓冲策略(比如带内存阈值保护、支持临时存储到RAM盘),可以自定义Appender维护日志队列:

class BufferedFileAppender : UnsynchronizedAppenderBase<ILoggingEvent>() {
    private val eventQueue = ConcurrentLinkedQueue<ILoggingEvent>()
    private var delegateFileAppender: FileAppender<ILoggingEvent>? = null
    private var isHDDReady = false
    private val MAX_BUFFER_SIZE = 2000 // 内存缓冲上限

    // HDD就绪后调用此方法启动文件输出
    fun initFileAppender(lc: LoggerContext) {
        delegateFileAppender = FileAppender<ILoggingEvent>().apply {
            context = lc
            name = "delegateLogFile"
            file = "/mnt/hdd/cz.myq.roger.ricoh/logs/logfile.log"
            encoder = PatternLayoutEncoder().apply {
                context = lc
                pattern = "%-12date{yyyy-MM-dd HH:mm:ss.SSS} %logger{12} %-5level - %msg%n"
                start()
            }
            isAppend = true
            rollingPolicy = TimeBasedRollingPolicy<ILoggingEvent>().apply {
                context = lc
                fileNamePattern = "/mnt/hdd/cz.myq.roger.ricoh/logs/logfile-%d{yyyy-MM-dd}.log.zip"
                maxHistory = 7
                setTotalSizeCap(FileSize.valueOf("100MB"))
            }.also {
                it.setParent(this)
                it.start()
            }
            start()
        }
        isHDDReady = true
        // 批量写入缓冲的日志
        while (eventQueue.isNotEmpty()) {
            delegateFileAppender?.doAppend(eventQueue.poll())
        }
    }

    override fun append(event: ILoggingEvent) {
        if (isHDDReady) {
            delegateFileAppender?.doAppend(event)
        } else {
            if (eventQueue.size < MAX_BUFFER_SIZE) {
                eventQueue.offer(event)
            } else {
                // 缓冲满时可选择丢弃或写入RAM盘
                logger.warn("Log buffer full, dropping event: ${event.message}")
            }
        }
    }
}

使用时,开机先初始化这个自定义Appender,HDD就绪后调用initFileAppender()即可。

关键注意事项

  • 缓冲容量需结合设备内存大小合理设置,避免内存溢出;
  • 若设备配有RAM盘,可优先将临时日志写入RAM盘,HDD就绪后再迁移,比纯内存缓冲更安全;
  • 确保HDD就绪的检测逻辑可靠,避免重复初始化Appender。

内容的提问来源于stack exchange,提问作者Mazmart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 00:55:14