log4jdbc是用来记录数据库sql的jar包。需要与log类.jar一起使用。之前我们公司使用的是log4j。但是据说log4j有性能问题。最后我们换用了现在比较流行的logback日志框架。但是,中间需要用适配的jar包,所以组合为log4jdbc+log4j-over-slfj+logback。
一、如何配置
数据库连接配置修改如下:
#driver需要配置为适配的log4jdbc的驱动类
dataSource.driverClass=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
#jdbcUrl需要增加前面的head:jdbc\:log4
dataSource.jdbcUrl=jdbc\:log4jdbc\:jtds\:sybase\://ip\:port/db;charset\=UTF-8;appname\=appname;
log4jdbc特有的配置-log4jdbc.log4j2.properties:
#配置真实的数据库驱动
log4jdbc.drivers=net.sourceforge.jtds.jdbc.Driver
#
log4jdbc.dump.fulldebugstacktrace=false
#配置为需要记录的包或类匹配路径
log4jdbc.debug.stack.prefix=
#sql的最大占行长度
log4jdbc.dump.sql.maxlinelength=150
#spy日志处理类
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
#warn级别的日志,时间耗时超过配置值的会打印出来
log4jdbc.sqltiming.warn.threshold=100
logback配置:
<appender name="jdbcfile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${baseHome}/${appname}_jdbc_${ip}_${port}.log</File>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] [%-5thread] %logger{20} -
%msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>warn</level>
</filter>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${baseHome}/${appname}_jdbc_${ip}_${port}.%d{yyyy-MM-dd}(%i).log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>200MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<logger name="jdbc.sqltiming" level="warn" additivity="false">
<appender-ref ref="jdbcfile" />
</logger>
二、源码跟踪
首先,我们先看看代理的驱动类--net.sf.log4jdbc.sql.jdbcapi.DriverSpy
1.为什么jdbcUrl需要增加前面的head:jdbc\:log4?
/**
* A <code>String</code> representing the prefix of URL
* to use log4jdbc.
*/
static final private String log4jdbcUrlPrefix = "jdbc:log4";
/**
* Get the actual URL that the real driver expects
* (strip off <code>#log4jdbcUrlPrefix</code> from <code>url</code>).
*
* @param url A <code>String</code> corresponding to a JDBC url for log4jdbc.
* @return A <code>String</code> representing url
* with <code>#log4jdbcUrlPrefix</code> stripped off.
*/
private String getRealUrl(String url)
{
return url.substring(log4jdbcUrlPrefix.length());
}
2.log4jdbc.log4j.properties只有这几个属性吗?
不止呢@~@
//你可以知道的远不止这些
public final class Properties
{
private static volatile SpyLogDelegator log;
/**
* A <code>String</code> representing the name of the class implementing
* <code>SpyLogDelegator</code> to use. It is used by {@link SpyLogFactory}
* to determine which class to load.
* Default is <code>net.sf.log4jdbc.log4j2.Log4j2SpyLogDelegator</code>
*
* @see SpyLogFactory
*/
static final String SpyLogDelegatorName; //这里就先列一个想看的自己看看properties
/**
* Static initializer.
*/
static
{
//first we init the logger
log = null;
//then we need the properties to define which logger to use
java.util.Properties props = getProperties();
SpyLogDelegatorName = props.getProperty("log4jdbc.spylogdelegator.name");//。。。。。
}
private static java.util.Properties getProperties()
{
java.util.Properties props = new java.util.Properties(System.getProperties());
//try to get the properties file.
//default name is log4jdbc.log4j2.properties
//check first if an alternative name has been provided in the System properties
String propertyFile = props.getProperty("log4jdbc.log4j2.properties.file",
"/log4jdbc.log4j2.properties");
if (log != null) {
log.debug("Trying to use properties file " + propertyFile);
}
InputStream propStream = Properties.class.getResourceAsStream(propertyFile);
if (propStream != null) {
try {
props.load(propStream);
} catch (IOException e) {
if (log != null) {
log.debug("Error when loading log4jdbc.log4j2.properties from classpath: " +
e.getMessage());
}
} finally {
try {
propStream.close();
} catch (IOException e) {
if (log != null) {
log.debug("Error when closing log4jdbc.log4j2.properties file" +
e.getMessage());
}
}
}
if (log != null) {
log.debug("log4jdbc.logj2.properties loaded from classpath");
}
} else {
if (log != null) {
log.debug("log4jdbc.logj2.properties not found in classpath. Using System properties.");
}
}
return props;
}
}
3.是哪调用的log4jdbc的connect方法呢?
java.sql.DriverManager的getConnection方法
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
4.什么时候记录的日志的?
这些都是检测的sql_spy类:
public boolean execute(String sql, String[] columnNames) throws SQLException
{
String methodCall = "execute(" + sql + ", " + columnNames + ")";
this.sql = sql;
reportStatementSql(sql, methodCall); //这个地方开始调用Slf4jSpyLogDelegator
long tstart = System.currentTimeMillis();
try
{
boolean result = realStatement.execute(sql, columnNames);
reportStatementSqlTiming(System.currentTimeMillis() - tstart, sql, methodCall);//2
return reportReturn(methodCall, result);//3
}
catch (SQLException s)
{
reportException(methodCall, s, sql, System.currentTimeMillis() - tstart);
throw s;
}
}
以下是打印sql的处理类,如果你想按照你的标准或是日志级别分配的话,你可以实现接口SpyLogDelegator:
以上是我的全部内容。我是游走在IT届的小女子,有人问你想在IT走多远?我想说,别人能走多远,我同样能!没有终点!