如何 用slf4j logback 把日志异步记录到数据库中

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何 用slf4j logback 把日志异步记录到数据库中相关的知识,希望对你有一定的参考价值。

参考技术A <!-- 将日志存储到oracle数据库中 -->
<appender name="db-classic-oracle" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
<driverClass>oracle.jdbc.driver.OracleDriver</driverClass>
<url>jdbc:oracle:thin:@localhost:1521:ZYD</url>
<user>scott</user>
<password>tiger</password>
<sqlDialect class="ch.qos.logback.core.db.dialect.OracleDialect" />
</dataSource>
</connectionSource>
<sqlDialect class="ch.qos.logback.core.db.dialect.OracleDialect" />
</appender>

如何不在 Logback 中记录特定类型的异常?

【中文标题】如何不在 Logback 中记录特定类型的异常?【英文标题】:How do I not log a particular type of Exception in Logback? 【发布时间】:2011-09-02 21:20:46 【问题描述】:

如何配置 Logback 以忽略特定类型异常的日志记录?

【问题讨论】:

【参考方案1】:

你可以用一个简单的EvaluatorFilter

<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
    <evaluator>
        <expression>java.lang.RuntimeException.class.isInstance(throwable)</expression>
    </evaluator>
    <onMatch>DENY</onMatch>
</filter>

请注意,您的pom.xml 中还需要以下依赖项:

<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>janino</artifactId>
    <version>2.5.16</version>
</dependency>

另一种可能的解决方案是自定义Filter 实现:

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.ThrowableProxy;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class SampleFilter extends Filter<ILoggingEvent> 

    private Class<?> exceptionClass;

    public SampleFilter() 
    

    @Override
    public FilterReply decide(final ILoggingEvent event) 
        final IThrowableProxy throwableProxy = event.getThrowableProxy();
        if (throwableProxy == null) 
            return FilterReply.NEUTRAL;
        

        if (!(throwableProxy instanceof ThrowableProxy)) 
            return FilterReply.NEUTRAL;
        

        final ThrowableProxy throwableProxyImpl = 
            (ThrowableProxy) throwableProxy;
        final Throwable throwable = throwableProxyImpl.getThrowable();
        if (exceptionClass.isInstance(throwable)) 
            return FilterReply.DENY;
        

        return FilterReply.NEUTRAL;
    

    public void setExceptionClassName(final String exceptionClassName) 
        try 
            exceptionClass = Class.forName(exceptionClassName);
         catch (final ClassNotFoundException e) 
            throw new IllegalArgumentException("Class is unavailable: "
                    + exceptionClassName, e);
        
    

使用适当的配置:

<filter class="hu.palacsint.logbacktest.SampleFilter">
    <exceptionClassName>java.lang.Exception</exceptionClassName>
</filter>

TurboFilteryou get the thrown Throwable instance directly 中,因此您可以调用isInstance 方法,而无需手动将IThrowableProxy 强制转换为ThrowableProxy

Further documentation

【讨论】:

谢谢,我已经解决了这个特定问题,但这是未来的好信息。【参考方案2】:

这个问题已有 5 年历史了,但我提供的解决方案只是为了使其保持最新状态。

我在官方文档中找到了解决方案: http://logback.qos.ch/manual/layouts.html

对于我的特殊情况,这是一个运行普通旧 servlet 的 17 年网站(啊,那些日子),如果用户没有登录,servlet 现在会抛出异常。所以这是我的代码 sn-ps:

Servlet

  try 
    InvalidLoginException.throwIfBadLogin(webUser);

    // main logic here

   catch (InvalidLoginException e) 
    throw e;
   catch (Throwable t) 
    log.error(t);
    throw new UnhandledException(t);
  

web.xml

<error-page>
    <exception-type>com.mycompany.servlet.exception.InvalidLoginException</exception-type>
    <location>/servlet/Login</location>
</error-page>

根据上面的设置,我不想记录此异常,因为它真的不是异常,而是重定向到登录的逻辑中断。

所以,我的 logback.xml 文件的开头是这样的:

  <configuration packagingData="true" scan="true" debug="true" scanPeriod="30 seconds">
    <evaluator name="InvalidLoginExceptionSuppressor">
      <expression>throwable != null &amp;&amp; throwable instanceof com.mycompany.servlet.exception.InvalidLoginException</expression>
    </evaluator>

在 logback.xml 文件的更下方,我的附加程序:

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%dMM-dd HH:mm:ss.SSS %-5level %logger36 - %msg %exfull,InvalidLoginExceptionSuppressor%n</pattern>
      <immediateFlush>false</immediateFlush>
    </encoder>

另外请注意,为了完成这项工作,我必须包含 janino 来处理表达式解析。

【讨论】:

【参考方案3】:

这是@palacsint 响应的另一个示例,当错误不是异常时使用JaninoEventEvaluator:

<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
  <evaluator>
    <expression>logger.equals("org.docx4j.fonts.GlyphCheck") &amp;&amp; level == ERROR</expression>
  </evaluator>
  <onMatch>DENY</onMatch>
</filter>

【讨论】:

如果它是您忽略的记录器,您可以禁用该记录器

以上是关于如何 用slf4j logback 把日志异步记录到数据库中的主要内容,如果未能解决你的问题,请参考以下文章

Logback,SLF4J,Log4J2。了解它们并学习如何使用。(翻译)

踩坑记——使用slf4j+logback记录日志

SLF4J + logback 实现日志输出和记录

SLF4J - 借助SLF4J, 统一适配所有日志实现为logback日志实现的实践

logback怎么异步日志到oracle数据库中

Java# 在项目中使用SLF4J+Logback来记录日志