log4jdbc source code analysis (1)

        log4jdbc is a jar package used to record database sql. Need to be used with log class .jar. Our company used log4j before. But log4j is said to have performance issues. Finally, we switched to the now more popular logback logging framework. However, an adapted jar package needs to be used in the middle, so the combination is log4jdbc+log4j-over-slfj+logback.

1. How to configure

    The database connection configuration is modified as follows:

 

#driver needs to be configured as the driver class of the adapted log4jdbc
dataSource.driverClass=net.sf.log4jdbc.sql.jdbcapi.DriverSpy

#jdbcUrl needs to add the preceding head:jdbc\:log4
dataSource.jdbcUrl=jdbc\:log4jdbc\:jtds\:sybase\://ip\:port/db;charset\=UTF-8;appname\=appname;

 

    log4jdbc specific configuration - log4jdbc.log4j2.properties:

 

#Configure the real database driver
log4jdbc.drivers=net.sourceforge.jtds.jdbc.Driver
#
log4jdbc.dump.fulldebugstacktrace = false
#Configure to match the path of the package or class that needs to be recorded
log4jdbc.debug.stack.prefix=
#sql maximum line length
log4jdbc.dump.sql.maxlinelength=150
#spy log processing class
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
#warn level log, if the time-consuming time exceeds the configuration value, it will be printed out
log4jdbc.sqltiming.warn.threshold=100
    logback configuration:
<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>
 2. Source tracking

    First, let's take a look at the driver class of the agent -- net.sf.log4jdbc.sql.jdbcapi.DriverSpy

  1. Why does jdbcUrl need to add the preceding 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. Does log4jdbc.log4j.properties only have these properties?

 More than that @~@

// You can know much more than this
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; //Here is a list of what you want to see and see the 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. Where is the connect method of log4jdbc called?

 

    getConnection method of java.sql.DriverManager

 

                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. When was the log recorded?

 

 These are the detected sql_spy classes:

 

public boolean execute(String sql, String[] columnNames) throws SQLException
	{
		String methodCall = "execute(" + sql + ", " + columnNames + ")";
		this.sql = sql;
		reportStatementSql(sql, methodCall); //This place starts to call 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;
		}
	}
 The following is the processing class for printing sql, if you want to assign it according to your standard or log level, you can implement the interface SpyLogDelegator:

 

 

 The above is all my content. I am a young woman in the IT field. Someone asked you how far you want to go in IT? I want to say, as far as others can go, I can too! There is no end!

   

    

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

       

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326943211&siteId=291194637