Added: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiver.html URL: http://svn.apache.org/viewvc/logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiver.html?view=auto&rev=558362 ============================================================================== --- logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiver.html (added) +++ logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiver.html Sat Jul 21 10:50:33 2007 @@ -0,0 +1,871 @@ + + + +LogFilePatternReceiver xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright 1999,2004 The Apache Software Foundation.
+3    * 
+4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+5    * use this file except in compliance with the License. You may obtain a copy of
+6    * the License at
+7    * 
+8    *      http://www.apache.org/licenses/LICENSE-2.0
+9    * 
+10   * Unless required by applicable law or agreed to in writing, software
+11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+13   * License for the specific language governing permissions and limitations under
+14   * the License.
+15   */
+16  
+17  package org.apache.log4j.varia;
+18  
+19  import java.io.BufferedReader;
+20  import java.io.FileNotFoundException;
+21  import java.io.IOException;
+22  import java.io.InputStreamReader;
+23  import java.io.Reader;
+24  import java.net.MalformedURLException;
+25  import java.net.URL;
+26  import java.text.SimpleDateFormat;
+27  import java.util.ArrayList;
+28  import java.util.HashMap;
+29  import java.util.HashSet;
+30  import java.util.Hashtable;
+31  import java.util.Iterator;
+32  import java.util.List;
+33  import java.util.Map;
+34  import java.util.Set;
+35  import java.util.TreeMap;
+36  
+37  import org.apache.log4j.Level;
+38  import org.apache.log4j.Logger;
+39  import org.apache.log4j.helpers.Constants;
+40  import org.apache.log4j.plugins.Receiver;
+41  import org.apache.log4j.rule.ExpressionRule;
+42  import org.apache.log4j.rule.Rule;
+43  import org.apache.log4j.spi.LoggingEvent;
+44  import org.apache.log4j.spi.ThrowableInformation;
+45  import org.apache.log4j.spi.LocationInfo;
+46  import org.apache.oro.text.perl.Perl5Util;
+47  import org.apache.oro.text.regex.MalformedPatternException;
+48  import org.apache.oro.text.regex.MatchResult;
+49  import org.apache.oro.text.regex.Pattern;
+50  import org.apache.oro.text.regex.Perl5Compiler;
+51  import org.apache.oro.text.regex.Perl5Matcher;
+52  
+53  /***
+54   * LogFilePatternReceiver can parse and tail log files, converting entries into
+55   * LoggingEvents.  If the file doesn't exist when the receiver is initialized, the
+56   * receiver will look for the file once every 10 seconds.
+57   * <p>
+58   * This receiver relies on ORO Perl5 features to perform the parsing of text in the 
+59   * log file, however the only regular expression field explicitly supported is 
+60   * a glob-style wildcard used to ignore fields in the log file if needed.  All other
+61   * fields are parsed by using the supplied keywords.
+62   * <p>
+63   * <b>Features:</b><br>
+64   * - specify the URL of the log file to be processed<br>
+65   * - specify the timestamp format in the file (if one exists)<br>
+66   * - specify the pattern (logFormat) used in the log file using keywords, a wildcard character (*) and fixed text<br>
+67   * - 'tail' the file (allows the contents of the file to be continually read and new events processed)<br>
+68   * - supports the parsing of multi-line messages and exceptions
+69   * - 'hostname' property set to URL host (or 'file' if not available)
+70   * - 'application' property set to URL path (or value of fileURL if not available) 
+71   *<p>
+72   * <b>Keywords:</b><br>
+73   * TIMESTAMP<br>
+74   * LOGGER<br>
+75   * LEVEL<br>
+76   * THREAD<br>
+77   * CLASS<br>
+78   * FILE<br>
+79   * LINE<br>
+80   * METHOD<br>
+81   * RELATIVETIME<br>
+82   * MESSAGE<br>
+83   * NDC<br>
+84   * PROP(key)<br>
+85   * <p>
+86   * Use a * to ignore portions of the log format that should be ignored
+87   * <p>
+88   * Example:<br>
+89   * If your file's patternlayout is this:<br>
+90   * <b>%d %-5p [%t] %C{2} (%F:%L) - %m%n</b>
+91   *<p>
+92   * specify this as the log format:<br>
+93   * <b>TIMESTAMP LEVEL [THREAD] CLASS (FILE:LINE) - MESSAGE</b>
+94   *<p>
+95   * To define a PROPERTY field, use PROP(key)
+96   * <p>
+97   * Example:<br> 
+98   * If you used the RELATIVETIME pattern layout character in the file, 
+99   * you can use PROP(RELATIVETIME) in the logFormat definition to assign 
+100  * the RELATIVETIME field as a property on the event.
+101  * <p>
+102  * If your file's patternlayout is this:<br>
+103  * <b>%r [%t] %-5p %c %x - %m%n</b>
+104  *<p>
+105  * specify this as the log format:<br>
+106  * <b>PROP(RELATIVETIME) [THREAD] LEVEL LOGGER * - MESSAGE</b>
+107  * <p>
+108  * Note the * - it can be used to ignore a single word or sequence of words in the log file
+109  * (in order for the wildcard to ignore a sequence of words, the text being ignored must be
+110  *  followed by some delimiter, like '-' or '[') - ndc is being ignored in this example.
+111  * <p>
+112  * Assign a filterExpression in order to only process events which match a filter.
+113  * If a filterExpression is not assigned, all events are processed.
+114  *<p>
+115  * <b>Limitations:</b><br>
+116  * - no support for the single-line version of throwable supported by patternlayout<br>
+117  *   (this version of throwable will be included as the last line of the message)<br>
+118  * - the relativetime patternLayout character must be set as a property: PROP(RELATIVETIME)<br>
+119  * - messages should appear as the last field of the logFormat because the variability in message content<br>
+120  * - exceptions are converted if the exception stack trace (other than the first line of the exception)<br>
+121  *   is stored in the log file with a tab followed by the word 'at' as the first characters in the line<br>
+122  * - tailing may fail if the file rolls over. 
+123  *<p>
+124  * <b>Example receiver configuration settings</b> (add these as params, specifying a LogFilePatternReceiver 'plugin'):<br>
+125  * param: "timestampFormat" value="yyyy-MM-d HH:mm:ss,SSS"<br>
+126  * param: "logFormat" value="RELATIVETIME [THREAD] LEVEL LOGGER * - MESSAGE"<br>
+127  * param: "fileURL" value="file:///c:/events.log"<br>
+128  * param: "tailing" value="true"
+129  *<p>
+130  * This configuration will be able to process these sample events:<br>
+131  * 710    [       Thread-0] DEBUG                   first.logger first - <test>   <test2>something here</test2>   <test3 blah=something/>   <test4>       <test5>something else</test5>   </test4></test><br>
+132  * 880    [       Thread-2] DEBUG                   first.logger third - <test>   <test2>something here</test2>   <test3 blah=something/>   <test4>       <test5>something else</test5>   </test4></test><br>
+133  * 880    [       Thread-0] INFO                    first.logger first - infomsg-0<br>
+134  * java.lang.Exception: someexception-first<br>
+135  *     at Generator2.run(Generator2.java:102)<br>
+136  *
+137  *@author Scott Deboy
+138  */
+139 public class LogFilePatternReceiver extends Receiver {
+140   private final Set keywords = new HashSet();
+141 
+142   private static final String PROP_START = "PROP(";
+143   private static final String PROP_END = ")";
+144 
+145   private static final String LOGGER = "LOGGER";
+146   private static final String MESSAGE = "MESSAGE";
+147   private static final String TIMESTAMP = "TIMESTAMP";
+148   private static final String NDC = "NDC";
+149   private static final String LEVEL = "LEVEL";
+150   private static final String THREAD = "THREAD";
+151   private static final String CLASS = "CLASS";
+152   private static final String FILE = "FILE";
+153   private static final String LINE = "LINE";
+154   private static final String METHOD = "METHOD";
+155   
+156   private static final String DEFAULT_HOST = "file";
+157   
+158   //all lines other than first line of exception begin with tab followed by 'at' followed by text
+159   private static final String EXCEPTION_PATTERN = "\tat.*";
+160   private static final String REGEXP_DEFAULT_WILDCARD = ".+?";
+161   private static final String REGEXP_GREEDY_WILDCARD = ".+";
+162   private static final String PATTERN_WILDCARD = "*";
+163   private static final String DEFAULT_GROUP = "(" + REGEXP_DEFAULT_WILDCARD + ")";
+164   private static final String GREEDY_GROUP = "(" + REGEXP_GREEDY_WILDCARD + ")";
+165   private static final String MULTIPLE_SPACES_REGEXP = "[ ]+";
+166   
+167   private final String newLine = System.getProperty("line.separator");
+168 
+169   private final String[] emptyException = new String[] { "" };
+170 
+171   private SimpleDateFormat dateFormat;
+172   private String timestampFormat = "yyyy-MM-d HH:mm:ss,SSS";
+173   private String logFormat;
+174   private String fileURL;
+175   private String host;
+176   private String path;
+177   private boolean tailing;
+178   private String filterExpression;
+179 
+180   private Perl5Util util = null;
+181   private Perl5Compiler exceptionCompiler = null;
+182   private Perl5Matcher exceptionMatcher = null;
+183   private static final String VALID_DATEFORMAT_CHAR_PATTERN = "[GyMwWDdFEaHkKhmsSzZ]";
+184 
+185   private Rule expressionRule;
+186 
+187   private Map currentMap;
+188   private List additionalLines;
+189   private List matchingKeywords;
+190 
+191   private String regexp;
+192   private Reader reader;
+193   private String timestampPatternText;
+194 
+195   private boolean useCurrentThread;
+196 
+197   public LogFilePatternReceiver() {
+198     keywords.add(TIMESTAMP);
+199     keywords.add(LOGGER);
+200     keywords.add(LEVEL);
+201     keywords.add(THREAD);
+202     keywords.add(CLASS);
+203     keywords.add(FILE);
+204     keywords.add(LINE);
+205     keywords.add(METHOD);
+206     keywords.add(MESSAGE);
+207     keywords.add(NDC);
+208   }
+209 
+210   /***
+211    * Accessor
+212    * 
+213    * @return file URL
+214    */
+215   public String getFileURL() {
+216     return fileURL;
+217   }
+218 
+219   /***
+220    * Mutator
+221    * 
+222    * @param fileURL
+223    */
+224   public void setFileURL(String fileURL) {
+225     this.fileURL = fileURL;
+226   }
+227 
+228   /***
+229    * Accessor
+230    * 
+231    * @return filter expression
+232    */
+233   public String getFilterExpression() {
+234     return filterExpression;
+235   }
+236 
+237   /***
+238    * Mutator
+239    * 
+240    * @param filterExpression
+241    */
+242   public void setFilterExpression(String filterExpression) {
+243     this.filterExpression = filterExpression;
+244   }
+245 
+246   /***
+247    * Accessor
+248    * 
+249    * @return tailing
+250    */
+251   public boolean isTailing() {
+252     return tailing;
+253   }
+254 
+255   /***
+256    * Mutator
+257    * 
+258    * @param tailing
+259    */
+260   public void setTailing(boolean tailing) {
+261     this.tailing = tailing;
+262   }
+263 
+264   /***
+265    * Accessor
+266    * 
+267    * @return log format
+268    */
+269   public String getLogFormat() {
+270     return logFormat;
+271   }
+272 
+273   /***
+274    * Mutator
+275    * 
+276    * @param logFormat
+277    *          the format
+278    */
+279   public void setLogFormat(String logFormat) {
+280     this.logFormat = logFormat;
+281   }
+282 
+283   /***
+284    * Mutator
+285    * 
+286    * @param timestampFormat
+287    */
+288   public void setTimestampFormat(String timestampFormat) {
+289     this.timestampFormat = timestampFormat;
+290   }
+291 
+292   /***
+293    * Accessor
+294    * 
+295    * @return timestamp format
+296    */
+297   public String getTimestampFormat() {
+298     return timestampFormat;
+299   }
+300 
+301   /***
+302    * Walk the additionalLines list, looking for the EXCEPTION_PATTERN.
+303    * <p>
+304    * Return the index of the first matched line minus 1 
+305    * (the match is the 2nd line of an exception)
+306    * <p>
+307    * Assumptions: <br>
+308    * - the additionalLines list may contain both message and exception lines<br>
+309    * - message lines are added to the additionalLines list and then
+310    * exception lines (all message lines occur in the list prior to all 
+311    * exception lines)
+312    * 
+313    * @return -1 if no exception line exists, line number otherwise
+314    */
+315   private int getExceptionLine() {
+316     try {
+317       Pattern exceptionPattern = exceptionCompiler.compile(EXCEPTION_PATTERN);
+318       for (int i = 0; i < additionalLines.size(); i++) {
+319         if (exceptionMatcher.matches((String) additionalLines.get(i), exceptionPattern)) {
+320           return i - 1;
+321         }
+322       }
+323     } catch (MalformedPatternException mpe) {
+324       getLogger().warn("Bad pattern: " + EXCEPTION_PATTERN);
+325     }
+326     return -1;
+327   }
+328 
+329   /***
+330    * Combine all message lines occuring in the additionalLines list, adding
+331    * a newline character between each line
+332    * <p>
+333    * the event will already have a message - combine this message
+334    * with the message lines in the additionalLines list 
+335    * (all entries prior to the exceptionLine index)
+336    * 
+337    * @param firstMessageLine primary message line
+338    * @param exceptionLine index of first exception line
+339    * @return message
+340    */
+341   private String buildMessage(String firstMessageLine, int exceptionLine) {
+342     if (additionalLines.size() == 0 || exceptionLine == 0) {
+343       return firstMessageLine;
+344     }
+345     StringBuffer message = new StringBuffer();
+346     if (firstMessageLine != null) {
+347       message.append(firstMessageLine);
+348     }
+349       
+350     int linesToProcess = (exceptionLine == -1?additionalLines.size(): exceptionLine);
+351 
+352     for (int i = 0; i < linesToProcess; i++) {
+353       message.append(newLine);
+354       message.append(additionalLines.get(i));
+355     }
+356     return message.toString();
+357   }
+358 
+359   /***
+360    * Combine all exception lines occuring in the additionalLines list into a 
+361    * String array
+362    * <p>
+363    * (all entries equal to or greater than the exceptionLine index)
+364    * 
+365    * @param exceptionLine index of first exception line
+366    * @return exception
+367    */
+368   private String[] buildException(int exceptionLine) {
+369     if (exceptionLine == -1) {
+370       return emptyException;
+371     }
+372     String[] exception = new String[additionalLines.size() - exceptionLine];
+373     for (int i = 0; i < additionalLines.size() - exceptionLine; i++) {
+374       exception[i] = (String) additionalLines.get(i + exceptionLine);
+375     }
+376     return exception;
+377   }
+378 
+379   /***
+380    * Construct a logging event from currentMap and additionalLines 
+381    * (additionalLines contains multiple message lines and any exception lines)
+382    * <p>
+383    * CurrentMap and additionalLines are cleared in the process
+384    * 
+385    * @return event
+386    */
+387   private LoggingEvent buildEvent() {
+388     if (currentMap.size() == 0) {
+389       if (additionalLines.size() > 0) {
+390         for (Iterator iter = additionalLines.iterator();iter.hasNext();) {
+391           getLogger().info("found non-matching line: " + iter.next());
+392         }
+393       }
+394       additionalLines.clear();
+395       return null;
+396     }
+397     //the current map contains fields - build an event
+398     int exceptionLine = getExceptionLine();
+399     String[] exception = buildException(exceptionLine);
+400 
+401     //messages are listed before exceptions in additionallines
+402     if (additionalLines.size() > 0 && exceptionLine != 0) {
+403       currentMap.put(MESSAGE, buildMessage((String) currentMap.get(MESSAGE),
+404           exceptionLine));
+405     }
+406     LoggingEvent event = convertToEvent(currentMap, exception);
+407     currentMap.clear();
+408     additionalLines.clear();
+409     return event;
+410   }
+411 
+412   /***
+413    * Read, parse and optionally tail the log file, converting entries into logging events.
+414    * 
+415    * A runtimeException is thrown if the logFormat pattern is malformed 
+416    * according to ORO's Perl5Compiler.
+417    * 
+418    * @param unbufferedReader
+419    * @throws IOException
+420    */
+421   protected void process(Reader unbufferedReader) throws IOException {
+422     BufferedReader bufferedReader = new BufferedReader(unbufferedReader);
+423 
+424     Perl5Compiler compiler = new Perl5Compiler();
+425     Pattern regexpPattern = null;
+426     try {
+427       regexpPattern = compiler.compile(regexp);
+428     } catch (MalformedPatternException mpe) {
+429       throw new RuntimeException("Bad pattern: " + regexp);
+430     }
+431 
+432     Perl5Matcher eventMatcher = new Perl5Matcher(); 
+433     String line = null;
+434     getLogger().debug("tailing file: " + tailing);
+435     do {
+436       while ((line = bufferedReader.readLine()) != null) {
+437         if (eventMatcher.matches(line, regexpPattern)) {
+438           //build an event from the previous match (held in current map)
+439           LoggingEvent event = buildEvent();
+440           if (event != null) {
+441             if (passesExpression(event)) {
+442               doPost(event);
+443             }
+444           }
+445           currentMap.putAll(processEvent(eventMatcher.getMatch()));
+446         } else {
+447           //getLogger().debug("line doesn't match pattern - must be ")
+448           //may be an exception or additional message lines
+449           additionalLines.add(line);
+450         }
+451       }
+452 
+453       //process last event if one exists
+454       LoggingEvent event = buildEvent();
+455       if (event != null) {
+456         if (passesExpression(event)) {
+457           doPost(event);
+458         }
+459         getLogger().debug("no further lines to process in " + fileURL);
+460       }
+461       try {
+462         synchronized (this) {
+463           wait(2000);
+464         }
+465       } catch (InterruptedException ie) {
+466       }
+467     } while (tailing);
+468     getLogger().debug("processing " + fileURL + " complete");
+469     shutdown();
+470   }
+471 
+472   /***
+473    * Helper method that supports the evaluation of the expression
+474    * 
+475    * @param event
+476    * @return true if expression isn't set, or the result of the evaluation otherwise 
+477    */
+478   private boolean passesExpression(LoggingEvent event) {
+479     if (event != null) {
+480       if (expressionRule != null) {
+481         return (expressionRule.evaluate(event));
+482       }
+483     }
+484     return true;
+485   }
+486 
+487   /***
+488    * Convert the ORO match into a map.
+489    * <p>
+490    * Relies on the fact that the matchingKeywords list is in the same
+491    * order as the groups in the regular expression
+492    *  
+493    * @param result
+494    * @return map
+495    */
+496   private Map processEvent(MatchResult result) {
+497     Map map = new HashMap();
+498     //group zero is the entire match - process all other groups
+499     for (int i = 1; i < result.groups(); i++) {
+500       map.put(matchingKeywords.get(i - 1), result.group(i));
+501     }
+502     return map;
+503   }
+504   
+505   /***
+506    * Helper method that will convert timestamp format to a pattern
+507    * 
+508    * 
+509    * @return string
+510    */
+511   private String convertTimestamp() {
+512     return util.substitute("s/("+VALID_DATEFORMAT_CHAR_PATTERN+")+/////w+/g", timestampFormat);
+513   }
+514   
+515   protected void setHost(String host) {
+516 	  this.host = host;
+517   }
+518   
+519   protected void setPath(String path) {
+520 	  this.path = path;
+521   }
+522 
+523   /***
+524    * Build the regular expression needed to parse log entries
+525    *  
+526    */
+527   protected void initialize() {
+528 	if (host == null && path == null) {
+529 		try {
+530 			URL url = new URL(fileURL);
+531 			host = url.getHost();
+532 			path = url.getPath();
+533 		} catch (MalformedURLException e1) {
+534 			// TODO Auto-generated catch block
+535 			e1.printStackTrace();
+536 		}
+537 	}
+538 	if (host == null || host.trim().equals("")) {
+539 		host = DEFAULT_HOST; 
+540 	}
+541 	if (path == null || path.trim().equals("")) {
+542 		path = fileURL;
+543 	}
+544 	
+545     util = new Perl5Util();
+546     exceptionCompiler = new Perl5Compiler();
+547     exceptionMatcher = new Perl5Matcher();
+548 
+549     currentMap = new HashMap();
+550     additionalLines = new ArrayList();
+551     matchingKeywords = new ArrayList();
+552     
+553     if (timestampFormat != null) {
+554       dateFormat = new SimpleDateFormat(timestampFormat);
+555       timestampPatternText = convertTimestamp();
+556     }
+557 
+558     try {
+559       if (filterExpression != null) {
+560         expressionRule = ExpressionRule.getRule(filterExpression);
+561       }
+562     } catch (Exception e) {
+563       getLogger().warn("Invalid filter expression: " + filterExpression, e);
+564     }
+565 
+566     Map keywordMap = new TreeMap();
+567 
+568     String newPattern = logFormat;
+569 
+570     /*
+571      * examine pattern, adding properties to an index-based map where the key is the 
+572      * numeric offset from the start of the pattern so that order can be preserved
+573      * 
+574      * Replaces PROP(X) definitions in the pattern with the short version X, so 
+575      * that the name can be used as the event property later 
+576      */
+577     int index = 0;
+578     int currentPosition = 0;
+579     String current = newPattern;
+580     while (index > -1) {
+581       index = current.indexOf(PROP_START);
+582       currentPosition = currentPosition + index;
+583       if (index > -1) {
+584         String currentProp = current.substring(current.indexOf(PROP_START));
+585         String prop = currentProp.substring(0,
+586             currentProp.indexOf(PROP_END) + 1);
+587         current = current.substring(current.indexOf(currentProp) + 1);
+588         String shortProp = prop.substring(PROP_START.length(),
+589             prop.length() - 1);
+590         keywordMap.put(new Integer(currentPosition), shortProp);
+591         newPattern = replace(prop, shortProp, newPattern);
+592       }
+593     }
+594 
+595     newPattern = replaceMetaChars(newPattern);
+596 
+597     //compress one or more spaces in the pattern into the [ ]+ regexp
+598     //(supports padding of level in log files)
+599     newPattern = util.substitute("s/" + MULTIPLE_SPACES_REGEXP +"/" + MULTIPLE_SPACES_REGEXP + "/g", newPattern);
+600     newPattern = replace(PATTERN_WILDCARD, REGEXP_DEFAULT_WILDCARD, newPattern);
+601 
+602     /*
+603      * we're using a treemap, so the index will be used as the key to ensure
+604      * keywords are ordered correctly
+605      * 
+606      * examine pattern, adding keywords to an index-based map patterns can
+607      * contain only one of these per entry...properties are the only 'keyword'
+608      * that can occur multiple times in an entry
+609      */
+610     Iterator iter = keywords.iterator();
+611     while (iter.hasNext()) {
+612       String keyword = (String) iter.next();
+613       int index2 = newPattern.indexOf(keyword);
+614       if (index2 > -1) {
+615         keywordMap.put(new Integer(index2), keyword);
+616       }
+617     }
+618 
+619     //keywordMap should be ordered by index..add all values to a list
+620     matchingKeywords.addAll(keywordMap.values());
+621 
+622     /*
+623      * iterate over the keywords found in the pattern and replace with regexp
+624      * group
+625      */
+626     String currentPattern = newPattern;
+627     for (int i = 0;i<matchingKeywords.size();i++) {
+628       String keyword = (String) matchingKeywords.get(i);
+629       //make the final keyword greedy
+630       if (i == (matchingKeywords.size() - 1)) {
+631         currentPattern = replace(keyword, GREEDY_GROUP, currentPattern);
+632       } else if (TIMESTAMP.equals(keyword)) {
+633         currentPattern = replace(keyword, "(" + timestampPatternText + ")", currentPattern);
+634       } else {
+635         currentPattern = replace(keyword, DEFAULT_GROUP, currentPattern);
+636       }
+637     }
+638 
+639     regexp = currentPattern;
+640     getLogger().debug("regexp is " + regexp);
+641   }
+642 
+643   /***
+644    * Helper method that will globally replace a section of text
+645    * 
+646    * @param pattern
+647    * @param replacement
+648    * @param input 
+649    * 
+650    * @return string
+651    */
+652   private String replace(String pattern, String replacement, String input) {
+653     return util.substitute("s/" + Perl5Compiler.quotemeta(pattern) + "/"
+654         + Perl5Compiler.quotemeta(replacement) + "/g", input);
+655   }
+656 
+657   /***
+658    * Some perl5 characters may occur in the log file format.  
+659    * Escape these characters to prevent parsing errors.
+660    * 
+661    * @param input
+662    * @return string
+663    */
+664   private String replaceMetaChars(String input) {
+665     input = replace("(", "//(", input);
+666     input = replace(")", "//)", input);
+667     input = replace("[", "//[", input);
+668     input = replace("]", "//]", input);
+669     input = replace("{", "//{", input);
+670     input = replace("}", "//}", input);
+671     input = replace("#", "//#", input);
+672     input = replace("/", "///", input);
+673     return input;
+674   }
+675 
+676   /***
+677    * Convert a keyword-to-values map to a LoggingEvent
+678    * 
+679    * @param fieldMap
+680    * @param exception
+681    * 
+682    * @return logging event
+683    */
+684   private LoggingEvent convertToEvent(Map fieldMap, String[] exception) {
+685     if (fieldMap == null) {
+686       return null;
+687     }
+688 
+689     //a logger must exist at a minimum for the event to be processed
+690     if (!fieldMap.containsKey(LOGGER)) {
+691       fieldMap.put(LOGGER, "Unknown");
+692     }
+693     if (exception == null) {
+694       exception = emptyException;
+695     }
+696 
+697     Logger logger = null;
+698     long timeStamp = 0L;
+699     String level = null;
+700     String threadName = null;
+701     Object message = null;
+702     String ndc = null;
+703     String className = null;
+704     String methodName = null;
+705     String eventFileName = null;
+706     String lineNumber = null;
+707     Hashtable properties = new Hashtable();
+708 
+709     logger = Logger.getLogger((String) fieldMap.remove(LOGGER));
+710 
+711     if ((dateFormat != null) && fieldMap.containsKey(TIMESTAMP)) {
+712       try {
+713         timeStamp = dateFormat.parse((String) fieldMap.remove(TIMESTAMP))
+714             .getTime();
+715       } catch (Exception e) {
+716         e.printStackTrace();
+717       }
+718     }
+719     //use current time if timestamp not parseable
+720     if (timeStamp == 0L) {
+721       timeStamp = System.currentTimeMillis();
+722     }
+723 
+724     level = (String) fieldMap.remove(LEVEL);
+725     Level levelImpl = Level.toLevel(level.trim());
+726 
+727     threadName = (String) fieldMap.remove(THREAD);
+728 
+729     message = fieldMap.remove(MESSAGE);
+730     if (message == null) {
+731       message = "";
+732     }
+733 
+734     ndc = (String) fieldMap.remove(NDC);
+735 
+736     className = (String) fieldMap.remove(CLASS);
+737 
+738     methodName = (String) fieldMap.remove(METHOD);
+739 
+740     eventFileName = (String) fieldMap.remove(FILE);
+741 
+742     lineNumber = (String) fieldMap.remove(LINE);
+743 
+744     properties.put(Constants.HOSTNAME_KEY, host);
+745     properties.put(Constants.APPLICATION_KEY, path);
+746     properties.put(Constants.RECEIVER_NAME_KEY, getName());
+747 
+748     //all remaining entries in fieldmap are properties
+749     properties.putAll(fieldMap);
+750 
+751     LocationInfo info = null;
+752 
+753     if ((eventFileName != null) || (className != null) || (methodName != null)
+754         || (lineNumber != null)) {
+755       info = new LocationInfo(eventFileName, className, methodName, lineNumber);
+756     } else {
+757       info = LocationInfo.NA_LOCATION_INFO;
+758     }
+759 
+760     LoggingEvent event = new LoggingEvent(null,
+761             logger, timeStamp, levelImpl, message,
+762             threadName,
+763             new ThrowableInformation(exception),
+764             ndc,
+765             info,
+766             properties);
+767 
+768     return event;
+769   }
+770 
+771   public static void main(String[] args) {
+772     /*
+773     LogFilePatternReceiver test = new LogFilePatternReceiver();
+774     test.setLogFormat("TIMESTAMP LEVEL [THREAD] LOGGER (FILE:LINE) - MESSAGE");
+775     test.setTailing(true);
+776     test.setFileURL("file:///C:/log/test.log");
+777     test.initialize();
+778     try {
+779       test.process(new InputStreamReader(new URL(test.getFileURL())
+780           .openStream()));
+781     } catch (IOException ioe) {
+782       ioe.printStackTrace();
+783     }
+784     */
+785   }
+786 
+787   /***
+788    * Close the reader. 
+789    */
+790   public void shutdown() {
+791     try {
+792       if (reader != null) {
+793         reader.close();
+794         reader = null;
+795       }
+796     } catch (IOException ioe) {
+797       ioe.printStackTrace();
+798     }
+799   }
+800 
+801   /***
+802    * Read and process the log file.
+803    */
+804   public void activateOptions() {
+805     Runnable runnable = new Runnable() {
+806       public void run() {
+807         initialize();
+808         while (reader == null) {
+809           getLogger().info("attempting to load file: " + getFileURL());
+810 	        try {
+811 	          reader = new InputStreamReader(new URL(getFileURL()).openStream());
+812 	        } catch (FileNotFoundException fnfe) {
+813 	          getLogger().info("file not available - will try again in 10 seconds");
+814 	          synchronized(this) {
+815 	            try {
+816 	              wait(10000);
+817 	            } catch (InterruptedException ie){}
+818 	          }
+819 	        } catch (IOException ioe) {
+820 	          getLogger().warn("unable to load file", ioe);
+821 	          return;
+822 	        }
+823         } 
+824         try {
+825           process(reader);
+826         } catch (IOException ioe) {
+827           //io exception - probably shut down
+828           getLogger().info("stream closed");
+829         }
+830       }
+831     };
+832     if(useCurrentThread) {
+833         runnable.run();
+834     }else {
+835         new Thread(runnable, "LogFilePatternReceiver-"+getName()).start();
+836     }
+837   }
+838 
+839      /***
+840       * When true, this property uses the current Thread to perform the import,
+841       * otherwise when false (the default), a new Thread is created and started to manage
+842       * the import.
+843       * @return
+844       */ 
+845     public final boolean isUseCurrentThread() {
+846         return useCurrentThread;
+847     }
+848 
+849     /***
+850      * Sets whether the current Thread or a new Thread is created to perform the import,
+851      * the default being false (new Thread created).
+852      * 
+853      * @param useCurrentThread
+854      */
+855     public final void setUseCurrentThread(boolean useCurrentThread) {
+856         this.useCurrentThread = useCurrentThread;
+857     }
+858 }
+
+
+ + Propchange: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiver.html ------------------------------------------------------------------------------ svn:mime-type = text/html Added: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.html URL: http://svn.apache.org/viewvc/logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.html?view=auto&rev=558362 ============================================================================== --- logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.html (added) +++ logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.html Sat Jul 21 10:50:33 2007 @@ -0,0 +1,63 @@ + + + +LogFilePatternReceiverBeanInfo 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.varia;
+19  
+20  import java.beans.PropertyDescriptor;
+21  import java.beans.SimpleBeanInfo;
+22  
+23  
+24  /***
+25   * BeanInfo class for the meta-data of the LogFilePatternReceiver.
+26   *
+27   */
+28  public class LogFilePatternReceiverBeanInfo extends SimpleBeanInfo {
+29    /* (non-Javadoc)
+30     * @see java.beans.BeanInfo#getPropertyDescriptors()
+31     */
+32    public PropertyDescriptor[] getPropertyDescriptors() {
+33      try {
+34        return new PropertyDescriptor[] {
+35          new PropertyDescriptor("fileURL", LogFilePatternReceiver.class),
+36          new PropertyDescriptor(
+37            "timestampFormat", LogFilePatternReceiver.class),
+38          new PropertyDescriptor("logFormat", LogFilePatternReceiver.class),
+39          new PropertyDescriptor("name", LogFilePatternReceiver.class),
+40          new PropertyDescriptor("tailing", LogFilePatternReceiver.class),
+41          new PropertyDescriptor(
+42            "filterExpression", LogFilePatternReceiver.class),
+43          new PropertyDescriptor("useCurrentThread", LogFilePatternReceiver.class),
+44        };
+45      } catch (Exception e) {
+46      }
+47  
+48      return null;
+49    }
+50  }
+
+
+ + Propchange: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.html ------------------------------------------------------------------------------ svn:mime-type = text/html Added: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-frame.html URL: http://svn.apache.org/viewvc/logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-frame.html?view=auto&rev=558362 ============================================================================== --- logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-frame.html (added) +++ logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-frame.html Sat Jul 21 10:50:33 2007 @@ -0,0 +1,30 @@ + + + + + + Apache Receivers Companion for log4j 1.2. 1.1-SNAPSHOT Reference Package org.apache.log4j.varia + + + + +

+ org.apache.log4j.varia +

+ +

Classes

+ + + + + \ No newline at end of file Propchange: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-frame.html ------------------------------------------------------------------------------ svn:mime-type = text/html Added: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-summary.html URL: http://svn.apache.org/viewvc/logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-summary.html?view=auto&rev=558362 ============================================================================== --- logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-summary.html (added) +++ logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-summary.html Sat Jul 21 10:50:33 2007 @@ -0,0 +1,77 @@ + + + + + + Apache Receivers Companion for log4j 1.2. 1.1-SNAPSHOT Reference Package $name + + + +
+ +
+
+ +
+ +

Package org.apache.log4j.varia

+ + + + + + + + + + + + + + + + + + +
Class Summary
+ ListModelAppender +
+ LogFilePatternReceiver +
+ LogFilePatternReceiverBeanInfo +
+ +
+ +
+
+ +
+
+ Copyright © null Apache Software Foundation. All Rights Reserved. + + \ No newline at end of file Propchange: logging/site/trunk/docs/log4j/companions/receivers/xref/org/apache/log4j/varia/package-summary.html ------------------------------------------------------------------------------ svn:mime-type = text/html