2017-09-01 1 views
0

Ich habe die folgende CustomConfigurationFactory. Anstatt nur alles in einer einzigen Datei zu protokollieren, nenne es "api", scheint es eine neue Protokolldatei für jede Zeile eines Stack-Trace zu erstellen.log4j CustomConfigurationFactory Erstellen einer neuen Protokolldatei für jede Zeile eines Stack-Trace?

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) 
    ) 
    } 
} 

Hier ist der relevante Teil meiner application.conf, die in der obigen Klasse, die als loggingConfig Konstruktor param injiziert wird: sind

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

Hier sind einige der Inhalte des/var/log/syslog-ng-Verzeichnis.

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 

Dies sind die Versionen von log4j Ich verwende:

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

ich alle Protokolle erwarten in den ‚api‘ Datei zu gehen, sondern stattdessen eine neue Datei für jeden Ich erhalte erstellt Linie einer Stapelspur. Jede Hilfe wird sehr geschätzt. Vielen Dank!

Verwandte:

Log4j2 Syslog appender(TCP protocol) sending exception stacktrace in multiple line and shwoing wrong log levels

und

Send log4j2 stack traces over syslog

Antwort

0

Das Problem hierbei war, dass Zeilenumbrüche ("\ n") angenommen das Ende einer Syslog-Nachricht sein, wenn gesendet über TCP.

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

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

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

Meine Abhilfe war zu formatieren Stapel Spuren etwas anderes als Linie zu verwenden, bricht für jede Zeile:

ich dies geändert:

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

zu diesem:

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