2017-09-01 32 views
0

我有以下CustomConfigurationFactory。但是,并非只是将所有内容都记录到单个文件中,而是将名称'api'记录下来,它似乎是为堆栈跟踪的每一行创建一个新的日志文件?log4j CustomConfigurationFactory为堆栈跟踪的每一行创建一个新的日志文件?

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 PARAM的相关部分:

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

下面是一些在/ var /日志的内容/ 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

回答

0

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

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(" -> "))) 
相关问题