Added: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/CustomSQLDBReceiver.html URL: http://svn.apache.org/viewvc/logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/CustomSQLDBReceiver.html?view=auto&rev=558362 ============================================================================== --- logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/CustomSQLDBReceiver.html (added) +++ logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/CustomSQLDBReceiver.html Sat Jul 21 10:50:33 2007 @@ -0,0 +1,483 @@ + + + +CustomSQLDBReceiver xref + + + +
View Javadoc
+
+1   /*
+2    * Licensed to the Apache Software Foundation (ASF) under one or more
+3    * contributor license agreements.  See the NOTICE file distributed with
+4    * this work for additional information regarding copyright ownership.
+5    * The ASF licenses this file to You under the Apache License, Version 2.0
+6    * (the "License"); you may not use this file except in compliance with
+7    * the License.  You may obtain a copy of the License at
+8    * 
+9    *      http://www.apache.org/licenses/LICENSE-2.0
+10   * 
+11   * Unless required by applicable law or agreed to in writing, software
+12   * distributed under the License is distributed on an "AS IS" BASIS,
+13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+14   * See the License for the specific language governing permissions and
+15   * limitations under the License.
+16   */
+17  
+18  package org.apache.log4j.db;
+19  
+20  import java.sql.Connection;
+21  import java.sql.ResultSet;
+22  import java.sql.SQLException;
+23  import java.sql.Statement;
+24  import java.util.Hashtable;
+25  import java.util.StringTokenizer;
+26  import java.util.Properties;
+27  
+28  import org.apache.log4j.Level;
+29  import org.apache.log4j.Logger;
+30  import org.apache.log4j.xml.UnrecognizedElementHandler;
+31  import org.apache.log4j.xml.DOMConfigurator;
+32  import org.apache.log4j.plugins.Pauseable;
+33  import org.apache.log4j.plugins.Receiver;
+34  import org.apache.log4j.scheduler.Job;
+35  import org.apache.log4j.scheduler.Scheduler;
+36  import org.apache.log4j.spi.LoggingEvent;
+37  import org.apache.log4j.spi.LoggerRepositoryEx;
+38  import org.apache.log4j.spi.ThrowableInformation;
+39  import org.apache.log4j.spi.LocationInfo;
+40  import org.apache.log4j.spi.OptionHandler;
+41  import org.w3c.dom.Element;
+42  
+43  /***
+44   * Converts log data stored in a database into LoggingEvents.
+45   * <p>
+46   * <b>NOTE:</b> This receiver cannot yet be created through Chainsaw's receiver panel.  
+47   * It must be created through an XML configuration file.
+48   * <p>
+49   * This receiver supports database configuration via ConnectionSource, in the
+50   * org.apache.log4j.db package: DriverManagerConnectionSource,
+51   * DataSourceConnectionSource, JNDIConnectionSource
+52   * <p>
+53   * This database receiver differs from DBReceiver in that this receiver relies
+54   * on custom SQL to retrieve logging event data, where DBReceiver requires the
+55   * use of a log4j-defined schema.
+56   * <p>
+57   * A 'refreshMillis' int parameter controls SQL execution. If 'refreshMillis' is
+58   * zero (the default), the receiver will run only one time. If it is set to any
+59   * other numeric value, the SQL will be executed on a recurring basis every
+60   * 'refreshMillis' milliseconds.
+61   * <p>
+62   * The receiver closes the connection and acquires a new connection on each 
+63   * execution of the SQL (use pooled connections if possible).
+64   * <p>
+65   * If the SQL will be executing on a recurring basis, specify the IDField param -
+66   * the column name holding the unique identifier (int) representing the logging
+67   * event.
+68   * <p>
+69   * As events are retrieved, the column represented by IDField is examined and
+70   * the largest value is held and used by the next execution of the SQL statement
+71   * to avoid retrieving previously processed events.
+72   * <p>
+73   * As an example, the IDField references a 'COUNTER' (int, auto-increment,
+74   * unique) column. The first execution of the SQL statement returns 500 rows,
+75   * with a final value in the COUNTER field of 500.
+76   * <p>
+77   * The SQL statement is manipulated prior to the next execution, adding ' WHERE
+78   * COUNTER > 500' to the statement to avoid retrieval of previously processed
+79   * events.
+80   * <p>
+81   * The select statement must provide ALL fields which define a LoggingEvent.
+82   * <p>
+83   * The SQL statement MUST include the columns: LOGGER, TIMESTAMP, LEVEL, THREAD,
+84   * MESSAGE, NDC, MDC, CLASS, METHOD, FILE, LINE, PROPERTIES, EXCEPTION
+85   * <p>
+86   * Use ' AS ' in the SQL statement to alias the SQL's column names to match your
+87   * database schema. (see example below).
+88   * <p>
+89   * Include all fields in the SQL statement, even if you don't have data for the
+90   * field (specify an empty string as the value for columns which you don't have
+91   * data).
+92   * <p>
+93   * The TIMESTAMP column must be a datetime.
+94   * <p>
+95   * Both a PROPERTIES column and an MDC column are supported. These fields
+96   * represent Maps on the logging event, but require the use of string
+97   * concatenation database functions to hold the (possibly multiple) name/value
+98   * pairs in the column.
+99   * <p>
+100  * For example, to include both 'userid' and 'lastname' properties in the
+101  * logging event (from either the PROPERTIES or MDC columns), the name/value
+102  * pairs must be concatenated together by your database.
+103  * <p>
+104  * The resulting PROPERTIES or MDC column must have data in this format: {{name,
+105  * value, name2, value2}}
+106  * <p>
+107  * The resulting PROPERTIES column would contain this text: {{userid, someone,
+108  * lastname, mylastname}}
+109  * <p>
+110  * Here is an example of concatenating a PROPERTIES or MDC column using MySQL's
+111  * concat function, where the 'application' and 'hostname' parameters were fixed
+112  * text, but the 'log4jid' key's value is the value of the COUNTER column:
+113  * <p>
+114  * concat("{{application,databaselogs,hostname,mymachine,log4jid,", COUNTER,
+115  * "}}") as PROPERTIES
+116  * <p>
+117  * log4jid is a special property that is used by Chainsaw to represent an 'ID'
+118  * field. Specify this property to ensure you can map events in Chainsaw to
+119  * events in the database if you need to go back and view events at a later time
+120  * or save the events to XML for later analysis.
+121  * <p>
+122  * Here is a complete MySQL SQL statement which can be used to provide events to
+123  * Chainsaw:
+124  * <p>
+125  * select logger as LOGGER, timestamp as TIMESTAMP, level as LEVEL, thread as
+126  * THREAD, message as MESSAGE, ndc as NDC, mdc as MDC, class as CLASS, method as
+127  * METHOD, file as FILE, line as LINE,
+128  * concat("{{application,databaselogs,hostname,mymachine, log4jid,",
+129  * COUNTER,"}}") as PROPERTIES, "" as EXCEPTION from logtable
+130  * <p>
+131  * @author Scott Deboy <sdeboy@apache.org>
+132  * <p>
+133  */
+134 public class CustomSQLDBReceiver extends Receiver implements Pauseable, UnrecognizedElementHandler {
+135 
+136     protected volatile Connection connection = null;
+137 
+138     protected String sqlStatement = "";
+139 
+140     /***
+141      * By default we refresh data every 1000 milliseconds.
+142      * 
+143      * @see #setRefreshMillis
+144      */
+145     static int DEFAULT_REFRESH_MILLIS = 1000;
+146 
+147     int refreshMillis = DEFAULT_REFRESH_MILLIS;
+148 
+149     protected String idField = null;
+150 
+151     int lastID = -1;
+152 
+153     private static final String WHERE_CLAUSE = " WHERE ";
+154 
+155     private static final String AND_CLAUSE = " AND ";
+156 
+157     private boolean whereExists = false;
+158 
+159     private boolean paused = false;
+160 
+161     private ConnectionSource connectionSource;
+162 
+163     public static final String LOG4J_ID_KEY = "log4jid";
+164 
+165     private Job customReceiverJob;
+166 
+167     public void activateOptions() {
+168       
+169       if(connectionSource == null)  {
+170         throw new IllegalStateException(
+171           "CustomSQLDBReceiver cannot function without a connection source");
+172       }
+173       whereExists = (sqlStatement.toUpperCase().indexOf(WHERE_CLAUSE) > -1);
+174     
+175       customReceiverJob = new CustomReceiverJob();
+176         
+177       if(this.repository == null) {
+178         throw new IllegalStateException(
+179         "CustomSQLDBReceiver cannot function without a reference to its owning repository");
+180       }
+181      
+182     
+183 
+184       if (repository instanceof LoggerRepositoryEx) {
+185         Scheduler scheduler = ((LoggerRepositoryEx) repository).getScheduler();
+186       
+187         scheduler.schedule(
+188           customReceiverJob, System.currentTimeMillis() + 500, refreshMillis);
+189       }
+190 
+191     }
+192 
+193     void closeConnection(Connection connection) {
+194         if (connection != null) {
+195             try {
+196                 // LogLog.warn("closing the connection. ", new Exception("x"));
+197                 connection.close();
+198             } catch (SQLException sqle) {
+199                 // nothing we can do here
+200             }
+201         }
+202     }
+203 
+204     public void setRefreshMillis(int refreshMillis) {
+205         this.refreshMillis = refreshMillis;
+206     }
+207 
+208     public int getRefreshMillis() {
+209         return refreshMillis;
+210     }
+211 
+212     /***
+213      * @return Returns the connectionSource.
+214      */
+215     public ConnectionSource getConnectionSource() {
+216         return connectionSource;
+217     }
+218 
+219     /***
+220      * @param connectionSource
+221      *            The connectionSource to set.
+222      */
+223     public void setConnectionSource(ConnectionSource connectionSource) {
+224         this.connectionSource = connectionSource;
+225     }
+226 
+227     public void close() {
+228         try {
+229             if ((connection != null) && !connection.isClosed()) {
+230                 connection.close();
+231             }
+232         } catch (SQLException e) {
+233             e.printStackTrace();
+234         } finally {
+235             connection = null;
+236         }
+237     }
+238 
+239     public void finalize() throws Throwable {
+240         super.finalize();
+241         close();
+242     }
+243 
+244     /*
+245      * (non-Javadoc)
+246      * 
+247      * @see org.apache.log4j.plugins.Plugin#shutdown()
+248      */
+249     public void shutdown() {
+250         getLogger().info("removing receiverJob from the Scheduler.");
+251 
+252         if(this.repository instanceof LoggerRepositoryEx) {
+253           Scheduler scheduler = ((LoggerRepositoryEx) repository).getScheduler();
+254           scheduler.delete(customReceiverJob);
+255         }
+256 
+257         lastID = -1;
+258     }
+259 
+260     public void setSql(String s) {
+261         sqlStatement = s;
+262     }
+263 
+264     public String getSql() {
+265         return sqlStatement;
+266     }
+267 
+268     public void setIDField(String id) {
+269         idField = id;
+270     }
+271 
+272     public String getIDField() {
+273         return idField;
+274     }
+275 
+276     public synchronized void setPaused(boolean p) {
+277         paused = p;
+278     }
+279 
+280     public synchronized boolean isPaused() {
+281         return paused;
+282     }
+283 
+284     class CustomReceiverJob implements Job {
+285         public void execute() {
+286             Connection connection = null;
+287 
+288             int oldLastID = lastID;
+289             try {
+290                 connection = connectionSource.getConnection();
+291                 Statement statement = connection.createStatement();
+292 
+293                 Logger eventLogger = null;
+294                 long timeStamp = 0L;
+295                 String level = null;
+296                 String threadName = null;
+297                 Object message = null;
+298                 String ndc = null;
+299                 Hashtable mdc = null;
+300                 String[] exception = null;
+301                 String className = null;
+302                 String methodName = null;
+303                 String fileName = null;
+304                 String lineNumber = null;
+305                 Hashtable properties = null;
+306 
+307                 String currentSQLStatement = sqlStatement;
+308                 if (whereExists) {
+309                     currentSQLStatement = sqlStatement + AND_CLAUSE + idField
+310                             + " > " + lastID;
+311                 } else {
+312                     currentSQLStatement = sqlStatement + WHERE_CLAUSE + idField
+313                             + " > " + lastID;
+314                 }
+315 
+316                 ResultSet rs = statement.executeQuery(currentSQLStatement);
+317 
+318                 int i = 0;
+319                 while (rs.next()) {
+320                     // add a small break every 1000 received events
+321                     if (++i == 1000) {
+322                         synchronized (this) {
+323                             try {
+324                                 // add a delay
+325                                 wait(300);
+326                             } catch (InterruptedException ie) {
+327                             }
+328                             i = 0;
+329                         }
+330                     }
+331                     eventLogger = Logger.getLogger(rs.getString("LOGGER"));
+332                     timeStamp = rs.getTimestamp("TIMESTAMP").getTime();
+333 
+334                     level = rs.getString("LEVEL");
+335                     threadName = rs.getString("THREAD");
+336                     message = rs.getString("MESSAGE");
+337                     ndc = rs.getString("NDC");
+338 
+339                     String mdcString = rs.getString("MDC");
+340                     mdc = new Hashtable();
+341 
+342                     if (mdcString != null) {
+343                         // support MDC being wrapped in {{name, value}}
+344                         // or
+345                         // just name, value
+346                         if ((mdcString.indexOf("{{") > -1)
+347                                 && (mdcString.indexOf("}}") > -1)) {
+348                             mdcString = mdcString
+349                                     .substring(mdcString.indexOf("{{") + 2,
+350                                             mdcString.indexOf("}}"));
+351                         }
+352 
+353                         StringTokenizer tok = new StringTokenizer(mdcString,
+354                                 ",");
+355 
+356                         while (tok.countTokens() > 1) {
+357                             mdc.put(tok.nextToken(), tok.nextToken());
+358                         }
+359                     }
+360 
+361                     exception = new String[] { rs.getString("EXCEPTION") };
+362                     className = rs.getString("CLASS");
+363                     methodName = rs.getString("METHOD");
+364                     fileName = rs.getString("FILE");
+365                     lineNumber = rs.getString("LINE");
+366 
+367                     // if properties are provided in the
+368                     // SQL they can be used here (for example, to route
+369                     // events to a unique tab in
+370                     // Chainsaw if the machinename and/or appname
+371                     // property
+372                     // are set)
+373                     String propertiesString = rs.getString("PROPERTIES");
+374                     properties = new Hashtable();
+375 
+376                     if (propertiesString != null) {
+377                         // support properties being wrapped in {{name,
+378                         // value}} or just name, value
+379                         if ((propertiesString.indexOf("{{") > -1)
+380                                 && (propertiesString.indexOf("}}") > -1)) {
+381                             propertiesString = propertiesString.substring(
+382                                     propertiesString.indexOf("{{") + 2,
+383                                     propertiesString.indexOf("}}"));
+384                         }
+385 
+386                         StringTokenizer tok2 = new StringTokenizer(
+387                                 propertiesString, ",");
+388                         while (tok2.countTokens() > 1) {
+389                             String name = tok2.nextToken();
+390                             String value = tok2.nextToken();
+391                             if (name.equals(LOG4J_ID_KEY)) {
+392                                 try {
+393                                     int thisInt = Integer.parseInt(value);
+394                                     value = String.valueOf(thisInt);
+395                                     if (thisInt > lastID) {
+396                                         lastID = thisInt;
+397                                     }
+398                                 } catch (Exception e) {
+399                                 }
+400                             }
+401                             properties.put(name, value);
+402                         }
+403                     }
+404 
+405                     Level levelImpl = Level.toLevel(level);
+406 
+407 
+408 					LocationInfo locationInfo = new LocationInfo(fileName,
+409 	                            className, methodName, lineNumber);
+410 	
+411 					ThrowableInformation throwableInfo =  new ThrowableInformation(
+412 		                            exception);
+413 	
+414 					properties.putAll(mdc);
+415 		
+416 				    LoggingEvent event = new LoggingEvent(eventLogger.getName(),
+417 				            eventLogger, timeStamp, levelImpl, message,
+418 				            threadName,
+419 				            throwableInfo,
+420 				            ndc,
+421 				            locationInfo,
+422 				            properties);
+423 
+424                     doPost(event);
+425                 }
+426                 //log when rows are retrieved
+427                 if (lastID != oldLastID) {
+428                     getLogger().debug("lastID: " + lastID);
+429                     oldLastID = lastID;
+430                 }
+431 
+432                 statement.close();
+433                 statement = null;
+434             } catch (SQLException sqle) {
+435                 getLogger()
+436                         .error("*************Problem receiving events", sqle);
+437             } finally {
+438                 closeConnection(connection);
+439             }
+440 
+441             // if paused, loop prior to executing sql query
+442             synchronized (this) {
+443                 while (isPaused()) {
+444                     try {
+445                         wait(1000);
+446                     } catch (InterruptedException ie) {
+447                     }
+448                 }
+449             }
+450         }
+451     }
+452 
+453     /***
+454      * @{inheritDoc}
+455      */
+456   public boolean parseUnrecognizedElement(Element element, Properties props) throws Exception {
+457         if ("connectionSource".equals(element.getNodeName())) {
+458             Object instance =
+459                     DOMConfigurator.parseElement(element, props, ConnectionSource.class);
+460             if (instance instanceof ConnectionSource) {
+461                ConnectionSource source = (ConnectionSource) instance;
+462                source.activateOptions();
+463                setConnectionSource(source);
+464             }
+465             return true;
+466         }
+467         return false;
+468   }
+469     
+470 }
+
+
+ + Propchange: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/CustomSQLDBReceiver.html ------------------------------------------------------------------------------ svn:mime-type = text/html Added: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBAppender.html URL: http://svn.apache.org/viewvc/logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBAppender.html?view=auto&rev=558362 ============================================================================== --- logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBAppender.html (added) +++ logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBAppender.html Sat Jul 21 10:50:33 2007 @@ -0,0 +1,413 @@ + + + +DBAppender xref + + + +
View Javadoc
+
+1   /*
+2    * Licensed to the Apache Software Foundation (ASF) under one or more
+3    * contributor license agreements.  See the NOTICE file distributed with
+4    * this work for additional information regarding copyright ownership.
+5    * The ASF licenses this file to You under the Apache License, Version 2.0
+6    * (the "License"); you may not use this file except in compliance with
+7    * the License.  You may obtain a copy of the License at
+8    *
+9    *      http://www.apache.org/licenses/LICENSE-2.0
+10   *
+11   * Unless required by applicable law or agreed to in writing, software
+12   * distributed under the License is distributed on an "AS IS" BASIS,
+13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+14   * See the License for the specific language governing permissions and
+15   * limitations under the License.
+16   */
+17  
+18  package org.apache.log4j.db;
+19  
+20  import org.apache.log4j.AppenderSkeleton;
+21  import org.apache.log4j.db.dialect.SQLDialect;
+22  import org.apache.log4j.db.dialect.Util;
+23  import org.apache.log4j.helpers.LogLog;
+24  import org.apache.log4j.spi.LocationInfo;
+25  import org.apache.log4j.spi.LoggingEvent;
+26  import org.apache.log4j.xml.DOMConfigurator;
+27  import org.apache.log4j.xml.UnrecognizedElementHandler;
+28  import org.w3c.dom.Element;
+29  
+30  import java.lang.reflect.InvocationTargetException;
+31  import java.lang.reflect.Method;
+32  import java.sql.Connection;
+33  import java.sql.PreparedStatement;
+34  import java.sql.ResultSet;
+35  import java.sql.SQLException;
+36  import java.sql.Statement;
+37  import java.util.Iterator;
+38  import java.util.Properties;
+39  import java.util.Set;
+40  
+41  
+42  /***
+43   * The DBAppender inserts loggin events into three database tables in a format
+44   * independent of the Java programming language. The three tables that
+45   * DBAppender inserts to must exists before DBAppender can be used. These tables
+46   * may be created with the help of SQL scripts found in the
+47   * <em>src/java/org/apache/log4j/db/dialect</em> directory. There is a
+48   * specific script for each of the most popular database systems. If the script
+49   * for your particular type of database system is missing, it should be quite
+50   * easy to write one, taking example on the already existing scripts. If you
+51   * send them to us, we will gladly include missing scripts in future releases.
+52   *
+53   * <p>
+54   * If the JDBC driver you are using supports the
+55   * {@link java.sql.Statement#getGeneratedKeys}method introduced in JDBC 3.0
+56   * specification, then you are all set. Otherwise, there must be an
+57   * {@link SQLDialect}appropriate for your database system. Currently, we have
+58   * dialects for PostgreSQL, MySQL, Oracle and MsSQL. As mentioed previously, an
+59   * SQLDialect is required only if the JDBC driver for your database system does
+60   * not support the {@link java.sql.Statement#getGeneratedKeys getGeneratedKeys}
+61   * method.
+62   * </p>
+63   *
+64   * <table border="1" cellpadding="4">
+65   * <tr>
+66   * <th>RDBMS</th>
+67   * <th>supports <br/><code>getGeneratedKeys()</code> method</th>
+68   * <th>specific <br/>SQLDialect support</th>
+69   * <tr>
+70   * <tr>
+71   * <td>PostgreSQL</td>
+72   * <td align="center">NO</td>
+73   * <td>present and used</td>
+74   * <tr>
+75   * <tr>
+76   * <td>MySQL</td>
+77   * <td align="center">YES</td>
+78   * <td>present, but not actually needed or used</td>
+79   * <tr>
+80   * <tr>
+81   * <td>Oracle</td>
+82   * <td align="center">YES</td>
+83   * <td>present, but not actually needed or used</td>
+84   * <tr>
+85   * <tr>
+86   * <td>DB2</td>
+87   * <td align="center">YES</td>
+88   * <td>not present, and not needed or used</td>
+89   * <tr>
+90   * <tr>
+91   * <td>MsSQL</td>
+92   * <td align="center">YES</td>
+93   * <td>not present, and not needed or used</td>
+94   * <tr>
+95   * <tr>
+96   *   <td>HSQL</td>
+97   *    <td align="center">NO</td>
+98   *    <td>present and used</td>
+99   * <tr>
+100  *
+101  * </table>
+102  * <p>
+103  * <b>Performance: </b> Experiments show that writing a single event into the
+104  * database takes approximately 50 milliseconds, on a "standard" PC. If pooled
+105  * connections are used, this figure drops to under 10 milliseconds. Note that
+106  * most JDBC drivers already ship with connection pooling support.
+107  * </p>
+108  *
+109  *
+110  *
+111  * <p>
+112  * <b>Configuration </b> DBAppender can be configured programmatically, or using
+113  * {@link org.apache.log4j.xml.DOMConfigurator JoranConfigurator}. Example
+114  * scripts can be found in the <em>tests/input/db</em> directory.
+115  *
+116  * @author Ceki G&uuml;lc&uuml;
+117  * @author Ray DeCampo
+118  * @since 1.3
+119  */
+120 public class DBAppender extends AppenderSkeleton implements UnrecognizedElementHandler {
+121   static final String insertPropertiesSQL =
+122     "INSERT INTO  logging_event_property (event_id, mapped_key, mapped_value) VALUES (?, ?, ?)";
+123   static final String insertExceptionSQL =
+124     "INSERT INTO  logging_event_exception (event_id, i, trace_line) VALUES (?, ?, ?)";
+125   static final String insertSQL;
+126   private static final Method GET_GENERATED_KEYS_METHOD;
+127 
+128 
+129   static {
+130     StringBuffer sql = new StringBuffer();
+131     sql.append("INSERT INTO logging_event (");
+132     sql.append("sequence_number, ");
+133     sql.append("timestamp, ");
+134     sql.append("rendered_message, ");
+135     sql.append("logger_name, ");
+136     sql.append("level_string, ");
+137     sql.append("ndc, ");
+138     sql.append("thread_name, ");
+139     sql.append("reference_flag, ");
+140     sql.append("caller_filename, ");
+141     sql.append("caller_class, ");
+142     sql.append("caller_method, ");
+143     sql.append("caller_line) ");
+144     sql.append(" VALUES (?, ?, ? ,?, ?, ?, ?, ?, ?, ?, ?, ?)");
+145     insertSQL = sql.toString();
+146     //
+147     //   PreparedStatement.getGeneratedKeys added in JDK 1.4
+148     //
+149     Method getGeneratedKeysMethod;
+150     try {
+151         getGeneratedKeysMethod = PreparedStatement.class.getMethod("getGeneratedKeys", null);
+152     } catch(Exception ex) {
+153         getGeneratedKeysMethod = null;
+154     }
+155     GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod;
+156   }
+157 
+158   ConnectionSource connectionSource;
+159   boolean cnxSupportsGetGeneratedKeys = false;
+160   boolean cnxSupportsBatchUpdates = false;
+161   SQLDialect sqlDialect;
+162   boolean locationInfo = false;
+163   
+164 
+165   public DBAppender() {
+166       super(false);
+167   }
+168 
+169   public void activateOptions() {
+170     LogLog.debug("DBAppender.activateOptions called");
+171 
+172     if (connectionSource == null) {
+173       throw new IllegalStateException(
+174         "DBAppender cannot function without a connection source");
+175     }
+176 
+177     sqlDialect = Util.getDialectFromCode(connectionSource.getSQLDialectCode());
+178     if (GET_GENERATED_KEYS_METHOD != null) {
+179         cnxSupportsGetGeneratedKeys = connectionSource.supportsGetGeneratedKeys();
+180     } else {
+181         cnxSupportsGetGeneratedKeys = false;
+182     }
+183     cnxSupportsBatchUpdates = connectionSource.supportsBatchUpdates();
+184     if (!cnxSupportsGetGeneratedKeys && (sqlDialect == null)) {
+185       throw new IllegalStateException(
+186         "DBAppender cannot function if the JDBC driver does not support getGeneratedKeys method *and* without a specific SQL dialect");
+187     }
+188     
+189     // all nice and dandy on the eastern front
+190     super.activateOptions();
+191   }
+192 
+193   /***
+194    * @return Returns the connectionSource.
+195    */
+196   public ConnectionSource getConnectionSource() {
+197     return connectionSource;
+198   }
+199 
+200   /***
+201    * @param connectionSource
+202    *          The connectionSource to set.
+203    */
+204   public void setConnectionSource(ConnectionSource connectionSource) {
+205     LogLog.debug("setConnectionSource called for DBAppender");
+206     this.connectionSource = connectionSource;
+207   }
+208 
+209   protected void append(LoggingEvent event) {
+210       Connection connection = null;
+211       try {
+212           connection = connectionSource.getConnection();
+213           connection.setAutoCommit(false);
+214           
+215           PreparedStatement insertStatement =
+216               connection.prepareStatement(insertSQL);
+217 
+218 /*          insertStatement.setLong(1, event.getSequenceNumber());*/
+219 		  insertStatement.setLong(1, 0);
+220 		
+221           insertStatement.setLong(2, event.getTimeStamp());
+222           insertStatement.setString(3, event.getRenderedMessage());
+223           insertStatement.setString(4, event.getLoggerName());
+224           insertStatement.setString(5, event.getLevel().toString());
+225           insertStatement.setString(6, event.getNDC());
+226           insertStatement.setString(7, event.getThreadName());
+227           insertStatement.setShort(8, DBHelper.computeReferenceMask(event));
+228           
+229           LocationInfo li;
+230           
+231           if (event.locationInformationExists() || locationInfo) {
+232               li = event.getLocationInformation();
+233           } else {
+234               li = LocationInfo.NA_LOCATION_INFO;
+235           }
+236           
+237           insertStatement.setString(9, li.getFileName());
+238           insertStatement.setString(10, li.getClassName());
+239           insertStatement.setString(11, li.getMethodName());
+240           insertStatement.setString(12, li.getLineNumber());
+241           
+242           int updateCount = insertStatement.executeUpdate();
+243           if (updateCount != 1) {
+244               LogLog.warn("Failed to insert loggingEvent");
+245           }
+246           
+247           ResultSet rs = null;
+248           Statement idStatement = null;
+249           boolean gotGeneratedKeys = false;
+250           if (cnxSupportsGetGeneratedKeys) {
+251               try {
+252                   rs = (ResultSet) GET_GENERATED_KEYS_METHOD.invoke(insertStatement, null);
+253                   gotGeneratedKeys = true;
+254               } catch(InvocationTargetException ex) {
+255                   Throwable target = ex.getTargetException();
+256                   if (target instanceof SQLException) {
+257                       throw (SQLException) target;
+258                   }
+259                   throw ex; 
+260               } catch(IllegalAccessException ex) {
+261                   LogLog.warn("IllegalAccessException invoking PreparedStatement.getGeneratedKeys", ex);
+262               }
+263           }
+264           
+265           if (!gotGeneratedKeys) {
+266               insertStatement.close();
+267               insertStatement = null;
+268               
+269               idStatement = connection.createStatement();
+270               idStatement.setMaxRows(1);
+271               rs = idStatement.executeQuery(sqlDialect.getSelectInsertId());
+272           }
+273           
+274           // A ResultSet cursor is initially positioned before the first row; the 
+275           // first call to the method next makes the first row the current row
+276           rs.next();
+277           int eventId = rs.getInt(1);
+278           
+279           rs.close();
+280 
+281           // we no longer need the insertStatement
+282           if(insertStatement != null) {
+283               insertStatement.close();
+284               insertStatement = null;
+285           }
+286 
+287           if(idStatement != null) {
+288               idStatement.close();
+289               idStatement = null;
+290           }
+291 
+292           Set propertiesKeys = event.getPropertyKeySet();
+293           
+294           if (propertiesKeys.size() > 0) {
+295               PreparedStatement insertPropertiesStatement =
+296                   connection.prepareStatement(insertPropertiesSQL);
+297               
+298               for (Iterator i = propertiesKeys.iterator(); i.hasNext();) {
+299                   String key = (String) i.next();
+300                   String value = (String) event.getProperty(key);
+301                   
+302                   //LogLog.info("id " + eventId + ", key " + key + ", value " + value);
+303                   insertPropertiesStatement.setInt(1, eventId);
+304                   insertPropertiesStatement.setString(2, key);
+305                   insertPropertiesStatement.setString(3, value);
+306                   
+307                   if (cnxSupportsBatchUpdates) {
+308                       insertPropertiesStatement.addBatch();
+309                   } else {
+310                       insertPropertiesStatement.execute();
+311                   }
+312               }
+313               
+314               if (cnxSupportsBatchUpdates) {
+315                   insertPropertiesStatement.executeBatch();
+316               }
+317               
+318               insertPropertiesStatement.close();
+319               insertPropertiesStatement = null;
+320           }
+321           
+322           String[] strRep = event.getThrowableStrRep();
+323           
+324           if (strRep != null) {
+325               LogLog.debug("Logging an exception");
+326               
+327               PreparedStatement insertExceptionStatement =
+328                   connection.prepareStatement(insertExceptionSQL);
+329               
+330               for (short i = 0; i < strRep.length; i++) {
+331                   insertExceptionStatement.setInt(1, eventId);
+332                   insertExceptionStatement.setShort(2, i);
+333                   insertExceptionStatement.setString(3, strRep[i]);
+334                   if (cnxSupportsBatchUpdates) {
+335                       insertExceptionStatement.addBatch();
+336                   } else {
+337                       insertExceptionStatement.execute();
+338                   }
+339               }
+340               if (cnxSupportsBatchUpdates) {
+341                   insertExceptionStatement.executeBatch();
+342               }
+343               insertExceptionStatement.close();
+344               insertExceptionStatement = null;
+345           }
+346           
+347           connection.commit();
+348       } catch (Throwable sqle) {
+349           LogLog.error("problem appending event", sqle);
+350       } finally {
+351           DBHelper.closeConnection(connection);
+352       }
+353   }
+354 
+355   public void close() {
+356     closed = true;
+357   }
+358 
+359   /***
+360    * Returns value of the <b>LocationInfo </b> property which determines whether
+361    * caller's location info is written to the database.
+362    */
+363   public boolean getLocationInfo() {
+364     return locationInfo;
+365   }
+366 
+367   /***
+368    * If true, the information written to the database will include caller's
+369    * location information. Due to performance concerns, by default no location
+370    * information is written to the database.
+371    */
+372   public void setLocationInfo(boolean locationInfo) {
+373     this.locationInfo = locationInfo;
+374   }
+375 
+376     /***
+377      * Gets whether appender requires a layout.
+378      * @return false
+379      */
+380   public boolean requiresLayout() {
+381       return false;
+382   }
+383 
+384     /***
+385      * @{inheritDoc}
+386      */
+387   public boolean parseUnrecognizedElement(Element element, Properties props) throws Exception {
+388         if ("connectionSource".equals(element.getNodeName())) {
+389             Object instance =
+390                     DOMConfigurator.parseElement(element, props, ConnectionSource.class);
+391             if (instance instanceof ConnectionSource) {
+392                ConnectionSource source = (ConnectionSource) instance;
+393                source.activateOptions();
+394                setConnectionSource(source);
+395             }
+396             return true;
+397         }
+398         return false;
+399   }
+400 }
+
+
+ + Propchange: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBAppender.html ------------------------------------------------------------------------------ svn:mime-type = text/html Added: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBHelper.html URL: http://svn.apache.org/viewvc/logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBHelper.html?view=auto&rev=558362 ============================================================================== --- logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBHelper.html (added) +++ logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBHelper.html Sat Jul 21 10:50:33 2007 @@ -0,0 +1,81 @@ + + + +DBHelper xref + + + +
View Javadoc
+
+1   /*
+2    * Licensed to the Apache Software Foundation (ASF) under one or more
+3    * contributor license agreements.  See the NOTICE file distributed with
+4    * this work for additional information regarding copyright ownership.
+5    * The ASF licenses this file to You under the Apache License, Version 2.0
+6    * (the "License"); you may not use this file except in compliance with
+7    * the License.  You may obtain a copy of the License at
+8    * 
+9    *      http://www.apache.org/licenses/LICENSE-2.0
+10   * 
+11   * Unless required by applicable law or agreed to in writing, software
+12   * distributed under the License is distributed on an "AS IS" BASIS,
+13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+14   * See the License for the specific language governing permissions and
+15   * limitations under the License.
+16   */
+17  
+18  package org.apache.log4j.db;
+19  
+20  import java.sql.Connection;
+21  import java.sql.SQLException;
+22  import java.sql.Statement;
+23  import java.util.Set;
+24  
+25  import org.apache.log4j.spi.LoggingEvent;
+26  
+27  /***
+28   * @author Ceki G&uuml;lc&uuml;
+29   *
+30   */
+31  public class DBHelper {
+32    
+33    public final static short PROPERTIES_EXIST = 0x01;
+34    public final static short EXCEPTION_EXISTS = 0x02;
+35    
+36    public  static short computeReferenceMask(LoggingEvent event) {
+37      short mask = 0;
+38      Set propertiesKeys = event.getPropertyKeySet();
+39      if(propertiesKeys.size() > 0) {
+40        mask = PROPERTIES_EXIST;
+41      }
+42      String[] strRep = event.getThrowableStrRep();
+43      if(strRep != null) {
+44        mask |= EXCEPTION_EXISTS;
+45      }
+46      return mask;
+47    }
+48    
+49    static public void closeConnection(Connection connection) {
+50      if(connection != null) {
+51        try { 
+52          connection.close();
+53        } catch(SQLException sqle) {
+54          // static utility classes should not log without an explicit repository
+55          // reference
+56        }
+57      }
+58    }
+59    
+60    public static void closeStatement(Statement statement) {
+61      if(statement != null) {
+62        try {
+63          statement.close();
+64        } catch(SQLException sqle) {
+65        }
+66      }
+67    }
+68  }
+
+
+ + Propchange: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/db/DBHelper.html ------------------------------------------------------------------------------ svn:mime-type = text/html