This is an automated email from the ASF dual-hosted git repository. pkarwasz pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 83c5193ab4b1e50263e6436cec2b651723e0670d Author: Gary Gregory <[email protected]> AuthorDate: Sun Feb 6 09:27:07 2022 -0500 Add more missing code and tests from Log4j 1.2.17. 2 tests are ignored for now. --- .../main/java/org/apache/log4j/PatternLayout.java | 76 ++- .../org/apache/log4j/helpers/FormattingInfo.java | 39 ++ .../org/apache/log4j/helpers/OptionConverter.java | 3 +- .../org/apache/log4j/helpers/PatternConverter.java | 111 ++++ .../org/apache/log4j/helpers/PatternParser.java | 570 +++++++++++++++++++++ .../src/test/java/org/apache/log4j/LayoutTest.java | 168 ++++++ .../org/apache/log4j/PropertyConfiguratorTest.java | 2 +- .../org/apache/log4j/helpers/DateLayoutTest.java | 288 +++++++++++ .../log4j/helpers/OptionConverterTestCase.java | 177 +++++++ .../log4j/helpers/PatternParserTestCase.java | 131 +++++ .../test/java/org/apache/log4j/util/Compare.java | 150 ++++++ .../src/test/java/org/apache/log4j/xml/XLevel.java | 74 +++ src/changes/changes.xml | 9 + 13 files changed, 1794 insertions(+), 4 deletions(-) diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/PatternLayout.java b/log4j-1.2-api/src/main/java/org/apache/log4j/PatternLayout.java index e250700..da6f87f 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/PatternLayout.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/PatternLayout.java @@ -16,8 +16,9 @@ */ package org.apache.log4j; +import org.apache.log4j.helpers.PatternConverter; +import org.apache.log4j.helpers.PatternParser; import org.apache.log4j.spi.LoggingEvent; -import org.apache.logging.log4j.util.Strings; /** * @@ -35,6 +36,17 @@ public class PatternLayout extends Layout { */ public final static String TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %x - %m%n"; + protected final int BUF_SIZE = 256; + + protected final int MAX_CAPACITY = 1024; + + // output buffer appended to when format() is invoked + private StringBuffer sbuf = new StringBuffer(BUF_SIZE); + + private String pattern; + + private PatternConverter head; + /** * Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN. * @@ -44,17 +56,77 @@ public class PatternLayout extends Layout { this(DEFAULT_CONVERSION_PATTERN); } + /** + * Constructs a PatternLayout using the supplied conversion pattern. + */ public PatternLayout(final String pattern) { + this.pattern = pattern; + head = createPatternParser((pattern == null) ? DEFAULT_CONVERSION_PATTERN : pattern).parse(); + } + /** + * Does not do anything as options become effective + */ + public void activateOptions() { + // nothing to do. + } + + /** + * 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 PatternParser createPatternParser(final String pattern) { + return new PatternParser(pattern); } + /** + * Produces a formatted string as specified by the conversion pattern. + */ @Override public String format(final LoggingEvent event) { - return Strings.EMPTY; + // Reset working stringbuffer + if (sbuf.capacity() > MAX_CAPACITY) { + sbuf = new StringBuffer(BUF_SIZE); + } else { + sbuf.setLength(0); + } + + PatternConverter c = head; + + while (c != null) { + c.format(sbuf, event); + c = c.next; + } + return sbuf.toString(); + } + + /** + * Returns the value of the <b>ConversionPattern</b> option. + */ + public String getConversionPattern() { + return pattern; } + /** + * The PatternLayout does not handle the throwable contained within {@link LoggingEvent LoggingEvents}. Thus, it returns + * <code>true</code>. + * + * @since 0.8.4 + */ @Override public boolean ignoresThrowable() { return true; } + + /** + * Set the <b>ConversionPattern</b> option. This is the string which controls formatting and consists of a mix of + * literal content and conversion specifiers. + */ + public void setConversionPattern(final String conversionPattern) { + pattern = conversionPattern; + head = createPatternParser(conversionPattern).parse(); + } + } diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/FormattingInfo.java b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/FormattingInfo.java new file mode 100644 index 0000000..7b62660 --- /dev/null +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/FormattingInfo.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + * @since 0.8.2 + */ +public class FormattingInfo { + int min = -1; + int max = 0x7FFFFFFF; + boolean leftAlign = false; + + void dump() { + LogLog.debug("min=" + min + ", max=" + max + ", leftAlign=" + leftAlign); + } + + void reset() { + min = -1; + max = 0x7FFFFFFF; + leftAlign = false; + } +} diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java index 14f19f8..9888979 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java @@ -30,6 +30,7 @@ import org.apache.log4j.spi.Configurator; import org.apache.log4j.spi.LoggerRepository; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.LoaderUtil; import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.Strings; @@ -52,7 +53,7 @@ public class OptionConverter { static char DELIM_STOP = '}'; static int DELIM_START_LEN = 2; static int DELIM_STOP_LEN = 1; - private static final Logger LOGGER = LogManager.getLogger(OptionConverter.class); + private static final Logger LOGGER = StatusLogger.getLogger(); private static final CharMap[] charMap = new CharMap[] { new CharMap('n', '\n'), diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/PatternConverter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/PatternConverter.java new file mode 100644 index 0000000..2b46db7 --- /dev/null +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/PatternConverter.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + */ +public abstract class PatternConverter { + public PatternConverter next; + int min = -1; + int max = 0x7FFFFFFF; + 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]); + } + } + } +} diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/PatternParser.java b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/PatternParser.java new file mode 100644 index 0000000..0d3ead6 --- /dev/null +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/PatternParser.java @@ -0,0 +1,570 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.LoggingEvent; +import org.apache.log4j.spi.LocationInfo; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.Arrays; + +// Contributors: Nelson Minar <([email protected]> +// Igor E. Poteryaev <[email protected]> +// Reinhard Deschler <[email protected]> + +/** + Most of the work of the {@link 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 {@link OptionConverter OptionConverters}. + + @author <a href=mailto:"[email protected]">James P. Cakalic</a> + @author Ceki Gülcü + @author Anders Kristensen + + @since 0.8.2 +*/ +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 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) { + if (key == null) { + StringBuffer buf = new StringBuffer("{"); + Map properties = event.getProperties(); + if (properties.size() > 0) { + Object[] keys = properties.keySet().toArray(); + Arrays.sort(keys); + for (int i = 0; i < keys.length; i++) { + buf.append('{'); + buf.append(keys[i]); + buf.append(','); + buf.append(properties.get(keys[i])); + buf.append('}'); + } + } + buf.append('}'); + return buf.toString(); + } else { + 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(); + } + } +} + diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/LayoutTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/LayoutTest.java new file mode 100644 index 0000000..991c3e9 --- /dev/null +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/LayoutTest.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.spi.LoggingEvent; + +import junit.framework.TestCase; + +/** + * Tests for Layout. + * + */ +public class LayoutTest extends TestCase { + + /** + * Concrete Layout class for tests. + */ + private static final class MockLayout extends Layout { + /** + * @{inheritDoc} + */ + public void activateOptions() { + } + + /** + * @{inheritDoc} + */ + public String format(final LoggingEvent event) { + return "Mock"; + } + + /** + * @{inheritDoc} + */ + public boolean ignoresThrowable() { + return true; + } + } + + /** + * Expected content type. + */ + private final String contentType; + + /** + * Expected value for ignoresThrowable. + */ + private final boolean ignoresThrowable; + + /** + * Expected value for header. + */ + private final String header; + + /** + * Expected value for footer. + */ + private final String footer; + + /** + * Construct a new instance of LayoutTest. + * + * @param testName test name. + */ + public LayoutTest(final String testName) { + super(testName); + contentType = "text/plain"; + ignoresThrowable = true; + header = null; + footer = null; + } + + /** + * Constructor for use by derived tests. + * + * @param testName name of test. + * @param expectedContentType expected value for getContentType(). + * @param expectedIgnoresThrowable expected value for ignoresThrowable(). + * @param expectedHeader expected value for getHeader(). + * @param expectedFooter expected value for getFooter(). + */ + protected LayoutTest(final String testName, final String expectedContentType, final boolean expectedIgnoresThrowable, final String expectedHeader, + final String expectedFooter) { + super(testName); + contentType = expectedContentType; + ignoresThrowable = expectedIgnoresThrowable; + header = expectedHeader; + footer = expectedFooter; + } + + /** + * Creates layout for test. + * + * @return new instance of Layout. + */ + protected Layout createLayout() { + return new MockLayout(); + } + + /** + * Tests format. + * + * @throws Exception derived tests, particular XMLLayoutTest, may throw exceptions. + */ + public void testFormat() throws Exception { + Logger logger = Logger.getLogger("org.apache.log4j.LayoutTest"); + LoggingEvent event = new LoggingEvent("org.apache.log4j.Logger", logger, Level.INFO, "Hello, World", null); + String result = createLayout().format(event); + assertEquals("Mock", result); + } + + /** + * Tests getContentType. + */ + public void testGetContentType() { + assertEquals(contentType, createLayout().getContentType()); + } + + /** + * Tests getFooter. + */ + public void testGetFooter() { + assertEquals(footer, createLayout().getFooter()); + } + + /** + * Tests getHeader. + */ + public void testGetHeader() { + assertEquals(header, createLayout().getHeader()); + } + + /** + * Tests ignoresThrowable. + */ + public void testIgnoresThrowable() { + assertEquals(ignoresThrowable, createLayout().ignoresThrowable()); + } + + /** + * Tests Layout.LINE_SEP. + */ + public void testLineSep() { + assertEquals(System.getProperty("line.separator"), Layout.LINE_SEP); + } + + /** + * Tests Layout.LINE_SEP. + */ + public void testLineSepLen() { + assertEquals(Layout.LINE_SEP.length(), Layout.LINE_SEP_LEN); + } +} diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/PropertyConfiguratorTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/PropertyConfiguratorTest.java index 26812ec..347bfd0 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/PropertyConfiguratorTest.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/PropertyConfiguratorTest.java @@ -406,7 +406,7 @@ public class PropertyConfiguratorTest { assertFalse(file.exists()); } - void validateNested() { + public void validateNested() { final Logger logger = Logger.getLogger("org.apache.log4j.PropertyConfiguratorTest"); final String appenderName = "ROLLING"; // Appender OK diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/helpers/DateLayoutTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/helpers/DateLayoutTest.java new file mode 100644 index 0000000..0573e78 --- /dev/null +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/helpers/DateLayoutTest.java @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.LayoutTest; +import org.apache.log4j.spi.LoggingEvent; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import java.util.TimeZone; +import java.util.Calendar; + +/** + * Tests {@link DateLayout}. + */ +public class DateLayoutTest extends LayoutTest { + + /** + * Construct a new instance of LayoutTest. + * + * @param testName test name. + */ + public DateLayoutTest(final String testName) { + super(testName); + } + + /** + * Constructor for use by derived tests. + * + * @param testName name of test. + * @param expectedContentType expected value for getContentType(). + * @param expectedIgnoresThrowable expected value for ignoresThrowable(). + * @param expectedHeader expected value for getHeader(). + * @param expectedFooter expected value for getFooter(). + */ + protected DateLayoutTest(final String testName, final String expectedContentType, final boolean expectedIgnoresThrowable, final String expectedHeader, + final String expectedFooter) { + super(testName, expectedContentType, expectedIgnoresThrowable, expectedHeader, expectedFooter); + } + + /** + * @{inheritDoc} + */ + protected Layout createLayout() { + return new MockLayout(); + } + + /** + * Tests DateLayout.NULL_DATE_FORMAT constant. + */ + public void testNullDateFormat() { + assertEquals("NULL", DateLayout.NULL_DATE_FORMAT); + } + + /** + * Tests DateLayout.RELATIVE constant. + */ + public void testRelativeTimeDateFormat() { + assertEquals("RELATIVE", DateLayout.RELATIVE_TIME_DATE_FORMAT); + } + + /** + * Tests DateLayout.DATE_FORMAT_OPTION constant. + * + * @deprecated since constant is deprecated + */ + public void testDateFormatOption() { + assertEquals("DateFormat", DateLayout.DATE_FORMAT_OPTION); + } + + /** + * Tests DateLayout.TIMEZONE_OPTION constant. + * + * @deprecated since constant is deprecated + */ + public void testTimeZoneOption() { + assertEquals("TimeZone", DateLayout.TIMEZONE_OPTION); + } + + /** + * Tests getOptionStrings(). + * + * @deprecated since getOptionStrings is deprecated. + * + */ + public void testGetOptionStrings() { + String[] options = ((DateLayout) createLayout()).getOptionStrings(); + assertEquals(2, options.length); + } + + /** + * Tests setting DateFormat through setOption method. + * + * @deprecated since setOption is deprecated. + */ + public void testSetOptionDateFormat() { + DateLayout layout = (DateLayout) createLayout(); + layout.setOption("dAtefOrmat", "foobar"); + assertEquals("FOOBAR", layout.getDateFormat()); + } + + /** + * Tests setting TimeZone through setOption method. + * + * @deprecated since setOption is deprecated. + */ + public void testSetOptionTimeZone() { + DateLayout layout = (DateLayout) createLayout(); + layout.setOption("tImezOne", "+05:00"); + assertEquals("+05:00", layout.getTimeZone()); + } + + /** + * Tests setDateFormat. + */ + public void testSetDateFormat() { + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat("ABSOLUTE"); + assertEquals("ABSOLUTE", layout.getDateFormat()); + } + + /** + * Tests setTimeZone. + */ + public void testSetTimeZone() { + DateLayout layout = (DateLayout) createLayout(); + layout.setTimeZone("+05:00"); + assertEquals("+05:00", layout.getTimeZone()); + } + + /** + * Tests 2 parameter setDateFormat with null. + */ + public void testSetDateFormatNull() { + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat((String) null, null); + } + + /** + * Tests 2 parameter setDateFormat with "NULL". + */ + public void testSetDateFormatNullString() { + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat("NuLL", null); + } + + /** + * Tests 2 parameter setDateFormat with "RELATIVE". + */ + public void testSetDateFormatRelative() { + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat("rElatIve", TimeZone.getDefault()); + } + + /** + * Tests 2 parameter setDateFormat with "ABSOLUTE". + */ + public void testSetDateFormatAbsolute() { + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat("aBsolUte", TimeZone.getDefault()); + } + + /** + * Tests 2 parameter setDateFormat with "DATETIME". + */ + public void testSetDateFormatDateTime() { + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat("dAte", TimeZone.getDefault()); + } + + /** + * Tests 2 parameter setDateFormat with "ISO8601". + */ + public void testSetDateFormatISO8601() { + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat("iSo8601", TimeZone.getDefault()); + } + + /** + * Tests 2 parameter setDateFormat with "HH:mm:ss". + */ + public void testSetDateFormatSimple() { + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat("HH:mm:ss", TimeZone.getDefault()); + } + + /** + * Tests activateOptions. + */ + public void testActivateOptions() { + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat("HH:mm:ss"); + layout.setTimeZone("+05:00"); + layout.activateOptions(); + } + + /** + * Tests setDateFormat(DateFormat, TimeZone). + */ + public void testSetDateFormatWithFormat() { + DateFormat format = new SimpleDateFormat("HH:mm"); + DateLayout layout = (DateLayout) createLayout(); + layout.setDateFormat(format, TimeZone.getDefault()); + } + + /** + * Tests IS08601DateFormat class. + * + * @deprecated since ISO8601DateFormat is deprecated + */ + public void testISO8601Format() { + DateFormat format = new ISO8601DateFormat(); + Calendar calendar = Calendar.getInstance(); + calendar.clear(); + calendar.set(1970, 0, 1, 0, 0, 0); + String actual = format.format(calendar.getTime()); + assertEquals("1970-01-01 00:00:00,000", actual); + } + + /** + * Tests DateTimeDateFormat class. + * + * @deprecated since DateTimeDateFormat is deprecated + */ + public void testDateTimeFormat() { + DateFormat format = new DateTimeDateFormat(); + Calendar calendar = Calendar.getInstance(); + calendar.clear(); + calendar.set(1970, 0, 1, 0, 0, 0); + String actual = format.format(calendar.getTime()); + SimpleDateFormat df = new SimpleDateFormat("dd MMM yyyy HH:mm:ss,SSS"); + String expected = df.format(calendar.getTime()); + assertEquals(expected, actual); + } + + /** + * Concrete Layout class for tests. + */ + private static final class MockLayout extends DateLayout { + /** + * Create new instance of MockLayout. + */ + public MockLayout() { + // + // checks that protected fields are properly initialized + assertNotNull(pos); + assertNotNull(date); + assertNull(dateFormat); + } + + /** + * @{inheritDoc} + */ + public String format(final LoggingEvent event) { + return "Mock"; + } + + /** + * @{inheritDoc} + */ + public void activateOptions() { + } + + /** + * @{inheritDoc} + */ + public boolean ignoresThrowable() { + return true; + } + } +} diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/helpers/OptionConverterTestCase.java b/log4j-1.2-api/src/test/java/org/apache/log4j/helpers/OptionConverterTestCase.java new file mode 100644 index 0000000..83ded20 --- /dev/null +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/helpers/OptionConverterTestCase.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +// Log4j uses the JUnit framework for internal unit testing. JUnit +// is available from "http://www.junit.org". + +package org.apache.log4j.helpers; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.PropertyConfiguratorTest; +import org.apache.log4j.xml.XLevel; +import org.junit.Ignore; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Test variable substitution code. + * + * @since 1.0 + */ +@Ignore("WIP") +public class OptionConverterTestCase extends TestCase { + + Properties props; + + public OptionConverterTestCase(String name) { + super(name); + } + + public void setUp() { + props = new Properties(); + props.put("TOTO", "wonderful"); + props.put("key1", "value1"); + props.put("key2", "value2"); + // Log4J will NPE without this: + props.put("line.separator", System.getProperty("line.separator")); + // Log4J will throw an Error without this: + props.put("java.home", System.getProperty("java.home")); + System.setProperties(props); + + } + + public void tearDown() { + props = null; + LogManager.resetConfiguration(); + } + + public void varSubstTest1() { + String r; + + r = OptionConverter.substVars("hello world.", null); + assertEquals("hello world.", r); + + r = OptionConverter.substVars("hello ${TOTO} world.", null); + + assertEquals("hello wonderful world.", r); + } + + public void varSubstTest2() { + String r; + + r = OptionConverter.substVars("Test2 ${key1} mid ${key2} end.", null); + assertEquals("Test2 value1 mid value2 end.", r); + } + + public void varSubstTest3() { + String r; + + r = OptionConverter.substVars("Test3 ${unset} mid ${key1} end.", null); + assertEquals("Test3 mid value1 end.", r); + } + + public void varSubstTest4() { + String val = "Test4 ${incomplete "; + try { + OptionConverter.substVars(val, null); + } catch (IllegalArgumentException e) { + String errorMsg = e.getMessage(); + // System.out.println('['+errorMsg+']'); + assertEquals('"' + val + "\" has no closing brace. Opening brace at position 6.", errorMsg); + } + } + + public void varSubstTest5() { + Properties props = new Properties(); + props.put("p1", "x1"); + props.put("p2", "${p1}"); + String res = OptionConverter.substVars("${p2}", props); + System.out.println("Result is [" + res + "]."); + assertEquals(res, "x1"); + } + + /** + * Tests configuring Log4J from an InputStream. + * + * @since 1.2.17 + */ + public void testInputStream() throws IOException { + File file = new File("src/test/resources/log4j1-1.2.17/input/filter1.properties"); + assertTrue(file.exists()); + try (FileInputStream inputStream = new FileInputStream(file)) { + OptionConverter.selectAndConfigure(inputStream, null, LogManager.getLoggerRepository()); + } + new PropertyConfiguratorTest().validateNested(); + } + + public void toLevelTest1() { + String val = "INFO"; + Level p = OptionConverter.toLevel(val, null); + assertEquals(p, Level.INFO); + } + + public void toLevelTest2() { + String val = "INFO#org.apache.log4j.xml.XLevel"; + Level p = OptionConverter.toLevel(val, null); + assertEquals(p, Level.INFO); + } + + public void toLevelTest3() { + String val = "TRACE#org.apache.log4j.xml.XLevel"; + Level p = OptionConverter.toLevel(val, null); + assertEquals(p, XLevel.TRACE); + } + + public void toLevelTest4() { + String val = "TR#org.apache.log4j.xml.XLevel"; + Level p = OptionConverter.toLevel(val, null); + assertEquals(p, null); + } + + public void toLevelTest5() { + String val = "INFO#org.apache.log4j.xml.TOTO"; + Level p = OptionConverter.toLevel(val, null); + assertEquals(p, null); + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTest(new OptionConverterTestCase("varSubstTest5")); + suite.addTest(new OptionConverterTestCase("varSubstTest1")); + suite.addTest(new OptionConverterTestCase("varSubstTest2")); + suite.addTest(new OptionConverterTestCase("varSubstTest3")); + suite.addTest(new OptionConverterTestCase("varSubstTest4")); + + suite.addTest(new OptionConverterTestCase("testInputStream")); + + suite.addTest(new OptionConverterTestCase("toLevelTest1")); + suite.addTest(new OptionConverterTestCase("toLevelTest2")); + suite.addTest(new OptionConverterTestCase("toLevelTest3")); + suite.addTest(new OptionConverterTestCase("toLevelTest4")); + suite.addTest(new OptionConverterTestCase("toLevelTest5")); + return suite; + } + +} diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/helpers/PatternParserTestCase.java b/log4j-1.2-api/src/test/java/org/apache/log4j/helpers/PatternParserTestCase.java new file mode 100644 index 0000000..e91cc0f --- /dev/null +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/helpers/PatternParserTestCase.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.Appender; +import org.apache.log4j.FileAppender; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.MDC; +import org.apache.log4j.PatternLayout; +import org.apache.log4j.util.Compare; +import org.junit.Ignore; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Test case for helpers/PatternParser.java. Tests the various conversion patterns supported by PatternParser. This test + * class tests PatternParser via the PatternLayout class which uses it. + */ +@Ignore("WIP") +public class PatternParserTestCase extends TestCase { + + static String OUTPUT_FILE = "target/PatternParser"; + static String WITNESS_FILE = "target/witness/PatternParser"; + + static String msgPattern = "%m%n"; + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTest(new PatternParserTestCase("mdcPattern")); + return suite; + } + Logger root; + + Logger logger; + + public PatternParserTestCase(String name) { + super(name); + } + + /** + * Test case for MDC conversion pattern. + */ + public void mdcPattern() throws Exception { + + String mdcMsgPattern1 = "%m : %X%n"; + String mdcMsgPattern2 = "%m : %X{key1}%n"; + String mdcMsgPattern3 = "%m : %X{key2}%n"; + String mdcMsgPattern4 = "%m : %X{key3}%n"; + String mdcMsgPattern5 = "%m : %X{key1},%X{key2},%X{key3}%n"; + + // set up appender + PatternLayout layout = new PatternLayout(msgPattern); + Appender appender = new FileAppender(layout, OUTPUT_FILE + "_mdc", false); + + // set appender on root and set level to debug + root.addAppender(appender); + root.setLevel(Level.DEBUG); + + // output starting message + root.debug("starting mdc pattern test"); + + layout.setConversionPattern(mdcMsgPattern1); + root.debug("empty mdc, no key specified in pattern"); + + layout.setConversionPattern(mdcMsgPattern2); + root.debug("empty mdc, key1 in pattern"); + + layout.setConversionPattern(mdcMsgPattern3); + root.debug("empty mdc, key2 in pattern"); + + layout.setConversionPattern(mdcMsgPattern4); + root.debug("empty mdc, key3 in pattern"); + + layout.setConversionPattern(mdcMsgPattern5); + root.debug("empty mdc, key1, key2, and key3 in pattern"); + + MDC.put("key1", "value1"); + MDC.put("key2", "value2"); + + layout.setConversionPattern(mdcMsgPattern1); + root.debug("filled mdc, no key specified in pattern"); + + layout.setConversionPattern(mdcMsgPattern2); + root.debug("filled mdc, key1 in pattern"); + + layout.setConversionPattern(mdcMsgPattern3); + root.debug("filled mdc, key2 in pattern"); + + layout.setConversionPattern(mdcMsgPattern4); + root.debug("filled mdc, key3 in pattern"); + + layout.setConversionPattern(mdcMsgPattern5); + root.debug("filled mdc, key1, key2, and key3 in pattern"); + + MDC.remove("key1"); + MDC.remove("key2"); + + layout.setConversionPattern(msgPattern); + root.debug("finished mdc pattern test"); + + assertTrue(Compare.compare(OUTPUT_FILE + "_mdc", WITNESS_FILE + "_mdc")); + } + + public void setUp() { + root = Logger.getRootLogger(); + root.removeAllAppenders(); + } + + public void tearDown() { + root.getLoggerRepository().resetConfiguration(); + } + +} diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/util/Compare.java b/log4j-1.2-api/src/test/java/org/apache/log4j/util/Compare.java new file mode 100644 index 0000000..b65b9e9 --- /dev/null +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/util/Compare.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.util; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class Compare { + + static final int B1_NULL = -1; + static final int B2_NULL = -2; + + public static boolean compare(final Class testClass, final String file1, final String file2) throws IOException { + try (final BufferedReader in1 = new BufferedReader(new FileReader(file1)); + final BufferedReader in2 = new BufferedReader(new InputStreamReader(open(testClass, file2)))) { + return compare(testClass, file1, file2, in1, in2); + } + } + + public static boolean compare(final Class testClass, final String file1, final String file2, final BufferedReader in1, final BufferedReader in2) + throws IOException { + + String s1; + int lineCounter = 0; + + while ((s1 = in1.readLine()) != null) { + lineCounter++; + + final String s2 = in2.readLine(); + + if (!s1.equals(s2)) { + System.out.println("Files [" + file1 + "] and [" + file2 + "] differ on line " + lineCounter); + System.out.println("One reads: [" + s1 + "]."); + System.out.println("Other reads:[" + s2 + "]."); + outputFile(testClass, file1); + outputFile(testClass, file2); + + return false; + } + } + + // the second file is longer + if (in2.read() != -1) { + System.out.println("File [" + file2 + "] longer than file [" + file1 + "]."); + outputFile(testClass, file1); + outputFile(testClass, file2); + + return false; + } + + return true; + } + + static public boolean compare(final String file1, final String file2) throws FileNotFoundException, IOException { + try (final BufferedReader in1 = new BufferedReader(new FileReader(file1)); final BufferedReader in2 = new BufferedReader(new FileReader(file2))) { + + String s1; + int lineCounter = 0; + while ((s1 = in1.readLine()) != null) { + lineCounter++; + final String s2 = in2.readLine(); + if (!s1.equals(s2)) { + System.out.println("Files [" + file1 + "] and [" + file2 + "] differ on line " + lineCounter); + System.out.println("One reads: [" + s1 + "]."); + System.out.println("Other reads:[" + s2 + "]."); + return false; + } + } + + // the second file is longer + if (in2.read() != -1) { + System.out.println("File [" + file2 + "] longer than file [" + file1 + "]."); + return false; + } + + return true; + } + } + + private static final InputStream open(final Class testClass, final String fileName) throws IOException { + String resourceName = fileName; + if (fileName.startsWith("witness/")) { + resourceName = fileName.substring(fileName.lastIndexOf('/') + 1); + } + InputStream is = testClass.getResourceAsStream(resourceName); + if (is == null) { + final File file = new File(fileName); + if (file.exists()) { + is = new FileInputStream(file); + } else { + throw new FileNotFoundException("Resource " + resourceName + " not found"); + } + } + return is; + } + + /** + * + * Prints file on the console. + * + */ + private static void outputFile(final Class testClass, final String file) throws IOException { + try (final InputStream is = open(testClass, file); final BufferedReader in1 = new BufferedReader(new InputStreamReader(is))) { + + String s1; + int lineCounter = 0; + System.out.println("--------------------------------"); + System.out.println("Contents of " + file + ":"); + + while ((s1 = in1.readLine()) != null) { + lineCounter++; + System.out.print(lineCounter); + + if (lineCounter < 10) { + System.out.print(" : "); + } else if (lineCounter < 100) { + System.out.print(" : "); + } else if (lineCounter < 1000) { + System.out.print(" : "); + } else { + System.out.print(": "); + } + + System.out.println(s1); + } + } + } + +} diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/xml/XLevel.java b/log4j-1.2-api/src/test/java/org/apache/log4j/xml/XLevel.java new file mode 100644 index 0000000..b0503b7 --- /dev/null +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/xml/XLevel.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.xml; + +import org.apache.log4j.Level; + +/** + * This class introduces a new level level called TRACE. TRACE has lower level than DEBUG. + */ +public class XLevel extends Level { + private static final long serialVersionUID = 7288304330257085144L; + + public static final int TRACE_INT = Level.DEBUG_INT - 1; + public static final int LETHAL_INT = Level.FATAL_INT + 1; + + private static String TRACE_STR = "TRACE"; + private static String LETHAL_STR = "LETHAL"; + + public static final XLevel TRACE = new XLevel(TRACE_INT, TRACE_STR, 7); + public static final XLevel LETHAL = new XLevel(LETHAL_INT, LETHAL_STR, 0); + + public static Level toLevel(final int i) throws IllegalArgumentException { + switch (i) { + case TRACE_INT: + return XLevel.TRACE; + case LETHAL_INT: + return XLevel.LETHAL; + } + return Level.toLevel(i); + } + + /** + * Convert the string passed as argument to a level. If the conversion fails, then this method returns {@link #TRACE}. + */ + public static Level toLevel(final String sArg) { + return toLevel(sArg, XLevel.TRACE); + } + + public static Level toLevel(final String sArg, final Level defaultValue) { + + if (sArg == null) { + return defaultValue; + } + final String stringVal = sArg.toUpperCase(); + + if (stringVal.equals(TRACE_STR)) { + return XLevel.TRACE; + } else if (stringVal.equals(LETHAL_STR)) { + return XLevel.LETHAL; + } + + return Level.toLevel(sArg, defaultValue); + } + + protected XLevel(final int level, final String strLevel, final int syslogEquiv) { + super(level, strLevel, syslogEquiv); + } + +} diff --git a/src/changes/changes.xml b/src/changes/changes.xml index a8722bd..c0e3c09 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -346,6 +346,15 @@ <action dev="ggregory" type="fix" due-to="Gary Gregory"> Log4j 1.2 bridge missing UtilLoggingLevel. </action> + <action dev="ggregory" type="fix" due-to="Gary Gregory"> + Log4j 1.2 bridge missing FormattingInfo. + </action> + <action dev="ggregory" type="fix" due-to="Gary Gregory"> + Log4j 1.2 bridge missing PatternConverter. + </action> + <action dev="ggregory" type="fix" due-to="Gary Gregory"> + Log4j 1.2 bridge missing PatternParser. + </action> <action dev="ggregory" type="fix"> JndiManager reverts to 2.17.0 behavior: Read the system property for each call. </action>
