Search code examples
javakotlinlogginglogbackslf4j

Logback buffer messages before HDD is available


So i have an embeedded java device that runs code as early as possible after boot. But HDD is not available immediately.

I've found out that using logback with xml configuration is not working as whenever it starts it checks for existance of log file which is not possible as HDD is not mounted yet.

So I've programatically added FileAppender when HDD is started. But this results in lots of messages being lost as there is no appender when the device boots and I am unable to get logs from the time when it booted till the HDD is available.

Is there a way to buffer these messages and print them to the file once the HDD is booted?

my way of initing appender:

fun startLogger() {
    logger.debug("Starting HDD logger")
    val lc = LoggerFactory.getILoggerFactory() as LoggerContext
    lc.reset()
    try {
        val root = lc.getLogger(Logger.ROOT_LOGGER_NAME)
        logFileAppender.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@apply)
                it.start()
            }
            start()
        }
        root.addAppender(logFileAppender)

        lc.getLogger(DNSIncoming::class.java).level = Level.WARN
    } catch (e: Exception) {
        logger.error("Error starting log", e)
    }
}

Solution

  • For anyone looking for an answer. I've followed the @kdgregory comment and implemented it this way:

    class MyAppender : RollingFileAppender<ILoggingEvent>() {
        private val buffer = mutableListOf<ILoggingEvent>()
    
        fun initHdd() {
            if (hddInit) return
            try {
                super.openFile(file)
                hddInit = true
                buffer.forEach {
                    append(it)
                }
                buffer.clear()
            } catch (e: Exception) {
            }
        }
    
    
        override fun openFile(file_name: String?): Boolean {
            if (!hddInit) outputStream = NullOutputStream()
            else super.openFile(file_name)
            return true
        }
    
    
        override fun subAppend(event: ILoggingEvent) {
            if (hddInit) super.subAppend(event)
            else {
                if (buffer.size >= MAX_BUFFER_SIZE) return
                buffer.add(event)
            }
        }
    
        companion object {
            private const val MAX_BUFFER_SIZE = 1000;
            private const val MAX_TAG_LENGTH = 23
            var hddInit = false
        }
    }