很早以前弄过将log4j的日志存储到数据库,不过是配置在properties文件,包括数据库配置也是写死的。现在正好有个需求要把日志存储到数据库中,还要进行过滤,只有本项目的才会进行保存,像Spring,mybatis,zookeeper这类的日志不需要进行保存,而且现在配置是动态的,根据不同的环境,有不同的数据库,而使用properties达不到这么灵活的效果,只能把properties改为使用xml来配置,但是好多例子在xml也是写死的数据库配置,如果想达到动态配置,需要依赖一个logback扩展jar。
文档地址:https://github.com/qos-ch/logback-extensions/wiki/Spring,
先增加maven依赖:
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.4</version>
</dependency>
logback.xml如下,配置的比较简单,还没配置输出到文件:
<?xml version="1.0"?>
<configuration>
<!-- 这里的appender为扩展的appender -->
<appender name="consoleAppender" class="ch.qos.logback.ext.spring.DelegatingLogbackAppender"/>
<!-- 日志级别 -->
<root>
<level value="error" />
<level value="info" />
<appender-ref ref="consoleAppender" />
</root>
</configuration>
下面开始整合,使用的Spring的xml形式:
在web.xml中增加监听器配置,如下:
<listener>
<listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>
<context-param>
<param-name>logbackConfigLocation</param-name>
<param-value>classpath:logback.xml</param-value>
</context-param>
文档中给出spring的bean配置类为:
ch.qos.logback.core.ConsoleAppender
但是这个类没有支持过滤器配置,所以建一个类,继承ConsoleAppender,如下:
import ch.qos.logback.core.filter.Filter;
import java.util.List;
public class ConsoleAppender extends ch.qos.logback.core.ConsoleAppender {
private List<Filter> filters;
public List<Filter> getFilters() {
return filters;
}
public void setFilters(List<Filter> filters) {
this.filters = filters;
if (this.filters != null) {
for (Filter filter : filters) {
addFilter(filter);
}
}
}
}
过滤器支持多个,所以使用List,在setFilters方法中遍历,将过滤器添加上,
下面为spring的xml配置:
<bean class="ch.qos.logback.ext.spring.ApplicationContextHolder"/>
<bean id="consoleAppender" class="com.system.web.log.ConsoleAppender" init-method="start" destroy-method="stop">
<property name="context" value="#{ T(org.slf4j.LoggerFactory).getILoggerFactory() }"/>
<property name="encoder">
<bean class="ch.qos.logback.classic.encoder.PatternLayoutEncoder" init-method="start" destroy-method="stop">
<property name="context" value="#{ T(org.slf4j.LoggerFactory).getILoggerFactory() }"/>
<property name="pattern" value="[%p][%d{yyyy-MM-dd HH:mm:ss,SSS}][%c:%L]%m%n"/>
</bean>
</property>
<property name="filters">
<list>
<bean class="com.system.web.filter.LogFilter"/>
</list>
</property>
</bean>
LogFilter类代码为:
import ch.qos.logback.classic.spi.LoggerContextVO;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;
import com.system.dao.log.Log;
import com.system.service.log.LogService;
import org.slf4j.Marker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Map;
public class LogFilter extends Filter<LoggingEvent> {
//日志保存的Service
@Autowired
private LogService LogService;
@Override
public FilterReply decide(LoggingEvent event) {
String loggerName = event.getLoggerName();
/**
* 项目本身的日志才会进行保存
*/
if (loggerName.startsWith("com.system")) {
Log log = new Log();
log.setClazzName(loggerName);
Date date = new Date(event.getTimeStamp());
log.setLogTimestamp(date);
log.setCreateTime(date);
log.setUpdateTime(date);
/**
* 使用toString,会带有日志级别
*/
log.setMessage(event.toString());
/**
* 保存日志,使用Spring的异步执行
*/
LogService.asyncSave(log);
}
return FilterReply.ACCEPT;
}
}
使用Spring的xml配置到此结束。
异常情况处理:
本地启动项目时是没问题的,日志也能进行保存,但是部署到测试环境出现了如下异常:
java.lang.ClassCastException:org.slf4j.impl.Log4jLoggerFactory
cannot be cast to ch.qos.logback.classic.LoggerContext,
通过使用IDEA查看pom文件的依赖树,发现zookeeper依赖了slf4j-log4j12,也同样实现了ILoggerFactory接口,但是没有实现Context接口,导致类转换失败,将依赖去掉即可,不影响项目的正常运行,如下:
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>