If a parent handler in wvlet.log.AsyncHandler throws an exception when parent.publish(record) is called in a poller thread, that poller thread silently dies and stops producing any logs.
We've encountered this issue because we use custom LogFormatter which was throwing an NPE in some rare cases. Here's a test case that emulates this issue
object FlakyFormatter extends LogFormatter {
override def formatLog(r: LogRecord): String = {
if (r.getMessage == "boom") {
throw new RuntimeException("boom!")
} else {
r.getMessage
}
}
}
test("keep writing logs if parent is flaky") {
val buf = new BufferedLogHandler(FlakyFormatter)
val l1 = "l1"
val l2 = "l2"
val l3 = "boom"
val l4 = "l4"
val logs =
withResource(new AsyncHandler(buf)) { h =>
val logger = Logger("internal.asyncerrortest")
logger.resetHandler(h)
logger.setLogLevel(LogLevel.ALL)
logger.info(l1)
logger.info(l2)
logger.info(l3)
logger.info(l4)
Thread.sleep(1000) // wait for the background thread to process the logs
buf.logs
}
logs.size shouldBe 3
logs(0).contains(l1) shouldBe true
logs(1).contains(l2) shouldBe true
logs(2).contains(l4) shouldBe true
}
It seems wvlet.airframe.log.AsyncHandler for Scala 3 is also affected.
I guess the fix is straightforward (wrap parent.publish(record) into Try(..) or try ... catch ...), but I'm not sure about what to do with a LogRecord that caused an error. So I decided to create an issue instead
If a parent handler in
wvlet.log.AsyncHandlerthrows an exception whenparent.publish(record)is called in a poller thread, that poller thread silently dies and stops producing any logs.We've encountered this issue because we use custom LogFormatter which was throwing an NPE in some rare cases. Here's a test case that emulates this issue
It seems
wvlet.airframe.log.AsyncHandlerfor Scala 3 is also affected.I guess the fix is straightforward (wrap
parent.publish(record)intoTry(..)ortry ... catch ...), but I'm not sure about what to do with aLogRecordthat caused an error. So I decided to create an issue instead