Home » apache-log4j-1.2.15 » org.apache » log4j » helpers » [javadoc | source]
    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   package org.apache.log4j.helpers;
   18   
   19   import org.apache.log4j.helpers.LogLog;
   20   import org.apache.log4j.helpers.OptionConverter;
   21   import org.apache.log4j.helpers.AbsoluteTimeDateFormat;
   22   import org.apache.log4j.Layout;
   23   import org.apache.log4j.spi.LoggingEvent;
   24   import org.apache.log4j.spi.LocationInfo;
   25   import java.text.DateFormat;
   26   import java.text.SimpleDateFormat;
   27   import java.util.Date;
   28   
   29   // Contributors:   Nelson Minar <(nelson@monkey.org>
   30   //                 Igor E. Poteryaev <jah@mail.ru>
   31   //                 Reinhard Deschler <reinhard.deschler@web.de>
   32   
   33   /**
   34      Most of the work of the {@link org.apache.log4j.PatternLayout} class
   35      is delegated to the PatternParser class.
   36   
   37      <p>It is this class that parses conversion patterns and creates
   38      a chained list of {@link OptionConverter OptionConverters}.
   39   
   40      @author <a href=mailto:"cakalijp@Maritz.com">James P. Cakalic</a>
   41      @author Ceki G&uuml;lc&uuml;
   42      @author Anders Kristensen
   43   
   44      @since 0.8.2
   45   */
   46   public class PatternParser {
   47   
   48     private static final char ESCAPE_CHAR = '%';
   49   
   50     private static final int LITERAL_STATE = 0;
   51     private static final int CONVERTER_STATE = 1;
   52     private static final int DOT_STATE = 3;
   53     private static final int MIN_STATE = 4;
   54     private static final int MAX_STATE = 5;
   55   
   56     static final int FULL_LOCATION_CONVERTER = 1000;
   57     static final int METHOD_LOCATION_CONVERTER = 1001;
   58     static final int CLASS_LOCATION_CONVERTER = 1002;
   59     static final int LINE_LOCATION_CONVERTER = 1003;
   60     static final int FILE_LOCATION_CONVERTER = 1004;
   61   
   62     static final int RELATIVE_TIME_CONVERTER = 2000;
   63     static final int THREAD_CONVERTER = 2001;
   64     static final int LEVEL_CONVERTER = 2002;
   65     static final int NDC_CONVERTER = 2003;
   66     static final int MESSAGE_CONVERTER = 2004;
   67   
   68     int state;
   69     protected StringBuffer currentLiteral = new StringBuffer(32);
   70     protected int patternLength;
   71     protected int i;
   72     PatternConverter head;
   73     PatternConverter tail;
   74     protected FormattingInfo formattingInfo = new FormattingInfo();
   75     protected String pattern;
   76   
   77     public
   78     PatternParser(String pattern) {
   79       this.pattern = pattern;
   80       patternLength =  pattern.length();
   81       state = LITERAL_STATE;
   82     }
   83   
   84     private
   85     void  addToList(PatternConverter pc) {
   86       if(head == null) {
   87         head = tail = pc;
   88       } else {
   89         tail.next = pc;
   90         tail = pc;
   91       }
   92     }
   93   
   94     protected
   95     String extractOption() {
   96       if((i < patternLength) && (pattern.charAt(i) == '{')) {
   97         int end = pattern.indexOf('}', i);
   98         if (end > i) {
   99   	String r = pattern.substring(i + 1, end);
  100   	i = end+1;
  101   	return r;
  102         }
  103       }
  104       return null;
  105     }
  106   
  107   
  108     /**
  109        The option is expected to be in decimal and positive. In case of
  110        error, zero is returned.  */
  111     protected
  112     int extractPrecisionOption() {
  113       String opt = extractOption();
  114       int r = 0;
  115       if(opt != null) {
  116         try {
  117   	r = Integer.parseInt(opt);
  118   	if(r <= 0) {
  119   	    LogLog.error(
  120   	        "Precision option (" + opt + ") isn't a positive integer.");
  121   	    r = 0;
  122   	}
  123         }
  124         catch (NumberFormatException e) {
  125   	LogLog.error("Category option \""+opt+"\" not a decimal integer.", e);
  126         }
  127       }
  128       return r;
  129     }
  130   
  131     public
  132     PatternConverter parse() {
  133       char c;
  134       i = 0;
  135       while(i < patternLength) {
  136         c = pattern.charAt(i++);
  137         switch(state) {
  138         case LITERAL_STATE:
  139           // In literal state, the last char is always a literal.
  140           if(i == patternLength) {
  141             currentLiteral.append(c);
  142             continue;
  143           }
  144           if(c == ESCAPE_CHAR) {
  145             // peek at the next char.
  146             switch(pattern.charAt(i)) {
  147             case ESCAPE_CHAR:
  148               currentLiteral.append(c);
  149               i++; // move pointer
  150               break;
  151             case 'n':
  152               currentLiteral.append(Layout.LINE_SEP);
  153               i++; // move pointer
  154               break;
  155             default:
  156               if(currentLiteral.length() != 0) {
  157                 addToList(new LiteralPatternConverter(
  158                                                     currentLiteral.toString()));
  159                 //LogLog.debug("Parsed LITERAL converter: \""
  160                 //           +currentLiteral+"\".");
  161               }
  162               currentLiteral.setLength(0);
  163               currentLiteral.append(c); // append %
  164               state = CONVERTER_STATE;
  165               formattingInfo.reset();
  166             }
  167           }
  168           else {
  169             currentLiteral.append(c);
  170           }
  171           break;
  172         case CONVERTER_STATE:
  173   	currentLiteral.append(c);
  174   	switch(c) {
  175   	case '-':
  176   	  formattingInfo.leftAlign = true;
  177   	  break;
  178   	case '.':
  179   	  state = DOT_STATE;
  180   	  break;
  181   	default:
  182   	  if(c >= '0' && c <= '9') {
  183   	    formattingInfo.min = c - '0';
  184   	    state = MIN_STATE;
  185   	  }
  186   	  else
  187   	    finalizeConverter(c);
  188   	} // switch
  189   	break;
  190         case MIN_STATE:
  191   	currentLiteral.append(c);
  192   	if(c >= '0' && c <= '9')
  193   	  formattingInfo.min = formattingInfo.min*10 + (c - '0');
  194   	else if(c == '.')
  195   	  state = DOT_STATE;
  196   	else {
  197   	  finalizeConverter(c);
  198   	}
  199   	break;
  200         case DOT_STATE:
  201   	currentLiteral.append(c);
  202   	if(c >= '0' && c <= '9') {
  203   	  formattingInfo.max = c - '0';
  204   	   state = MAX_STATE;
  205   	}
  206   	else {
  207   	  LogLog.error("Error occured in position "+i
  208   		     +".\n Was expecting digit, instead got char \""+c+"\".");
  209   	  state = LITERAL_STATE;
  210   	}
  211   	break;
  212         case MAX_STATE:
  213   	currentLiteral.append(c);
  214   	if(c >= '0' && c <= '9')
  215   	  formattingInfo.max = formattingInfo.max*10 + (c - '0');
  216   	else {
  217   	  finalizeConverter(c);
  218   	  state = LITERAL_STATE;
  219   	}
  220   	break;
  221         } // switch
  222       } // while
  223       if(currentLiteral.length() != 0) {
  224         addToList(new LiteralPatternConverter(currentLiteral.toString()));
  225         //LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
  226       }
  227       return head;
  228     }
  229   
  230     protected
  231     void finalizeConverter(char c) {
  232       PatternConverter pc = null;
  233       switch(c) {
  234       case 'c':
  235         pc = new CategoryPatternConverter(formattingInfo,
  236   					extractPrecisionOption());
  237         //LogLog.debug("CATEGORY converter.");
  238         //formattingInfo.dump();
  239         currentLiteral.setLength(0);
  240         break;
  241       case 'C':
  242         pc = new ClassNamePatternConverter(formattingInfo,
  243   					 extractPrecisionOption());
  244         //LogLog.debug("CLASS_NAME converter.");
  245         //formattingInfo.dump();
  246         currentLiteral.setLength(0);
  247         break;
  248       case 'd':
  249         String dateFormatStr = AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT;
  250         DateFormat df;
  251         String dOpt = extractOption();
  252         if(dOpt != null)
  253   	dateFormatStr = dOpt;
  254   
  255         if(dateFormatStr.equalsIgnoreCase(
  256                                       AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT))
  257   	df = new  ISO8601DateFormat();
  258         else if(dateFormatStr.equalsIgnoreCase(
  259                                      AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT))
  260   	df = new AbsoluteTimeDateFormat();
  261         else if(dateFormatStr.equalsIgnoreCase(
  262                                 AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT))
  263   	df = new DateTimeDateFormat();
  264         else {
  265   	try {
  266   	  df = new SimpleDateFormat(dateFormatStr);
  267   	}
  268   	catch (IllegalArgumentException e) {
  269   	  LogLog.error("Could not instantiate SimpleDateFormat with " +
  270   		       dateFormatStr, e);
  271   	  df = (DateFormat) OptionConverter.instantiateByClassName(
  272   			           "org.apache.log4j.helpers.ISO8601DateFormat",
  273   				   DateFormat.class, null);
  274   	}
  275         }
  276         pc = new DatePatternConverter(formattingInfo, df);
  277         //LogLog.debug("DATE converter {"+dateFormatStr+"}.");
  278         //formattingInfo.dump();
  279         currentLiteral.setLength(0);
  280         break;
  281       case 'F':
  282         pc = new LocationPatternConverter(formattingInfo,
  283   					FILE_LOCATION_CONVERTER);
  284         //LogLog.debug("File name converter.");
  285         //formattingInfo.dump();
  286         currentLiteral.setLength(0);
  287         break;
  288       case 'l':
  289         pc = new LocationPatternConverter(formattingInfo,
  290   					FULL_LOCATION_CONVERTER);
  291         //LogLog.debug("Location converter.");
  292         //formattingInfo.dump();
  293         currentLiteral.setLength(0);
  294         break;
  295       case 'L':
  296         pc = new LocationPatternConverter(formattingInfo,
  297   					LINE_LOCATION_CONVERTER);
  298         //LogLog.debug("LINE NUMBER converter.");
  299         //formattingInfo.dump();
  300         currentLiteral.setLength(0);
  301         break;
  302       case 'm':
  303         pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER);
  304         //LogLog.debug("MESSAGE converter.");
  305         //formattingInfo.dump();
  306         currentLiteral.setLength(0);
  307         break;
  308       case 'M':
  309         pc = new LocationPatternConverter(formattingInfo,
  310   					METHOD_LOCATION_CONVERTER);
  311         //LogLog.debug("METHOD converter.");
  312         //formattingInfo.dump();
  313         currentLiteral.setLength(0);
  314         break;
  315       case 'p':
  316         pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER);
  317         //LogLog.debug("LEVEL converter.");
  318         //formattingInfo.dump();
  319         currentLiteral.setLength(0);
  320         break;
  321       case 'r':
  322         pc = new BasicPatternConverter(formattingInfo,
  323   					 RELATIVE_TIME_CONVERTER);
  324         //LogLog.debug("RELATIVE time converter.");
  325         //formattingInfo.dump();
  326         currentLiteral.setLength(0);
  327         break;
  328       case 't':
  329         pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER);
  330         //LogLog.debug("THREAD converter.");
  331         //formattingInfo.dump();
  332         currentLiteral.setLength(0);
  333         break;
  334         /*case 'u':
  335         if(i < patternLength) {
  336   	char cNext = pattern.charAt(i);
  337   	if(cNext >= '0' && cNext <= '9') {
  338   	  pc = new UserFieldPatternConverter(formattingInfo, cNext - '0');
  339   	  LogLog.debug("USER converter ["+cNext+"].");
  340   	  formattingInfo.dump();
  341   	  currentLiteral.setLength(0);
  342   	  i++;
  343   	}
  344   	else
  345   	  LogLog.error("Unexpected char" +cNext+" at position "+i);
  346         }
  347         break;*/
  348       case 'x':
  349         pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER);
  350         //LogLog.debug("NDC converter.");
  351         currentLiteral.setLength(0);
  352         break;
  353       case 'X':
  354         String xOpt = extractOption();
  355         pc = new MDCPatternConverter(formattingInfo, xOpt);
  356         currentLiteral.setLength(0);
  357         break;
  358       default:
  359         LogLog.error("Unexpected char [" +c+"] at position "+i
  360   		   +" in conversion patterrn.");
  361         pc = new LiteralPatternConverter(currentLiteral.toString());
  362         currentLiteral.setLength(0);
  363       }
  364   
  365       addConverter(pc);
  366     }
  367   
  368     protected
  369     void addConverter(PatternConverter pc) {
  370       currentLiteral.setLength(0);
  371       // Add the pattern converter to the list.
  372       addToList(pc);
  373       // Next pattern is assumed to be a literal.
  374       state = LITERAL_STATE;
  375       // Reset formatting info
  376       formattingInfo.reset();
  377     }
  378   
  379     // ---------------------------------------------------------------------
  380     //                      PatternConverters
  381     // ---------------------------------------------------------------------
  382   
  383     private static class BasicPatternConverter extends PatternConverter {
  384       int type;
  385   
  386       BasicPatternConverter(FormattingInfo formattingInfo, int type) {
  387         super(formattingInfo);
  388         this.type = type;
  389       }
  390   
  391       public
  392       String convert(LoggingEvent event) {
  393         switch(type) {
  394         case RELATIVE_TIME_CONVERTER:
  395   	return (Long.toString(event.timeStamp - LoggingEvent.getStartTime()));
  396         case THREAD_CONVERTER:
  397   	return event.getThreadName();
  398         case LEVEL_CONVERTER:
  399   	return event.getLevel().toString();
  400         case NDC_CONVERTER:
  401   	return event.getNDC();
  402         case MESSAGE_CONVERTER: {
  403   	return event.getRenderedMessage();
  404         }
  405         default: return null;
  406         }
  407       }
  408     }
  409   
  410     private static class LiteralPatternConverter extends PatternConverter {
  411       private String literal;
  412   
  413       LiteralPatternConverter(String value) {
  414         literal = value;
  415       }
  416   
  417       public
  418       final
  419       void format(StringBuffer sbuf, LoggingEvent event) {
  420         sbuf.append(literal);
  421       }
  422   
  423       public
  424       String convert(LoggingEvent event) {
  425         return literal;
  426       }
  427     }
  428   
  429     private static class DatePatternConverter extends PatternConverter {
  430       private DateFormat df;
  431       private Date date;
  432   
  433       DatePatternConverter(FormattingInfo formattingInfo, DateFormat df) {
  434         super(formattingInfo);
  435         date = new Date();
  436         this.df = df;
  437       }
  438   
  439       public
  440       String convert(LoggingEvent event) {
  441         date.setTime(event.timeStamp);
  442         String converted = null;
  443         try {
  444           converted = df.format(date);
  445         }
  446         catch (Exception ex) {
  447           LogLog.error("Error occured while converting date.", ex);
  448         }
  449         return converted;
  450       }
  451     }
  452   
  453     private static class MDCPatternConverter extends PatternConverter {
  454       private String key;
  455   
  456       MDCPatternConverter(FormattingInfo formattingInfo, String key) {
  457         super(formattingInfo);
  458         this.key = key;
  459       }
  460   
  461       public
  462       String convert(LoggingEvent event) {
  463         Object val = event.getMDC(key);
  464         if(val == null) {
  465   	return null;
  466         } else {
  467   	return val.toString();
  468         }
  469       }
  470     }
  471   
  472   
  473     private class LocationPatternConverter extends PatternConverter {
  474       int type;
  475   
  476       LocationPatternConverter(FormattingInfo formattingInfo, int type) {
  477         super(formattingInfo);
  478         this.type = type;
  479       }
  480   
  481       public
  482       String convert(LoggingEvent event) {
  483         LocationInfo locationInfo = event.getLocationInformation();
  484         switch(type) {
  485         case FULL_LOCATION_CONVERTER:
  486   	return locationInfo.fullInfo;
  487         case METHOD_LOCATION_CONVERTER:
  488   	return locationInfo.getMethodName();
  489         case LINE_LOCATION_CONVERTER:
  490   	return locationInfo.getLineNumber();
  491         case FILE_LOCATION_CONVERTER:
  492   	return locationInfo.getFileName();
  493         default: return null;
  494         }
  495       }
  496     }
  497   
  498     private static abstract class NamedPatternConverter extends PatternConverter {
  499       int precision;
  500   
  501       NamedPatternConverter(FormattingInfo formattingInfo, int precision) {
  502         super(formattingInfo);
  503         this.precision =  precision;
  504       }
  505   
  506       abstract
  507       String getFullyQualifiedName(LoggingEvent event);
  508   
  509       public
  510       String convert(LoggingEvent event) {
  511         String n = getFullyQualifiedName(event);
  512         if(precision <= 0)
  513   	return n;
  514         else {
  515   	int len = n.length();
  516   
  517   	// We substract 1 from 'len' when assigning to 'end' to avoid out of
  518   	// bounds exception in return r.substring(end+1, len). This can happen if
  519   	// precision is 1 and the category name ends with a dot.
  520   	int end = len -1 ;
  521   	for(int i = precision; i > 0; i--) {
  522   	  end = n.lastIndexOf('.', end-1);
  523   	  if(end == -1)
  524   	    return n;
  525   	}
  526   	return n.substring(end+1, len);
  527         }
  528       }
  529     }
  530   
  531     private class ClassNamePatternConverter extends NamedPatternConverter {
  532   
  533       ClassNamePatternConverter(FormattingInfo formattingInfo, int precision) {
  534         super(formattingInfo, precision);
  535       }
  536   
  537       String getFullyQualifiedName(LoggingEvent event) {
  538         return event.getLocationInformation().getClassName();
  539       }
  540     }
  541   
  542     private class CategoryPatternConverter extends NamedPatternConverter {
  543   
  544       CategoryPatternConverter(FormattingInfo formattingInfo, int precision) {
  545         super(formattingInfo, precision);
  546       }
  547   
  548       String getFullyQualifiedName(LoggingEvent event) {
  549         return event.getLoggerName();
  550       }
  551     }
  552   }
  553   

Save This Page
Home » apache-log4j-1.2.15 » org.apache » log4j » helpers » [javadoc | source]