如何清理Log4j中的日志消息以将其保存在数据库中

时间:2010-01-11 13:25:00

标签: java jdbc log4j

我正在尝试将日志消息保存到中央数据库。为此,我在log4j的xml配置中配置了以下Appender:

<appender name="DB" class="org.apache.log4j.jdbc.JDBCAppender">
            <param name="URL" value="jdbc:postgresql://localhost/logging_test" />
            <param name="user" value="test_user" />
            <param name="password" value="test_password" />
            <param name="sql" value="INSERT INTO log_messages ( log_level, message, log_date ) VALUES ( '%p', '%m', '%d{yyyy-MM-dd HH:mm:ss}' )" />
</appender>

这样可以正常工作,除了一些消息包含',然后appender失败。

有一种简单的方法吗?

9 个答案:

答案 0 :(得分:6)

我建议您创建一个自定义appender并覆盖flushBufferexecute方法,您可以在这些方法中转义字符串或使用PreparedStatement

public class MyJDBCAppender extends JDBCAppender {

}

要解释为什么需要覆盖flushBuffer - appender将LogEvent个对象放入缓冲区,稍后将其刷回目标(在本例中为数据库)。此处,flushBuffer方法使用getLogStatement和(通过execute)正常Statement。您可以完全替换该行为。看看the current source code

然后注册你的appender而不是JDBCAppender

答案 1 :(得分:3)

我不熟悉log4j或JDBC,但我知道JDBC支持预处理语句。也许有一种方法可以将它与JDBCAppender一起使用

答案 2 :(得分:3)

看看这个解决此问题的非官方Log4J JDBCAppender,并在Apache 2.0许可下发布。在与org.apache.log4j.jdbc.JDBCAppender

的比较中引用其功能
  
      
  • 登录(关系)数据库
  •   
  • 灵活的连接处理(尚不支持DataSource)
  •   
  • 用于执行实际记录的灵活sql命令
  •   
  • 支持预备语句和存储过程(J2SDK 1.4+)
  •   
  • 启用具有特殊字符的消息记录,例如'(单个   引用)和(逗号)
  •   
  • 灵活的表格和列结构
  •   
  • 灵活的ID生成
  •   
  • 允许多个PatternLayout应用程序;在一个或多个   列
  •   
  • 支持J2SDK 1.3,1.4和1.5
  •   
  • 支持Log4j 1.2.9和当前开发
  •   

或者,你应该认真考虑这个选项,从log4j切换到它的继任者logback(这是发生的事情),DBAppender使用PreparedStatement(参见sources),可以使用JNDI数据源,连接池(这是一个很大的优点),等等。有关此appender的更多信息,请参阅在线手册http://logback.qos.ch/manual/appenders.html#DBAppender

答案 3 :(得分:3)

我用以下方式解决了问题:

复制了名为JDBCAppender

ACMEJDBCAppender的源代码

覆盖getLogStatement(LoggingEvent event)方法,克隆旧事件并为新事件提供转义邮件。

从oop的角度来看,这不是最干净的解决方案,但它可以完成工作。希望它有所帮助。

protected String getLogStatement(LoggingEvent event) {

  LoggingEvent clone = new LoggingEvent(
    event.fqnOfCategoryClass,
    LogManager.getLogger(event.getLoggerName()),
    event.getLevel(),
    AidaUtils.sqlEscape(event.getMessage().toString()),
    event.getThrowableInformation()!=null ? event.getThrowableInformation().getThrowable() : null
  );

  return getLayout().format(clone);
}

答案 4 :(得分:1)

根据Javadocs,官方JDBCAppender非常有限,特别是没有办法处理这个问题。

另一种方法是使用替代的appender,例如this one,其目的是在功能上与Log4J兼容,除此之外,你工作。

答案 5 :(得分:1)

要解决此问题,请记录到Oracle,您可以使用Oracle的报价运算符。

将报价运算符包裹在%m附近(即q#'%m'#)

例如:

INSERT INTO log_messages ( log_level, message, log_date ) 
VALUES ( '%p', q#'%m'#, '%d{yyyy-MM-dd HH:mm:ss}' )

答案 6 :(得分:0)

Joao,抱歉迟到了,但现在是:

<appender name="DB" class="org.apache.log4j.db.DBAppender">                                                                                                             
                <connectionSource class="org.apache.log4j.db.DriverManagerConnectionSource">                                                                                       
                        <param name="driverClass" value="org.postgresql.Driver" />                                                                                                 
                        <param name="url" value="jdbc:postgresql://localhost/database" />                                                                                      
                        <param name="user" value="user" />                                                                                                                          
                        <param name="password" value="password" />                                                                                                                 
                </connectionSource>                                                                                                                                                
                <layout class="org.apache.log4j.PatternLayout">                                                                                                                    
                        <param name="ConversionPattern" value="%d %-5p [%t] %c - %m%n" />                                                                                          
                </layout>                                                                                                                                                          
        </appender>

希望它有所帮助!

答案 7 :(得分:0)

如果您使用的是SQL Server,可以使用以下

SET QUOTED_IDENTIFIER OFF;
INSERT INTO log_messages ( log_level, message, log_date ) VALUES ( "%p", ":%m", "%d{yyyy-MM-dd HH:mm:ss}" )'
SET QUOTED_IDENTIFIER OFF;

将问题转换为双引号。如果您的消息中没有双引号,则可以解决问题。

答案 8 :(得分:0)

对于postgresql,请使用$$

示例:$$%m $$