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

发布于 2024-08-17 14:56:52 字数 613 浏览 2 评论 0原文

我正在尝试将日志消息保存到中央数据库。为了做到这一点,我在 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 失败。

有没有简单的方法可以做到这一点?

I'm trying to save log messages to a central database. In order to do this, I configured the following Appender in log4j's xml configuration:

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

This works fine, except some of the messages contain ', and then the appender fails.

Is there an easy way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

瑾兮 2024-08-24 14:56:52

我建议创建一个自定义附加程序并覆盖 flushBufferexecute 方法,您可以在其中转义字符串或使用 PreparedStatement

public class MyJDBCAppender extends JDBCAppender {

}

解释为什么需要覆盖flushBuffer - 附加程序将LogEvent对象放入缓冲区中,该缓冲区稍后会刷新到目标(在本例中为数据库)。此处,flushBuffer 方法使用 getLogStatement 和(通过execute)普通的 Statement。您可以完全替换该行为。查看当前源代码

然后注册您的appender,而不是JDBCAppender

I'd suggest creating a custom appender and overriding the flushBuffer and execute methods where you can escape your strings or use PreparedStatement :

public class MyJDBCAppender extends JDBCAppender {

}

To explain why you need to override flushBuffer - the appender puts LogEvent objects into a buffer which is later flushed towards the target (database in this case). Here, the flushBuffer method uses getLogStatement and (via execute) a normal Statement. You can replace that behaviour completely. Have a look a the current source code

Then register your appender istead of JDBCAppender.

萤火眠眠 2024-08-24 14:56:52

看看这个非官方的 Log4J JDBCAppender 它修复了这个问题并在阿帕奇 2.0 许可证。引用其功能与org.apache.log4j.jdbc.JDBCAppender进行比较:

  • 记录到(关系)数据库
  • 灵活的连接处理(尚不支持数据源)
  • 灵活的 sql 命令来执行实际日志记录
  • 支持准备好的语句和存储过程(J2SDK 1.4+)
  • 允许记录带有特殊字符的消息,例如 '(单个
    引用)和,(逗号)
  • 灵活的表和列结构
  • 灵活的 ID 生成
  • 允许多个 PatternLayout 应用程序;在一个或多个
    栏目
  • 支持 J2SDK 1.3、1.4 和 1.5
  • 支持 Log4j 1.2.9 和当前开发

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

Have a look at this non official Log4J JDBCAppender which fixes this issue and is distributed under the Apache 2.0 license. Quoting its features in comparision to org.apache.log4j.jdbc.JDBCAppender:

  • Log to (relational) database
  • Flexible connection handling (does not yet support DataSource)
  • Flexible sql commands to execute actual logging
  • Prepared Statements and Stored Procedures (J2SDK 1.4+) supported
  • Enables logging of messages with special characters such as ' (single
    quote) and , (comma)
  • Flexible table and column structure
  • Flexible id generation
  • Multiple PatternLayout applications allowed; in one or more
    columns
  • Supports J2SDK 1.3, 1.4 and 1.5
  • Supports Log4j 1.2.9 and current development

Or, and you should seriously consider this option, switch from log4j to its successor, logback (this is where things happen) which has a DBAppender that uses PreparedStatement (see the sources), that can use a JNDI datasource, connection pooling (this is a big plus), etc. For more information about this appender, refer to the online manual http://logback.qos.ch/manual/appenders.html#DBAppender

不顾 2024-08-24 14:56:52

我不熟悉 log4j 或 JDBC,但我知道 JDBC 支持准备好的语句。也许有一种方法可以将其与 JDBCAppender 一起使用

I'm not familiar with log4j or JDBC, but I do know JDBC supports prepared statements. Perhaps there is a way to use that with the JDBCAppender

前事休说 2024-08-24 14:56:52

我通过以下方式解决了这个问题:

复制名为 ACMEJDBCAppenderJDBCAppender 源代码

覆盖 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);
}

i solved the thing in the following way :

Copied the source code of the JDBCAppender called ACMEJDBCAppender

override the getLogStatement(LoggingEvent event) method, cloning the old event and providing the new one with the escaped message.

Not the cleanest solution from the oop point of view but it does the work. Hope it helps.

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);
}
那小子欠揍 2024-08-24 14:56:52

根据 Javadocs,官方的JDBCAppender功能相当有限,尤其是没有很好的方法来处理这个问题。

解决这个问题的一种方法是使用替代的附加程序,例如这个,其目的是在功能上与 Log4J 兼容,但工作除外。

As per the Javadocs, the offical JDBCAppender is quite limited, and in particular has no good way of dealing with this issue.

One way around it is to use an alternative appender, such as this one which aims to be functionally compatible with the Log4J one except, you know, work.

原来分手还会想你 2024-08-24 14:56:52

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

将引号运算符括在 %m 周围(即 q#'%m'#)

例如:

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

To get around this problem logging to Oracle, you can use Oracle's quote operator.

Wrap the quote operator around %m (i.e. q#'%m'#)

For example:

INSERT INTO log_messages ( log_level, message, log_date ) 
VALUES ( '%p', q#'%m'#, '%d{yyyy-MM-dd HH:mm:ss}' )
愿与i 2024-08-24 14:56:52

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>

希望有帮助!

Joao, sorry for being late, but here it is:

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

Hope it helps!

溺孤伤于心 2024-08-24 14:56:52

如果您使用的是 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;

命令将问题转移到双引号上。如果您的消息中没有双引号,这可以解决问题。

If you are using SQL server you can use the following

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;

Which shifts the problem to double quotes. If you don't have double quotes in your messages this could solve the problem.

神爱温柔 2024-08-24 14:56:52

对于 postgresql,使用 $$

示例:$$%m$$

For postgresql, use $$

Example: $$%m$$

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文