java.util.loggingのログをStackdriverに出力する(続き)

前回の続き。

曲がりくねった方法をとってしまったが、java.util.loggingの仕様を順に追って検討すればできた。

java.util.loggingのログの出力の設定は、

  • java.util.logging.config.class のシステムプロパティの定義があればそれを参照
  • java.util.logging.config.fileのシステムプロパティの定義があればそれを参照
  • どちらも無ければ ({JRE}/lib/logging.properties) の定義をみにいく

という動きをする。なので java.util.logging.config.class を定義する方法を取った。

LoggingConfig.scala

package com.test

import java.io.InputStream
import java.util.logging._

import ch.qos.logback.core.CoreConstants

class LoggingConfig() {
  try {
    val property: InputStream = getClass.getResourceAsStream("/logging.properties")

    if (property != null) {
      LogManager.getLogManager.readConfiguration(property)
    }
  } catch {
    case e: Exception =>
      e.printStackTrace()
  }
}

class StdOutHandler extends StreamHandler {
  val envLogLevel: Level = sys.env.get("LOG_LEVEL") match {
    case Some("ALL")   => Level.ALL
    case Some("TRACE") => Level.FINEST
    case Some("DEBUG") => Level.CONFIG
    case Some("INFO")  => Level.INFO
    case Some("WARN")  => Level.WARNING
    case Some("ERROR") => Level.SEVERE
    case Some("OFF")   => Level.OFF
    case _             => Level.ALL
  }
  setOutputStream(System.out)
  setLevel(envLogLevel)
  setFormatter(new CustomFormatter)
}

class CustomFormatter extends Formatter {
  override def format(record: LogRecord): String =
    s"""{
       |  "severity" : "${record.getLevel}",
       |  "message" : "(${record.getLoggerName}) ${formatMessage(record)}"
       |}
       |""".stripMargin.replace("\n", "") + CoreConstants.LINE_SEPARATOR
}

logging.properties

handlers=com.test.StdOutHandler
.level=ALL

本当はLoggingConfig.scalaだけで完結させることができるのかもしれないが、どうやればいいのかわからなかったため、一部をlogging.propertiesに残している。 これで、java.util.loggingを使って出力されるログをGCPのStackdriver Loggingに合わせたフォーマットで出力できるようになった。

なお、logbackでやる方法はこちら。

github.com