sdeboy 2003/06/05 22:33:04 Modified: src/java/org/apache/log4j/jdbc JDBCReceiver.java Log: Updated JDBCReceiver documentation. What doesn't work: * Can't reconstruct the event's timestamp if patternlayout's timestamp was used to store the data - ISO8601DateFormat can't convert the string back to a date. * No exception support in jdbcappender * No properties support in patternlayout However, both fields are supported in the receiver, so users can add properties to the SQL statement if they want events routed to unique tabs in Chainsaw V2). Revision Changes Path 1.2 +89 -15 jakarta-log4j-sandbox/src/java/org/apache/log4j/jdbc/JDBCReceiver.java Index: JDBCReceiver.java =================================================================== RCS file: /home/cvs/jakarta-log4j-sandbox/src/java/org/apache/log4j/jdbc/JDBCReceiver.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- JDBCReceiver.java 5 Jun 2003 05:19:05 -0000 1.1 +++ JDBCReceiver.java 6 Jun 2003 05:33:04 -0000 1.2 @@ -70,6 +70,48 @@ import java.util.StringTokenizer; +/** + * Convert Log data stored in a database into LoggingEvents. + * + * This receiver executes the SQL statement defined in the plugin configuration once, + * converting the rows it finds into LoggingEvents, and then ends. + * + * The configuration of this plugin is very similar to the JDBCAppender, however a + * SELECT statement must be provided instead of an INSERT statement. + * + * The select statement must provide all fields which define a LoggingEvent, with + * the column names matching this list: LOGGER, TIMESTAMP, LEVEL, THREAD, MESSAGE, + * NDC, MDC, CLASS, METHOD, FILE, LINE, PROPERTIES, EXCEPTION + * + * If the source table doesn't provide a column for any of the fields, the field must + * still be provided in the SELECT statement. For example, if a JDBCAppender was used + * to write only a timestamp, level and patternlayout combination of message and other + * fields, here is a sample SQL statement you would provide as the plugin 'sql' param: + * + * param name="sql" value='select "" as LOGGER, timestamp as TIMESTAMP, level as LEVEL, + * "" as THREAD, message as MESSAGE, "" as NDC, "" as MDC, "" as CLASS, "" as METHOD, + * "" as FILE, "" as LINE, "{{log4japp,databaselogs,log4jmachinename,mymachine}}" + * as PROPERTIES, "" as EXCEPTION from logtable' + * + * In other words, if a number of LoggingEvent properties were combined into one field + * in the database, the combined field should be set as the MESSAGE column in the + * SELECT statement. Missing columns should be set to "". + * + * Make sure to alias the column names if needed to match the list provided above. + * + * NOTE: Patternlayout doesn't support Properties and JDBCAppender doesn't support + * exceptions, but the fields can be defined in the SQL statement and included in + * the event. + * + * This means that log4japp and/or log4jmachinename properties can be provided and + * the properties may be used to create a unique tab for the events. + * + * Both {{name, value, name2, value2}} formats and formats without the double braces + * are supported for MDC and properties fields. + * + * @author Scott Deboy <[EMAIL PROTECTED]> + * + */ public class JDBCReceiver extends Receiver { private boolean isActive = false; @@ -93,6 +135,9 @@ public JDBCReceiver() { } + /** + * Start a thread which will handle the retrieval. + */ public void activateOptions() { new JDBCReceiverThread().start(); } @@ -149,22 +194,22 @@ databaseUser = user; } - public void setURL(String url) { - databaseURL = url; - } - - public void setPassword(String password) { - databasePassword = password; - } - public String getUser() { return databaseUser; } + public void setURL(String url) { + databaseURL = url; + } + public String getURL() { return databaseURL; } + public void setPassword(String password) { + databasePassword = password; + } + public String getPassword() { return databasePassword; } @@ -211,6 +256,13 @@ while (rs.next()) { logger = Logger.getLogger(rs.getString("LOGGER")); + //TIMESTAMP PARSING IS NOT WORKING for the default format. + + //The default timestamp format, ISO8601DateFormat, doesn't have a + //parse method to convert the format back to a date. + //This parse process just tries to use the default dateformat parse + //methods set to Lenient to convert it back to a date. + //if that fails, it will use the current time as the timestamp DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); df.setLenient(true); @@ -229,29 +281,51 @@ mdc = new Hashtable(); if (mdcString != null) { + //support MDC being wrapped in {{name, value}} or just name, value if ( (mdcString.indexOf("{{") > -1) && (mdcString.indexOf("}}") > -1)) { mdcString = mdcString.substring( mdcString.indexOf("{{") + 2, mdcString.indexOf("}}")); + } - StringTokenizer tok = new StringTokenizer(mdcString, ","); + StringTokenizer tok = new StringTokenizer(mdcString, ","); - while (tok.countTokens() > 1) { - mdc.put(tok.nextToken(), tok.nextToken()); - } + while (tok.countTokens() > 1) { + mdc.put(tok.nextToken(), tok.nextToken()); } } - //exception not supported for now - but a placeholder is here for when it is supported - //exception = new String[] {rs.getString("EXCEPTION")}; + //although exception is not supported by jdbcappender, it needs to be provided in the SQL string + exception = new String[] {rs.getString("EXCEPTION")}; className = rs.getString("CLASS"); methodName = rs.getString("METHOD"); fileName = rs.getString("FILE"); lineNumber = rs.getString("LINE"); - //properties not supported for now + //although properties are not supported by JDBCAppender, if they are provided in the + //SQL they can be used here (for example, to route events to a unique tab if + //the machinename and/or appname property are set) + String propertiesString = rs.getString("PROPERTIES"); properties = new Hashtable(); + + if (propertiesString != null) { + //support properties being wrapped in {{name, value}} or just name, value + if ( + (propertiesString.indexOf("{{") > -1) + && (propertiesString.indexOf("}}") > -1)) { + propertiesString = + propertiesString.substring( + propertiesString.indexOf("{{") + 2, + propertiesString.indexOf("}}")); + } + + StringTokenizer tok2 = new StringTokenizer(propertiesString, ","); + + while (tok2.countTokens() > 1) { + properties.put(tok2.nextToken(), tok2.nextToken()); + } + } Level levelImpl = Level.toLevel(level);
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]