Вывести идентификатор приложения Spark в журналы с Log4j - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть специальный файл Log4j для приложения Spark.Я хотел бы вывести идентификатор приложения Spark вместе с другими атрибутами, такими как сообщение и дата, чтобы строковая структура JSON выглядела так:

{"name":,"time":,"date":,"level":,"thread":,"message":,"app_id":}

Теперь эта структура выглядит следующим образом:

{"name":,"time":,"date":,"level":,"thread":,"message":}

Как определить такой макет для журналов драйверов Spark?

Мой файл log4j выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>

    <appender name="Json" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.hadoop.log.Log4Json">
            <param name="ConversionLayout" value=""/>
        </layout>
    </appender>

    <root>
        <level value="INFO"/>
        <appender-ref ref="Json"/>
    </root>
</log4j:configuration>

1 Ответ

0 голосов
/ 15 февраля 2019

Я сомневаюсь, что org.apache.hadoop.log.Log4Json можно настроить для этой цели.В соответствии с его javadoc и исходным кодом, он может быть довольно громоздким.

Хотя похоже, что вы используете Log4j 1x, его API довольно гибок, и мы можем легко определить наш собственный макет, расширив org.apache.log4j.Layout. * 1005.*

Нам потребуется класс case, который будет преобразован в JSON в соответствии с целевой структурой:

case class LoggedMessage(name: String,
                         appId: String,
                         thread: String,
                         time: Long,
                         level: String,
                         message: String)

И Layout может быть расширен следующим образом.Чтобы получить доступ к значению "app_id", мы будем использовать сопоставленный диагностический контекст Log4j

import org.apache.log4j.Layout
import org.apache.log4j.spi.LoggingEvent
import org.json4s.DefaultFormats
import org.json4s.native.Serialization.write

class JsonLoggingLayout extends Layout {
  // required by the API
  override def ignoresThrowable(): Boolean = false
  // required by the API
  override def activateOptions(): Unit = { /* nothing */ }

  override def format(event: LoggingEvent): String = {
    // we are using json4s for JSON serialization
    implicit val formats = DefaultFormats

    // retrieve app_id from Mapped Diagnostic Context
    val appId = event.getMDC("app_id") match {
      case null => "[no_app]" // logged messages outside our app
      case defined: AnyRef => defined.toString
    }
    val message = LoggedMessage("TODO",
                                appId,
                                Thread.currentThread().getName,
                                event.getTimeStamp,
                                event.getLevel.toString,
                                event.getMessage.toString)
    write(message) + "\n"
  }

}

Наконец, когда создается сеанс Spark, мы помещаем значение app_id в MDC:

import org.apache.log4j.{Logger, MDC}

// create Spark session

MDC.put("app_id", session.sparkContext.applicationId)

logger.info("-------- this is info --------")
logger.warn("-------- THIS IS A WARNING --------")
logger.error("-------- !!! ERROR !!! --------")

При этом создаются следующие журналы:

{"name":"TODO","appId":"local-1550247707920","thread":"main","time":1550247708149,"level":"INFO","message":"-------- this is info --------"}
{"name":"TODO","appId":"local-1550247707920","thread":"main","time":1550247708150,"level":"WARN","message":"-------- THIS IS A WARNING --------"}
{"name":"TODO","appId":"local-1550247707920","thread":"main","time":1550247708150,"level":"ERROR","message":"-------- !!! ERROR !!! --------"}

И, конечно же, не забудьте сослаться на реализацию в log4j config xml:

<appender name="Json" class="org.apache.log4j.ConsoleAppender">
  <layout class="stackoverflow.q54706582.JsonLoggingLayout" />
</appender>
...