log4j CustomConfigurationFactory为堆栈跟踪的每一行创建一个新的日志文件?

时间:2017-09-01 11:19:51

标签: java scala log4j

我有以下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"

我希望所有日志都能进入&#39; api&#39;文件,但我得到为堆栈跟踪的每一行创建一个新文件。任何帮助深表感谢。谢谢!

相关:

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

Send log4j2 stack traces over syslog

1 个答案:

答案 0 :(得分:0)

这里的问题是,当通过TCP发送时,断行(&#34; \ n&#34;)被假定为系统日志消息的结束。

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

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

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

我的解决方法是将堆栈跟踪格式化为每行使用除换行符之外的其他内容:

我改变了这个:

@RequestMapping(value = "/updateSums/{id}", method = RequestMethod.GET) 
public String updateFew(@PathVariable String id ,Model model)
{
    EntityManager em = entityManagerFactory.createEntityManager();
    id= id.replace(",", "','");
    id= "'"+id+"'";
    em.getTransaction().begin();
    System.out.println( );
     em.createNativeQuery("update user_Record set email= :uname  where id in ("+id+")", UserRecord.class)
            .setParameter("uname", "shaktimaan@gangadhar.tv")
            .executeUpdate()
            ;

    em.getTransaction().commit();

    return "user_one";
}

到此:

$imgg = "/var/abc/def/product/";
.
.
<img src="data:<?php echo mime_content_type($imgg . $row[2])?>;charset=utf-
8;base64,<?php $image = base64_encode(file_get_contents($imgg . $row[2])); 
echo $image; ?>" alt="" border=3 height=50 width=50/>