【问题标题】:log4j CustomConfigurationFactory creating a new log file for every line of a stack trace?log4j CustomConfigurationFactory 为堆栈跟踪的每一行创建一个新的日志文件?
【发布时间】:2018-02-10 10:55:03
【问题描述】:

我有以下 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 appender(TCP protocol) sending exception stacktrace in multiple line and shwoing wrong log levels

Send log4j2 stack traces over syslog

【问题讨论】:

    标签: java scala log4j


    【解决方案1】:

    这里的问题是,当通过 TCP 发送时,换行符(“\n”)被假定为系统日志消息的结尾。

    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(" -> ")))
    

    【讨论】:

      猜你喜欢
      • 2014-02-03
      • 1970-01-01
      • 2023-01-20
      • 1970-01-01
      • 2013-11-11
      • 1970-01-01
      • 1970-01-01
      • 2012-01-29
      • 1970-01-01
      相关资源
      最近更新 更多