簡體   English   中英

log4j CustomConfigurationFactory是否為堆棧跟蹤的每一行創建一個新的日志文件?

[英]log4j CustomConfigurationFactory creating a new log file for every line of a stack trace?

我有以下CustomConfigurationFactory。 但是,似乎不僅僅是將所有內容都記錄到一個名為“ api”的文件中,而是似乎正在為堆棧跟蹤的每一行創建一個新的日志文件?

import com.example.api.{LoggingConfig, SyslogConfig}
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.core.LoggerContext
import org.apache.logging.log4j.core.appender.ConsoleAppender
import org.apache.logging.log4j.core.config.builder.api._
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration
import org.apache.logging.log4j.core.config.plugins.Plugin
import org.apache.logging.log4j.core.config.{ConfigurationFactory, ConfigurationSource, Order}

@Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
@Order(50)
class LoggingConfFileConfigurationFactory(loggingConfig: LoggingConfig) extends ConfigurationFactory{


  override def getConfiguration(loggerContext: LoggerContext, source: ConfigurationSource): BuiltConfiguration = {
    getConfiguration(loggerContext, source.toString(), null) 
  }

  override def getConfiguration(loggerContext: LoggerContext, name: String, configLocation: URI): BuiltConfiguration = {
    val builder: ConfigurationBuilder[BuiltConfiguration] = ConfigurationBuilderFactory.newConfigurationBuilder();
    createConfiguration(name, builder);
  }

  override def getSupportedTypes(): Array[String] = {
    Array[String]("*")
  }

  private def createConfiguration(name:String, builder: ConfigurationBuilder[BuiltConfiguration]): BuiltConfiguration = {

    builder.setConfigurationName(name)
    builder.setStatusLevel(Level.ERROR) //internal log4j level of logging

    val consoleAppenderBuilder: AppenderComponentBuilder = builder.newAppender("Stdout", "CONSOLE")
      .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT)
    consoleAppenderBuilder.add(builder.newLayout("PatternLayout")
      .addAttribute("pattern", "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"))

    builder.add(consoleAppenderBuilder)

    if(loggingConfig.appenders.contains("Syslog")) {
      builder.add(createSyslogAppender(loggingConfig.syslogConfig, builder))
    }

    val rootLogger = builder.newRootLogger(Level.valueOf(loggingConfig.level))

    for(appender <- loggingConfig.appenders) {
      rootLogger.add(builder.newAppenderRef(appender))
    }

    for(logger <- loggingConfig.loggers) {
      builder.add(builder.newLogger(logger.name, logger.level))
    }

    builder.add(rootLogger)
    builder.build()
  }

  private def createSyslogAppender(syslogConfig: Option[SyslogConfig], builder: ConfigurationBuilder[BuiltConfiguration]) = {

    val config = syslogConfig match {
      case Some(x) => x
      case None => SyslogConfig("syslog-ng", 515, "api", "LOCAL0")
    }

    val messageFormat = builder.newComponent("KeyValuePair")
    messageFormat.addAttribute("key", "class")
    messageFormat.addAttribute("value", "%logger{36}")

    builder.newAppender("Syslog", "Syslog")
      .addAttribute("format", "RFC5424")
      .addAttribute("host",
        loggingConfig.syslogConfig match {
          case Some(x) => x.host
          case None => "syslog-ng"
        })
      .addAttribute("port", config.port)
      .addAttribute("protocol", "TCP")
      .addAttribute("appName", config.appName)
      .addAttribute("includeMDC", "true")
      .addAttribute("mdcId", "mdc")
      .addAttribute("facility", config.facility)
      .addAttribute("newLine", "true")
      .addAttribute("messageId", "Log")
      .addAttribute("id", config.appName)
      .addComponent(
        builder.newComponent("LoggerFields")
          .addComponent(messageFormat)
      )
  }
}

這是我的application.conf的相關部分,將其作為loggingConfig構造函數參數注入上述類中:

logging = {
  level = "INFO"
  appenders = "Stdout,Syslog"
  syslog = {
    host = "syslog-ng"
    port = 515
    appname = "api"
    facility = "LOCAL0"
  }

這是/ var / log / syslog-ng目錄的一些內容。

ls /var/log/syslog-ng/  

java.lang.Thread.run(Thread.java                                               
slick.jdbc.Invoker.foreach(Invoker.scala
com.mysql.cj.jdbc.PreparedStatement.execute(PreparedStatement.java                                    
slick.jdbc.StatementInvoker.foreach(StatementInvoker.scala
api

這些是我正在使用的log4j的版本:

"org.apache.logging.log4j" % "log4j-api" % "2.8",
"org.apache.logging.log4j" % "log4j-core" % "2.8",
"com.typesafe.scala-logging" %% "scala-logging" % "3.5.0",
"org.apache.logging.log4j" % "log4j-slf4j-impl" % "2.8"

我希望所有日志都進入“ api”文件,但是我正在為堆棧跟蹤的每一行創建一個新文件。 任何幫助深表感謝。 謝謝!

有關:

Log4j2 Syslog追加器(TCP協議)在多行中發送異常stacktrace並調整錯誤的日志級別

通過syslog發送log4j2堆棧跟蹤

這里的問題是,通過TCP發送時,斷行符(“ \\ n”)被認為是syslog消息的結尾。

https://stackoverflow.com/a/40590058/5300930

https://jira.qos.ch/browse/LOGBACK-413

https://github.com/rsyslog/rsyslog/issues/1165

我的解決方法是格式化堆棧跟蹤以對每行使用除換行符以外的內容:

我改變了這個:

logger.error(s"Trace: %s".format(t.getStackTrace.mkString("\n")))

對此:

logger.error(s"Trace: %s".format(t.getStackTrace.mkString(" -> ")))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM