Author: carnold Date: Tue Mar 7 22:14:45 2006 New Revision: 384131 URL: http://svn.apache.org/viewcvs?rev=384131&view=rev Log: Bug 38024: Restored PatternLayout.createPatternLayout for log4j 1.2 compat
Added: logging/log4j/trunk/src/java/org/apache/log4j/helpers/FormattingInfo.java logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternConverter.java logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternParser.java logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternConverter.java logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternParser.java logging/log4j/trunk/tests/input/pattern/patternLayout15.properties logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternLayout.java logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternParser.java logging/log4j/trunk/tests/witness/pattern/patternLayout.15 Modified: logging/log4j/trunk/src/java/org/apache/log4j/PatternLayout.java logging/log4j/trunk/tests/src/java/org/apache/log4j/PatternLayoutTestCase.java Modified: logging/log4j/trunk/src/java/org/apache/log4j/PatternLayout.java URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/PatternLayout.java?rev=384131&r1=384130&r2=384131&view=diff ============================================================================== --- logging/log4j/trunk/src/java/org/apache/log4j/PatternLayout.java (original) +++ logging/log4j/trunk/src/java/org/apache/log4j/PatternLayout.java Tue Mar 7 22:14:45 2006 @@ -17,18 +17,9 @@ package org.apache.log4j; import org.apache.log4j.helpers.OptionConverter; -import org.apache.log4j.pattern.FormattingInfo; -import org.apache.log4j.pattern.LiteralPatternConverter; -import org.apache.log4j.pattern.LoggingEventPatternConverter; -import org.apache.log4j.pattern.PatternParser; +import org.apache.log4j.helpers.PatternConverter; +import org.apache.log4j.pattern.BridgePatternConverter; import org.apache.log4j.spi.LoggingEvent; -import org.apache.log4j.spi.LoggerRepositoryEx; - - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; // Contributors: Nelson Minar <[EMAIL PROTECTED]> @@ -439,25 +430,16 @@ */ public static final String PATTERN_RULE_REGISTRY = "PATTERN_RULE_REGISTRY"; - /** - * Conversion pattern. - */ - private String conversionPattern; - - /** - * Pattern converters. - */ - private LoggingEventPatternConverter[] patternConverters; /** - * Field widths and alignment corresponding to pattern converters. - */ - private FormattingInfo[] patternFields; + * Initial converter for pattern. + */ + private PatternConverter head; /** - * String buffer used in formatting. + * Conversion pattern. */ - private StringBuffer buf = new StringBuffer(); + private String conversionPattern; /** * True if any element in pattern formats information from exceptions. @@ -477,9 +459,15 @@ * Constructs a PatternLayout using the supplied conversion pattern. * @param pattern conversion pattern. */ - public PatternLayout(String pattern) { + public PatternLayout(final String pattern) { this.conversionPattern = pattern; - activateOptions(); + head = createPatternParser( + (pattern == null) ? DEFAULT_CONVERSION_PATTERN : pattern).parse(); + if (head instanceof BridgePatternConverter) { + handlesExceptions = !((BridgePatternConverter) head).ignoresThrowable(); + } else { + handlesExceptions = false; + } } /** @@ -489,9 +477,15 @@ * * @param conversionPattern conversion pattern. */ - public void setConversionPattern(String conversionPattern) { + public void setConversionPattern(final String conversionPattern) { this.conversionPattern = OptionConverter.convertSpecialChars(conversionPattern); + head = createPatternParser(this.conversionPattern).parse(); + if (head instanceof BridgePatternConverter) { + handlesExceptions = !((BridgePatternConverter) head).ignoresThrowable(); + } else { + handlesExceptions = false; + } } /** @@ -502,69 +496,41 @@ return conversionPattern; } + + /** + Returns PatternParser used to parse the conversion string. Subclasses + may override this to return a subclass of PatternParser which recognize + custom conversion characters. + + @since 0.9.0 + */ + protected org.apache.log4j.helpers.PatternParser createPatternParser(String pattern) { + return new org.apache.log4j.pattern.BridgePatternParser(pattern, + repository, getLogger()); + } + + /** Activates the conversion pattern. Do not forget to call this method after you change the parameters of the PatternLayout instance. */ public void activateOptions() { - List converters = new ArrayList(); - List fields = new ArrayList(); - Map converterRegistry = null; - - if (this.repository != null) { - if (repository instanceof LoggerRepositoryEx) { - converterRegistry = - (Map) ((LoggerRepositoryEx) repository).getObject(PATTERN_RULE_REGISTRY); - } - } - - PatternParser.parse( - conversionPattern, converters, fields, converterRegistry, - PatternParser.getPatternLayoutRules(), getLogger()); - - patternConverters = new LoggingEventPatternConverter[converters.size()]; - patternFields = new FormattingInfo[converters.size()]; - - int i = 0; - Iterator converterIter = converters.iterator(); - Iterator fieldIter = fields.iterator(); - - while (converterIter.hasNext()) { - Object converter = converterIter.next(); - - if (converter instanceof LoggingEventPatternConverter) { - patternConverters[i] = (LoggingEventPatternConverter) converter; - handlesExceptions |= patternConverters[i].handlesThrowable(); - } else { - patternConverters[i] = new LiteralPatternConverter(""); - } - - if (fieldIter.hasNext()) { - patternFields[i] = (FormattingInfo) fieldIter.next(); - } else { - patternFields[i] = FormattingInfo.getDefault(); - } - - i++; - } + // nothing to do. } + /** * Formats a logging event to a writer. * @param event logging event to be formatted. */ public String format(final LoggingEvent event) { - buf.setLength(0); - - for (int i = 0; i < patternConverters.length; i++) { - int startField = buf.length(); - patternConverters[i].format(event, buf); - patternFields[i].format(startField, buf); - } - - String retval = buf.toString(); - buf.setLength(0); - return retval; + StringBuffer buf = new StringBuffer(); + for(PatternConverter c = head; + c != null; + c = c.next) { + c.format(buf, event); + } + return buf.toString(); } /** Added: logging/log4j/trunk/src/java/org/apache/log4j/helpers/FormattingInfo.java URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/helpers/FormattingInfo.java?rev=384131&view=auto ============================================================================== --- logging/log4j/trunk/src/java/org/apache/log4j/helpers/FormattingInfo.java (added) +++ logging/log4j/trunk/src/java/org/apache/log4j/helpers/FormattingInfo.java Tue Mar 7 22:14:45 2006 @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.helpers; + + +/** + FormattingInfo instances contain the information obtained when parsing + formatting modifiers in conversion modifiers. + + @author <a href=mailto:[EMAIL PROTECTED]>Jim Cakalic</a> + @author Ceki Gülcü + + @since 0.8.2 + @deprecated Since 1.3 + */ +public class FormattingInfo { + int min = -1; + int max = Integer.MAX_VALUE; + boolean leftAlign = false; + + void reset() { + min = -1; + max = Integer.MAX_VALUE; + leftAlign = false; + } + + void dump() { + LogLog.debug("min="+min+", max="+max+", leftAlign="+leftAlign); + } +} + Added: logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternConverter.java URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternConverter.java?rev=384131&view=auto ============================================================================== --- logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternConverter.java (added) +++ logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternConverter.java Tue Mar 7 22:14:45 2006 @@ -0,0 +1,111 @@ +/* + * Copyright 1999-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.helpers; + +import org.apache.log4j.spi.LoggingEvent; + +/** + + <p>PatternConverter is an abtract class that provides the + formatting functionality that derived classes need. + + <p>Conversion specifiers in a conversion patterns are parsed to + individual PatternConverters. Each of which is responsible for + converting a logging event in a converter specific manner. + + @author <a href="mailto:[EMAIL PROTECTED]">James P. Cakalic</a> + @author Ceki Gülcü + + @since 0.8.2 + @deprecated Since 1.3 + */ +public abstract class PatternConverter { + public PatternConverter next; + int min = -1; + int max = Integer.MAX_VALUE; + boolean leftAlign = false; + + protected + PatternConverter() { } + + protected + PatternConverter(FormattingInfo fi) { + min = fi.min; + max = fi.max; + leftAlign = fi.leftAlign; + } + + /** + Derived pattern converters must override this method in order to + convert conversion specifiers in the correct way. + */ + abstract + protected + String convert(LoggingEvent event); + + /** + A template method for formatting in a converter specific way. + */ + public + void format(StringBuffer sbuf, LoggingEvent e) { + String s = convert(e); + + if(s == null) { + if(0 < min) + spacePad(sbuf, min); + return; + } + + int len = s.length(); + + if(len > max) + sbuf.append(s.substring(len-max)); + else if(len < min) { + if(leftAlign) { + sbuf.append(s); + spacePad(sbuf, min-len); + } + else { + spacePad(sbuf, min-len); + sbuf.append(s); + } + } + else + sbuf.append(s); + } + + static String[] SPACES = {" ", " ", " ", " ", //1,2,4,8 spaces + " ", // 16 spaces + " " }; // 32 spaces + + /** + Fast space padding method. + */ + public + void spacePad(StringBuffer sbuf, int length) { + while(length >= 32) { + sbuf.append(SPACES[5]); + length -= 32; + } + + for(int i = 4; i >= 0; i--) { + if((length & (1<<i)) != 0) { + sbuf.append(SPACES[i]); + } + } + } +} Added: logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternParser.java URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternParser.java?rev=384131&view=auto ============================================================================== --- logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternParser.java (added) +++ logging/log4j/trunk/src/java/org/apache/log4j/helpers/PatternParser.java Tue Mar 7 22:14:45 2006 @@ -0,0 +1,552 @@ +/* + * Copyright 1999-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.log4j.helpers; + +import org.apache.log4j.Layout; +import org.apache.log4j.spi.LocationInfo; +import org.apache.log4j.spi.LoggingEvent; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +// Contributors: Nelson Minar <([EMAIL PROTECTED]> +// Igor E. Poteryaev <[EMAIL PROTECTED]> +// Reinhard Deschler <[EMAIL PROTECTED]> + +/** + Most of the work of the [EMAIL PROTECTED] org.apache.log4j.PatternLayout} class + is delegated to the PatternParser class. + + <p>It is this class that parses conversion patterns and creates + a chained list of [EMAIL PROTECTED] OptionConverter OptionConverters}. + + @author <a href=mailto:"[EMAIL PROTECTED]">James P. Cakalic</a> + @author Ceki Gülcü + @author Anders Kristensen + + @since 0.8.2 + @deprecated Since 1.3 +*/ +public class PatternParser { + + private static final char ESCAPE_CHAR = '%'; + + private static final int LITERAL_STATE = 0; + private static final int CONVERTER_STATE = 1; + private static final int MINUS_STATE = 2; + private static final int DOT_STATE = 3; + private static final int MIN_STATE = 4; + private static final int MAX_STATE = 5; + + static final int FULL_LOCATION_CONVERTER = 1000; + static final int METHOD_LOCATION_CONVERTER = 1001; + static final int CLASS_LOCATION_CONVERTER = 1002; + static final int LINE_LOCATION_CONVERTER = 1003; + static final int FILE_LOCATION_CONVERTER = 1004; + + static final int RELATIVE_TIME_CONVERTER = 2000; + static final int THREAD_CONVERTER = 2001; + static final int LEVEL_CONVERTER = 2002; + static final int NDC_CONVERTER = 2003; + static final int MESSAGE_CONVERTER = 2004; + + int state; + protected StringBuffer currentLiteral = new StringBuffer(32); + protected int patternLength; + protected int i; + PatternConverter head; + PatternConverter tail; + protected FormattingInfo formattingInfo = new FormattingInfo(); + protected String pattern; + + public + PatternParser(String pattern) { + this.pattern = pattern; + patternLength = pattern.length(); + state = LITERAL_STATE; + } + + private + void addToList(PatternConverter pc) { + if(head == null) { + head = tail = pc; + } else { + tail.next = pc; + tail = pc; + } + } + + protected + String extractOption() { + if((i < patternLength) && (pattern.charAt(i) == '{')) { + int end = pattern.indexOf('}', i); + if (end > i) { + String r = pattern.substring(i + 1, end); + i = end+1; + return r; + } + } + return null; + } + + + /** + The option is expected to be in decimal and positive. In case of + error, zero is returned. */ + protected + int extractPrecisionOption() { + String opt = extractOption(); + int r = 0; + if(opt != null) { + try { + r = Integer.parseInt(opt); + if(r <= 0) { + LogLog.error( + "Precision option (" + opt + ") isn't a positive integer."); + r = 0; + } + } + catch (NumberFormatException e) { + LogLog.error("Category option \""+opt+"\" not a decimal integer.", e); + } + } + return r; + } + + public + PatternConverter parse() { + char c; + i = 0; + while(i < patternLength) { + c = pattern.charAt(i++); + switch(state) { + case LITERAL_STATE: + // In literal state, the last char is always a literal. + if(i == patternLength) { + currentLiteral.append(c); + continue; + } + if(c == ESCAPE_CHAR) { + // peek at the next char. + switch(pattern.charAt(i)) { + case ESCAPE_CHAR: + currentLiteral.append(c); + i++; // move pointer + break; + case 'n': + currentLiteral.append(Layout.LINE_SEP); + i++; // move pointer + break; + default: + if(currentLiteral.length() != 0) { + addToList(new LiteralPatternConverter( + currentLiteral.toString())); + //LogLog.debug("Parsed LITERAL converter: \"" + // +currentLiteral+"\"."); + } + currentLiteral.setLength(0); + currentLiteral.append(c); // append % + state = CONVERTER_STATE; + formattingInfo.reset(); + } + } + else { + currentLiteral.append(c); + } + break; + case CONVERTER_STATE: + currentLiteral.append(c); + switch(c) { + case '-': + formattingInfo.leftAlign = true; + break; + case '.': + state = DOT_STATE; + break; + default: + if(c >= '0' && c <= '9') { + formattingInfo.min = c - '0'; + state = MIN_STATE; + } + else + finalizeConverter(c); + } // switch + break; + case MIN_STATE: + currentLiteral.append(c); + if(c >= '0' && c <= '9') + formattingInfo.min = formattingInfo.min*10 + (c - '0'); + else if(c == '.') + state = DOT_STATE; + else { + finalizeConverter(c); + } + break; + case DOT_STATE: + currentLiteral.append(c); + if(c >= '0' && c <= '9') { + formattingInfo.max = c - '0'; + state = MAX_STATE; + } + else { + LogLog.error("Error occured in position "+i + +".\n Was expecting digit, instead got char \""+c+"\"."); + state = LITERAL_STATE; + } + break; + case MAX_STATE: + currentLiteral.append(c); + if(c >= '0' && c <= '9') + formattingInfo.max = formattingInfo.max*10 + (c - '0'); + else { + finalizeConverter(c); + state = LITERAL_STATE; + } + break; + } // switch + } // while + if(currentLiteral.length() != 0) { + addToList(new LiteralPatternConverter(currentLiteral.toString())); + //LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\"."); + } + return head; + } + + protected + void finalizeConverter(char c) { + PatternConverter pc = null; + switch(c) { + case 'c': + pc = new CategoryPatternConverter(formattingInfo, + extractPrecisionOption()); + //LogLog.debug("CATEGORY converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 'C': + pc = new ClassNamePatternConverter(formattingInfo, + extractPrecisionOption()); + //LogLog.debug("CLASS_NAME converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 'd': + String dateFormatStr = AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT; + DateFormat df; + String dOpt = extractOption(); + if(dOpt != null) + dateFormatStr = dOpt; + + if(dateFormatStr.equalsIgnoreCase( + AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT)) + df = new ISO8601DateFormat(); + else if(dateFormatStr.equalsIgnoreCase( + AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT)) + df = new AbsoluteTimeDateFormat(); + else if(dateFormatStr.equalsIgnoreCase( + AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT)) + df = new DateTimeDateFormat(); + else { + try { + df = new SimpleDateFormat(dateFormatStr); + } + catch (IllegalArgumentException e) { + LogLog.error("Could not instantiate SimpleDateFormat with " + + dateFormatStr, e); + df = (DateFormat) OptionConverter.instantiateByClassName( + "org.apache.log4j.helpers.ISO8601DateFormat", + DateFormat.class, null); + } + } + pc = new DatePatternConverter(formattingInfo, df); + //LogLog.debug("DATE converter {"+dateFormatStr+"}."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 'F': + pc = new LocationPatternConverter(formattingInfo, + FILE_LOCATION_CONVERTER); + //LogLog.debug("File name converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 'l': + pc = new LocationPatternConverter(formattingInfo, + FULL_LOCATION_CONVERTER); + //LogLog.debug("Location converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 'L': + pc = new LocationPatternConverter(formattingInfo, + LINE_LOCATION_CONVERTER); + //LogLog.debug("LINE NUMBER converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 'm': + pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER); + //LogLog.debug("MESSAGE converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 'M': + pc = new LocationPatternConverter(formattingInfo, + METHOD_LOCATION_CONVERTER); + //LogLog.debug("METHOD converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 'p': + pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER); + //LogLog.debug("LEVEL converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 'r': + pc = new BasicPatternConverter(formattingInfo, + RELATIVE_TIME_CONVERTER); + //LogLog.debug("RELATIVE time converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + case 't': + pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER); + //LogLog.debug("THREAD converter."); + //formattingInfo.dump(); + currentLiteral.setLength(0); + break; + /*case 'u': + if(i < patternLength) { + char cNext = pattern.charAt(i); + if(cNext >= '0' && cNext <= '9') { + pc = new UserFieldPatternConverter(formattingInfo, cNext - '0'); + LogLog.debug("USER converter ["+cNext+"]."); + formattingInfo.dump(); + currentLiteral.setLength(0); + i++; + } + else + LogLog.error("Unexpected char" +cNext+" at position "+i); + } + break;*/ + case 'x': + pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER); + //LogLog.debug("NDC converter."); + currentLiteral.setLength(0); + break; + case 'X': + String xOpt = extractOption(); + pc = new MDCPatternConverter(formattingInfo, xOpt); + currentLiteral.setLength(0); + break; + default: + LogLog.error("Unexpected char [" +c+"] at position "+i + +" in conversion patterrn."); + pc = new LiteralPatternConverter(currentLiteral.toString()); + currentLiteral.setLength(0); + } + + addConverter(pc); + } + + protected + void addConverter(PatternConverter pc) { + currentLiteral.setLength(0); + // Add the pattern converter to the list. + addToList(pc); + // Next pattern is assumed to be a literal. + state = LITERAL_STATE; + // Reset formatting info + formattingInfo.reset(); + } + + // --------------------------------------------------------------------- + // PatternConverters + // --------------------------------------------------------------------- + + private static class BasicPatternConverter extends PatternConverter { + int type; + + BasicPatternConverter(FormattingInfo formattingInfo, int type) { + super(formattingInfo); + this.type = type; + } + + public + String convert(LoggingEvent event) { + switch(type) { + case RELATIVE_TIME_CONVERTER: + return (Long.toString(event.timeStamp - LoggingEvent.getStartTime())); + case THREAD_CONVERTER: + return event.getThreadName(); + case LEVEL_CONVERTER: + return event.getLevel().toString(); + case NDC_CONVERTER: + return event.getNDC(); + case MESSAGE_CONVERTER: { + return event.getRenderedMessage(); + } + default: return null; + } + } + } + + private static class LiteralPatternConverter extends PatternConverter { + private String literal; + + LiteralPatternConverter(String value) { + literal = value; + } + + public + final + void format(StringBuffer sbuf, LoggingEvent event) { + sbuf.append(literal); + } + + public + String convert(LoggingEvent event) { + return literal; + } + } + + private static class DatePatternConverter extends PatternConverter { + private DateFormat df; + private Date date; + + DatePatternConverter(FormattingInfo formattingInfo, DateFormat df) { + super(formattingInfo); + date = new Date(); + this.df = df; + } + + public + String convert(LoggingEvent event) { + date.setTime(event.timeStamp); + String converted = null; + try { + converted = df.format(date); + } + catch (Exception ex) { + LogLog.error("Error occured while converting date.", ex); + } + return converted; + } + } + + private static class MDCPatternConverter extends PatternConverter { + private String key; + + MDCPatternConverter(FormattingInfo formattingInfo, String key) { + super(formattingInfo); + this.key = key; + } + + public + String convert(LoggingEvent event) { + Object val = event.getMDC(key); + if(val == null) { + return null; + } else { + return val.toString(); + } + } + } + + + private class LocationPatternConverter extends PatternConverter { + int type; + + LocationPatternConverter(FormattingInfo formattingInfo, int type) { + super(formattingInfo); + this.type = type; + } + + public + String convert(LoggingEvent event) { + LocationInfo locationInfo = event.getLocationInformation(); + switch(type) { + case FULL_LOCATION_CONVERTER: + return locationInfo.fullInfo; + case METHOD_LOCATION_CONVERTER: + return locationInfo.getMethodName(); + case LINE_LOCATION_CONVERTER: + return locationInfo.getLineNumber(); + case FILE_LOCATION_CONVERTER: + return locationInfo.getFileName(); + default: return null; + } + } + } + + private static abstract class NamedPatternConverter extends PatternConverter { + int precision; + + NamedPatternConverter(FormattingInfo formattingInfo, int precision) { + super(formattingInfo); + this.precision = precision; + } + + abstract + String getFullyQualifiedName(LoggingEvent event); + + public + String convert(LoggingEvent event) { + String n = getFullyQualifiedName(event); + if(precision <= 0) + return n; + else { + int len = n.length(); + + // We substract 1 from 'len' when assigning to 'end' to avoid out of + // bounds exception in return r.substring(end+1, len). This can happen if + // precision is 1 and the category name ends with a dot. + int end = len -1 ; + for(int i = precision; i > 0; i--) { + end = n.lastIndexOf('.', end-1); + if(end == -1) + return n; + } + return n.substring(end+1, len); + } + } + } + + private class ClassNamePatternConverter extends NamedPatternConverter { + + ClassNamePatternConverter(FormattingInfo formattingInfo, int precision) { + super(formattingInfo, precision); + } + + String getFullyQualifiedName(LoggingEvent event) { + return event.getLocationInformation().getClassName(); + } + } + + private class CategoryPatternConverter extends NamedPatternConverter { + + CategoryPatternConverter(FormattingInfo formattingInfo, int precision) { + super(formattingInfo, precision); + } + + String getFullyQualifiedName(LoggingEvent event) { + return event.getLoggerName(); + } + } +} + Added: logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternConverter.java URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternConverter.java?rev=384131&view=auto ============================================================================== --- logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternConverter.java (added) +++ logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternConverter.java Tue Mar 7 22:14:45 2006 @@ -0,0 +1,145 @@ +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.pattern; + +import org.apache.log4j.PatternLayout; +import org.apache.log4j.ULogger; +import org.apache.log4j.spi.LoggerRepository; +import org.apache.log4j.spi.LoggerRepositoryEx; +import org.apache.log4j.spi.LoggingEvent; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + + +/** + * The class implements the pre log4j 1.3 org.apache.log4j.helpers.PatternConverter + * contract by delegating to the log4j 1.3 pattern implementation. + * + * + * @author Curt Arnold + * @since 1.3 + * + */ +public final class BridgePatternConverter + extends org.apache.log4j.helpers.PatternConverter { + /** + * Pattern converters. + */ + private LoggingEventPatternConverter[] patternConverters; + + /** + * Field widths and alignment corresponding to pattern converters. + */ + private FormattingInfo[] patternFields; + + /** + * Does pattern process exceptions. + */ + private boolean handlesExceptions; + + /** + * Create a new instance. + * @param pattern pattern, may not be null. + * @param repository logger repository, may be null. + * @param logger logger for internal logging. + */ + public BridgePatternConverter( + final String pattern, final LoggerRepository repository, + final ULogger logger) { + next = null; + handlesExceptions = false; + + List converters = new ArrayList(); + List fields = new ArrayList(); + Map converterRegistry = null; + + if (repository instanceof LoggerRepositoryEx) { + converterRegistry = + (Map) ((LoggerRepositoryEx) repository).getObject( + PatternLayout.PATTERN_RULE_REGISTRY); + } + + PatternParser.parse( + pattern, converters, fields, converterRegistry, + PatternParser.getPatternLayoutRules(), logger); + + patternConverters = new LoggingEventPatternConverter[converters.size()]; + patternFields = new FormattingInfo[converters.size()]; + + int i = 0; + Iterator converterIter = converters.iterator(); + Iterator fieldIter = fields.iterator(); + + while (converterIter.hasNext()) { + Object converter = converterIter.next(); + + if (converter instanceof LoggingEventPatternConverter) { + patternConverters[i] = (LoggingEventPatternConverter) converter; + handlesExceptions |= patternConverters[i].handlesThrowable(); + } else { + patternConverters[i] = + new org.apache.log4j.pattern.LiteralPatternConverter(""); + } + + if (fieldIter.hasNext()) { + patternFields[i] = (FormattingInfo) fieldIter.next(); + } else { + patternFields[i] = FormattingInfo.getDefault(); + } + + i++; + } + } + + /** + * [EMAIL PROTECTED] + */ + protected String convert(final LoggingEvent event) { + // + // code should be unreachable. + // + StringBuffer sbuf = new StringBuffer(); + format(sbuf, event); + + return sbuf.toString(); + } + + /** + Format event to string buffer. + @param sbuf string buffer to receive formatted event, may not be null. + @param e event to format, may not be null. + */ + public void format(final StringBuffer sbuf, final LoggingEvent e) { + for (int i = 0; i < patternConverters.length; i++) { + int startField = sbuf.length(); + patternConverters[i].format(e, sbuf); + patternFields[i].format(startField, sbuf); + } + } + + /** + * Will return false if any of the conversion specifiers in the pattern + * handles [EMAIL PROTECTED] Exception Exceptions}. + * @return true if the pattern formats any information from exceptions. + */ + public boolean ignoresThrowable() { + return !handlesExceptions; + } +} Added: logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternParser.java URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternParser.java?rev=384131&view=auto ============================================================================== --- logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternParser.java (added) +++ logging/log4j/trunk/src/java/org/apache/log4j/pattern/BridgePatternParser.java Tue Mar 7 22:14:45 2006 @@ -0,0 +1,65 @@ +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.pattern; + +import org.apache.log4j.ULogger; +import org.apache.log4j.spi.LoggerRepository; + + +/** + * The class implements the pre log4j 1.3 org.apache.log4j.helpers.PatternConverter + * contract by delegating to the log4j 1.3 pattern implementation. + * + * + * @author Curt Arnold + * @since 1.3 + * + */ +public final class BridgePatternParser + extends org.apache.log4j.helpers.PatternParser { + /** + * Logger repository. + */ + private final LoggerRepository repository; + + /** + * Internal logger. + */ + private final ULogger logger; + + /** + * Create a new instance. + * @param conversionPattern pattern, may not be null. + * @param repository repository, may be null. + * @param logger internal logger, may be null. + */ + public BridgePatternParser( + final String conversionPattern, final LoggerRepository repository, + final ULogger logger) { + super(conversionPattern); + this.repository = repository; + this.logger = logger; + } + + /** + * Create new pattern converter. + * @return pattern converter. + */ + public org.apache.log4j.helpers.PatternConverter parse() { + return new BridgePatternConverter(pattern, repository, logger); + } +} Added: logging/log4j/trunk/tests/input/pattern/patternLayout15.properties URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/pattern/patternLayout15.properties?rev=384131&view=auto ============================================================================== --- logging/log4j/trunk/tests/input/pattern/patternLayout15.properties (added) +++ logging/log4j/trunk/tests/input/pattern/patternLayout15.properties Tue Mar 7 22:14:45 2006 @@ -0,0 +1,12 @@ +log4j.rootCategory=TRACE, testAppender +log4j.appender.testAppender=org.apache.log4j.FileAppender +log4j.appender.testAppender.File= output/temp +log4j.appender.testAppender.Append=false +log4j.appender.testAppender.layout=org.apache.log4j.MyPatternLayout +log4j.appender.testAppender.layout.ConversionPattern=%5p %-4# - %m%n + +# Prevent internal log4j DEBUG messages from polluting the output. +log4j.logger.org.apache.log4j.PropertyConfigurator=INFO +log4j.logger.org.apache.log4j.config.PropertySetter=INFO +log4j.logger.org.apache.log4j.FileAppender=INFO + Added: logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternLayout.java URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternLayout.java?rev=384131&view=auto ============================================================================== --- logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternLayout.java (added) +++ logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternLayout.java Tue Mar 7 22:14:45 2006 @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j; +import org.apache.log4j.helpers.PatternParser; + +/** + + Example showing how to extend PatternLayout to recognize additional + conversion characters. + + <p>In this case MyPatternLayout recognizes %# conversion pattern. It + outputs the value of an internal counter which is also incremented + at each call. + + <p>See <a href=doc-files/MyPatternLayout.java><b>source</b></a> code + for more details. + + @see MyPatternParser + @see org.apache.log4j.PatternLayout + @author Anders Kristensen +*/ +public class MyPatternLayout extends PatternLayout { + public + MyPatternLayout() { + this(DEFAULT_CONVERSION_PATTERN); + } + + public + MyPatternLayout(String pattern) { + super(pattern); + } + + public + PatternParser createPatternParser(String pattern) { + return new MyPatternParser( + pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern); + } +} Added: logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternParser.java URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternParser.java?rev=384131&view=auto ============================================================================== --- logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternParser.java (added) +++ logging/log4j/trunk/tests/src/java/org/apache/log4j/MyPatternParser.java Tue Mar 7 22:14:45 2006 @@ -0,0 +1,71 @@ +/* + * Copyright 1999-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j; + +import org.apache.log4j.helpers.FormattingInfo; +import org.apache.log4j.helpers.PatternConverter; +import org.apache.log4j.helpers.PatternParser; +import org.apache.log4j.spi.LoggingEvent; + +/** + Example showing how to extend PatternParser to recognize additional + conversion characters. The examples shows that minimum and maximum + width and alignment settings apply for "extension" conversion + characters just as they do for PatternLayout recognized characters. + + <p>In this case MyPatternParser recognizes %# and outputs the value + of an internal counter which is also incremented at each call. + + See <a href=doc-files/MyPatternParser.java><b>source</b></a> code + for more details. + + @see org.apache.log4j.MyPatternLayout + @see org.apache.log4j.helpers.PatternParser + @see org.apache.log4j.PatternLayout + + @author Anders Kristensen +*/ +public class MyPatternParser extends PatternParser { + + int counter = 0; + + public + MyPatternParser(String pattern) { + super(pattern); + } + + public + void finalizeConverter(char c) { + if (c == '#') { + addConverter(new UserDirPatternConverter(formattingInfo)); + currentLiteral.setLength(0); + } else { + super.finalizeConverter(c); + } + } + + private class UserDirPatternConverter extends PatternConverter { + UserDirPatternConverter(FormattingInfo formattingInfo) { + super(formattingInfo); + } + + public + String convert(LoggingEvent event) { + return String.valueOf(++counter); + } + } +} Modified: logging/log4j/trunk/tests/src/java/org/apache/log4j/PatternLayoutTestCase.java URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/PatternLayoutTestCase.java?rev=384131&r1=384130&r2=384131&view=diff ============================================================================== --- logging/log4j/trunk/tests/src/java/org/apache/log4j/PatternLayoutTestCase.java (original) +++ logging/log4j/trunk/tests/src/java/org/apache/log4j/PatternLayoutTestCase.java Tue Mar 7 22:14:45 2006 @@ -39,6 +39,8 @@ static String EXCEPTION1 = "java.lang.Exception: Just testing"; static String EXCEPTION2 = "\\s*at .*\\(.*:\\d{1,4}\\)"; static String EXCEPTION3 = "\\s*at .*\\(Native Method\\)"; + static String EXCEPTION4 = "\\s*at .*\\(.*Compiled Code\\)"; + static String PAT0 = "\\[main]\\ (DEBUG|INFO|WARN|ERROR|FATAL) .* - Message \\d{1,2}"; static String PAT1 = Filter.ISO8601_PAT + " " + PAT0; @@ -62,7 +64,7 @@ + "apache.log4j.PatternLayoutTestCase.common\\(PatternLayoutTestCase.java:\\d{3}\\): " + "Message \\d{1,2}"; static String PAT14 = - "^(DEBUG| INFO| WARN|ERROR|FATAL)\\ \\d{1,2}\\ *- Message \\d{1,2}"; + "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL)\\ \\d{1,2}\\ *- Message \\d{1,2}"; static String PAT_MDC_1 = ""; Logger root; Logger logger; @@ -322,6 +324,26 @@ assertTrue(Compare.compare(FILTERED, "witness/pattern/patternLayout.mdc.1")); } + /** + * Tests log4j 1.2 style extension of PatternLayout. + * Was test14 in log4j 1.2. + * @throws Exception + */ + public void test15() throws Exception { + PropertyConfigurator.configure("input/pattern/patternLayout15.properties"); + common(); + ControlFilter cf1 = new ControlFilter(new String[]{PAT14, EXCEPTION1, + EXCEPTION2, EXCEPTION3, EXCEPTION4}); + Transformer.transform( + TEMP, FILTERED, + new Filter[] { + cf1, new LineNumberFilter(), new SunReflectFilter(), + new JunitTestRunnerFilter() + }); + assertTrue(Compare.compare(FILTERED, "witness/pattern/patternLayout.15")); + } + + void common() { int i = -1; @@ -341,6 +363,7 @@ root.log(Level.FATAL, "Message " + i); Exception e = new Exception("Just testing"); + logger.debug("Message " + ++i, e); logger.info("Message " + ++i, e); logger.warn("Message " + ++i, e); @@ -422,28 +445,5 @@ root.debug("finished mdc pattern test"); assertTrue(Compare.compare(OUTPUT_FILE, WITNESS_FILE)); - } - - public static Test XXXsuite() { - TestSuite suite = new TestSuite(); - suite.addTest(new PatternLayoutTest("test1")); - - suite.addTest(new PatternLayoutTest("test2")); - suite.addTest(new PatternLayoutTest("test3")); - suite.addTest(new PatternLayoutTest("test4")); - suite.addTest(new PatternLayoutTest("test5")); - suite.addTest(new PatternLayoutTest("test6")); - suite.addTest(new PatternLayoutTest("test7")); - suite.addTest(new PatternLayoutTest("test8")); - suite.addTest(new PatternLayoutTest("test9")); - suite.addTest(new PatternLayoutTest("test10")); - suite.addTest(new PatternLayoutTest("test11")); - suite.addTest(new PatternLayoutTest("test12")); - suite.addTest(new PatternLayoutTest("test13")); - suite.addTest(new PatternLayoutTest("test14")); - suite.addTest(new PatternLayoutTest("testMDC1")); - suite.addTest(new PatternLayoutTest("testMDC2")); - - return suite; } } Added: logging/log4j/trunk/tests/witness/pattern/patternLayout.15 URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/witness/pattern/patternLayout.15?rev=384131&view=auto ============================================================================== --- logging/log4j/trunk/tests/witness/pattern/patternLayout.15 (added) +++ logging/log4j/trunk/tests/witness/pattern/patternLayout.15 Tue Mar 7 22:14:45 2006 @@ -0,0 +1,75 @@ +DEBUG 1 - Message 0 +DEBUG 2 - Message 0 + INFO 3 - Message 1 + INFO 4 - Message 1 + WARN 5 - Message 2 + WARN 6 - Message 2 +ERROR 7 - Message 3 +ERROR 8 - Message 3 +FATAL 9 - Message 4 +FATAL 10 - Message 4 +DEBUG 11 - Message 5 +java.lang.Exception: Just testing + at org.apache.log4j.PatternLayoutTestCase.common(X) + at org.apache.log4j.PatternLayoutTestCase.test15(X) + at java.lang.reflect.Method.invoke(X) + at junit.framework.TestCase.runTest(X) + at junit.framework.TestCase.runBare(X) + at junit.framework.TestResult$1.protect(X) + at junit.framework.TestResult.runProtected(X) + at junit.framework.TestResult.run(X) + at junit.framework.TestCase.run(X) + at junit.framework.TestSuite.runTest(X) + at junit.framework.TestSuite.run(X) + INFO 12 - Message 6 +java.lang.Exception: Just testing + at org.apache.log4j.PatternLayoutTestCase.common(X) + at org.apache.log4j.PatternLayoutTestCase.test15(X) + at java.lang.reflect.Method.invoke(X) + at junit.framework.TestCase.runTest(X) + at junit.framework.TestCase.runBare(X) + at junit.framework.TestResult$1.protect(X) + at junit.framework.TestResult.runProtected(X) + at junit.framework.TestResult.run(X) + at junit.framework.TestCase.run(X) + at junit.framework.TestSuite.runTest(X) + at junit.framework.TestSuite.run(X) + WARN 13 - Message 7 +java.lang.Exception: Just testing + at org.apache.log4j.PatternLayoutTestCase.common(X) + at org.apache.log4j.PatternLayoutTestCase.test15(X) + at java.lang.reflect.Method.invoke(X) + at junit.framework.TestCase.runTest(X) + at junit.framework.TestCase.runBare(X) + at junit.framework.TestResult$1.protect(X) + at junit.framework.TestResult.runProtected(X) + at junit.framework.TestResult.run(X) + at junit.framework.TestCase.run(X) + at junit.framework.TestSuite.runTest(X) + at junit.framework.TestSuite.run(X) +ERROR 14 - Message 8 +java.lang.Exception: Just testing + at org.apache.log4j.PatternLayoutTestCase.common(X) + at org.apache.log4j.PatternLayoutTestCase.test15(X) + at java.lang.reflect.Method.invoke(X) + at junit.framework.TestCase.runTest(X) + at junit.framework.TestCase.runBare(X) + at junit.framework.TestResult$1.protect(X) + at junit.framework.TestResult.runProtected(X) + at junit.framework.TestResult.run(X) + at junit.framework.TestCase.run(X) + at junit.framework.TestSuite.runTest(X) + at junit.framework.TestSuite.run(X) +FATAL 15 - Message 9 +java.lang.Exception: Just testing + at org.apache.log4j.PatternLayoutTestCase.common(X) + at org.apache.log4j.PatternLayoutTestCase.test15(X) + at java.lang.reflect.Method.invoke(X) + at junit.framework.TestCase.runTest(X) + at junit.framework.TestCase.runBare(X) + at junit.framework.TestResult$1.protect(X) + at junit.framework.TestResult.runProtected(X) + at junit.framework.TestResult.run(X) + at junit.framework.TestCase.run(X) + at junit.framework.TestSuite.runTest(X) + at junit.framework.TestSuite.run(X) --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]