Repository: logging-log4j2 Updated Branches: refs/heads/master fee199f66 -> fe021d94b
LOG4J2-1129 - Allow PatternLayout to select a pattern to use based on some selection criteria Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/fe021d94 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/fe021d94 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/fe021d94 Branch: refs/heads/master Commit: fe021d94b385c52eb91b486bd26120630efef53d Parents: fee199f Author: Ralph Goers <[email protected]> Authored: Wed Sep 23 11:42:02 2015 -0700 Committer: Ralph Goers <[email protected]> Committed: Wed Sep 23 11:42:02 2015 -0700 ---------------------------------------------------------------------- .../core/layout/MarkerPatternSelector.java | 125 +++++++++++++++ .../log4j/core/layout/PatternLayout.java | 97 +++++++++--- .../logging/log4j/core/layout/PatternMatch.java | 154 +++++++++++++++++++ .../log4j/core/layout/PatternSelector.java | 30 ++++ .../logging/log4j/core/PatternSelectorTest.java | 53 +++++++ .../core/appender/ConsoleAppenderTest.java | 2 +- .../log4j/core/layout/PatternLayoutTest.java | 37 ++++- .../test/resources/log4j-patternSelector.xml | 33 ++++ .../log4j/perf/jmh/PatternLayoutBenchmark.java | 16 +- .../jmh/PatternLayoutComparisonBenchmark.java | 2 +- src/changes/changes.xml | 3 + 11 files changed, 517 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MarkerPatternSelector.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MarkerPatternSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MarkerPatternSelector.java new file mode 100644 index 0000000..f54cf3a --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MarkerPatternSelector.java @@ -0,0 +1,125 @@ +/* + * 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.logging.log4j.core.layout; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.Node; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; +import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; +import org.apache.logging.log4j.core.pattern.PatternFormatter; +import org.apache.logging.log4j.core.pattern.PatternParser; +import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.status.StatusLogger; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Selects the pattern to use based on the Marker in the LogEvent. + */ +@Plugin(name = "MarkerPatternSelector", category = Node.CATEGORY, elementType = PatternSelector.ELEMENT_TYPE, printObject = true) +public class MarkerPatternSelector implements PatternSelector { + + private final Map<String, PatternFormatter[]> formatterMap = new HashMap<>(); + + private final Map<String, String> patternMap = new HashMap<>(); + + private final PatternFormatter[] defaultFormatters; + + private final String defaultPattern; + + private static Logger LOGGER = StatusLogger.getLogger(); + + + public MarkerPatternSelector(final PatternMatch[] properties, final String defaultPattern, + final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi, + final Configuration config) { + final PatternParser parser = PatternLayout.createPatternParser(config); + for (PatternMatch property : properties) { + try { + List<PatternFormatter> list = parser.parse(property.getPattern(), alwaysWriteExceptions, noConsoleNoAnsi); + formatterMap.put(property.getKey(), list.toArray(new PatternFormatter[list.size()])); + patternMap.put(property.getKey(), property.getPattern()); + } catch (RuntimeException ex) { + throw new IllegalArgumentException("Cannot parse pattern '" + property.getPattern() + "'", ex); + } + } + try { + List<PatternFormatter> list = parser.parse(defaultPattern, alwaysWriteExceptions, noConsoleNoAnsi); + defaultFormatters = list.toArray(new PatternFormatter[list.size()]); + this.defaultPattern = defaultPattern; + } catch (RuntimeException ex) { + throw new IllegalArgumentException("Cannot parse pattern '" + defaultPattern + "'", ex); + } + } + + @Override + public PatternFormatter[] getFormatters(LogEvent event) { + Marker marker = event.getMarker(); + if (marker == null) { + return defaultFormatters; + } + for (String key : formatterMap.keySet()) { + if (marker.isInstanceOf(key)) { + return formatterMap.get(key); + } + } + return defaultFormatters; + } + + + @PluginFactory + public static MarkerPatternSelector createSelector(@PluginElement("PatternMatch") final PatternMatch[] properties, + @PluginAttribute("defaultPattern") String defaultPattern, + @PluginAttribute(value = "alwaysWriteExceptions", defaultBoolean = true) final boolean alwaysWriteExceptions, + @PluginAttribute(value = "noConsoleNoAnsi", defaultBoolean = false) final boolean noConsoleNoAnsi, + @PluginConfiguration final Configuration config) { + if (defaultPattern == null) { + defaultPattern = PatternLayout.DEFAULT_CONVERSION_PATTERN; + } + if (properties == null || properties.length == 0) { + LOGGER.warn("No marker patterns were provided"); + } + return new MarkerPatternSelector(properties, defaultPattern, alwaysWriteExceptions, + noConsoleNoAnsi, config); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (Map.Entry<String, String> entry : patternMap.entrySet()) { + if (!first) { + sb.append(", "); + } + sb.append("key=\"").append(entry.getKey()).append("\", pattern=\"").append(entry.getValue()).append("\""); + first = false; + } + if (!first) { + sb.append(", "); + } + sb.append("default=\"").append(defaultPattern).append("\""); + return sb.toString(); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java index 4ea5627..e5b78d3 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java @@ -93,6 +93,10 @@ public final class PatternLayout extends AbstractStringLayout { */ private final String conversionPattern; + private final PatternSelector patternSelector; + + private final Serializer serializer; + /** * The current Configuration. @@ -111,6 +115,7 @@ public final class PatternLayout extends AbstractStringLayout { * @param config The Configuration. * @param replace The regular expression to match. * @param pattern conversion pattern. + * @param patternSelector The PatternSelector. * @param charset The character set. * @param alwaysWriteExceptions Whether or not exceptions should always be handled in this pattern (if {@code true}, * exceptions will be written even if the pattern does not specify so). @@ -119,21 +124,29 @@ public final class PatternLayout extends AbstractStringLayout { * @param header */ private PatternLayout(final Configuration config, final RegexReplacement replace, final String pattern, - final Charset charset, final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi, + final PatternSelector patternSelector, final Charset charset, + final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi, final String header, final String footer) { super(charset, toBytes(header, charset), toBytes(footer, charset)); this.replace = replace; this.conversionPattern = pattern; + this.patternSelector = patternSelector; this.config = config; this.alwaysWriteExceptions = alwaysWriteExceptions; this.noConsoleNoAnsi = noConsoleNoAnsi; - final PatternParser parser = createPatternParser(config); - try { - List<PatternFormatter> list = parser.parse(pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern, - this.alwaysWriteExceptions, this.noConsoleNoAnsi); - this.formatters = list.toArray(new PatternFormatter[0]); - } catch (RuntimeException ex) { - throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex); + if (patternSelector == null) { + serializer = new PatternSerializer(); + final PatternParser parser = createPatternParser(config); + try { + List<PatternFormatter> list = parser.parse(pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern, + this.alwaysWriteExceptions, this.noConsoleNoAnsi); + this.formatters = list.toArray(new PatternFormatter[0]); + } catch (RuntimeException ex) { + throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex); + } + } else { + this.formatters = null; + serializer = new PatternSelectorSerializer(); } } @@ -191,16 +204,7 @@ public final class PatternLayout extends AbstractStringLayout { */ @Override public String toSerializable(final LogEvent event) { - final StringBuilder buf = prepareStringBuilder(strBuilder); - final int len = formatters.length; - for (int i = 0; i < len; i++) { - formatters[i].format(event, buf); - } - String str = buf.toString(); - if (replace != null) { - str = replace.format(str); - } - return str; + return serializer.toSerializable(event); } /** @@ -223,7 +227,7 @@ public final class PatternLayout extends AbstractStringLayout { @Override public String toString() { - return conversionPattern; + return patternSelector == null ? conversionPattern : patternSelector.toString(); } /** @@ -250,6 +254,7 @@ public final class PatternLayout extends AbstractStringLayout { @PluginFactory public static PatternLayout createLayout( @PluginAttribute(value = "pattern", defaultString = DEFAULT_CONVERSION_PATTERN) final String pattern, + @PluginElement("PatternSelector") final PatternSelector patternSelector, @PluginConfiguration final Configuration config, @PluginElement("Replace") final RegexReplacement replace, @PluginAttribute(value = "charset", defaultString = "UTF-8") final Charset charset, @@ -259,6 +264,7 @@ public final class PatternLayout extends AbstractStringLayout { @PluginAttribute("footer") final String footer) { return newBuilder() .withPattern(pattern) + .withPatternSelector(patternSelector) .withConfiguration(config) .withRegexReplacement(replace) .withCharset(charset) @@ -269,6 +275,47 @@ public final class PatternLayout extends AbstractStringLayout { .build(); } + + private interface Serializer { + + String toSerializable(final LogEvent event); + } + + private class PatternSerializer implements Serializer { + @Override + public String toSerializable(final LogEvent event) { + final StringBuilder buf = strBuilder.get(); + buf.setLength(0); + final int len = formatters.length; + for (int i = 0; i < len; i++) { + formatters[i].format(event, buf); + } + String str = buf.toString(); + if (replace != null) { + str = replace.format(str); + } + return str; + } + } + + private class PatternSelectorSerializer implements Serializer { + @Override + public String toSerializable(final LogEvent event) { + final StringBuilder buf = strBuilder.get(); + buf.setLength(0); + PatternFormatter[] formatters = patternSelector.getFormatters(event); + final int len = formatters.length; + for (int i = 0; i < len; i++) { + formatters[i].format(event, buf); + } + String str = buf.toString(); + if (replace != null) { + str = replace.format(str); + } + return str; + } + } + /** * Creates a PatternLayout using the default options. These options include using UTF-8, the default conversion * pattern, exceptions being written, and with ANSI escape codes. @@ -300,6 +347,9 @@ public final class PatternLayout extends AbstractStringLayout { @PluginBuilderAttribute private String pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN; + @PluginElement("PatternSelector") + private PatternSelector patternSelector = null; + @PluginConfiguration private Configuration configuration = null; @@ -332,6 +382,11 @@ public final class PatternLayout extends AbstractStringLayout { return this; } + public Builder withPatternSelector(final PatternSelector patternSelector) { + this.patternSelector = patternSelector; + return this; + } + public Builder withConfiguration(final Configuration configuration) { this.configuration = configuration; @@ -374,8 +429,8 @@ public final class PatternLayout extends AbstractStringLayout { if (configuration == null) { configuration = new DefaultConfiguration(); } - return new PatternLayout(configuration, regexReplacement, pattern, charset, alwaysWriteExceptions, - noConsoleNoAnsi, header, footer); + return new PatternLayout(configuration, regexReplacement, pattern, patternSelector, charset, + alwaysWriteExceptions, noConsoleNoAnsi, header, footer); } } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternMatch.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternMatch.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternMatch.java new file mode 100644 index 0000000..2633c54 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternMatch.java @@ -0,0 +1,154 @@ +/* + * 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.logging.log4j.core.layout; + +import org.apache.logging.log4j.core.config.Node; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; + +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; + +/** + * PatternMatch configuration item. + * + * @since 2.4.1 implements {@link Serializable} + */ +@Plugin(name = "PatternMatch", category = Node.CATEGORY, printObject = true) +public final class PatternMatch implements Serializable { + + private static final long serialVersionUID = 4331228262821046877L; + + private final String key; + private final String pattern; + + /** + * Constructs a key/value pair. The constructor should only be called from test classes. + * @param key The key. + * @param pattern The value. + */ + public PatternMatch(final String key, final String pattern) { + this.key = key; + this.pattern = pattern; + } + + /** + * Returns the key. + * @return the key. + */ + public String getKey() { + return key; + } + + /** + * Returns the pattern. + * @return The pattern. + */ + public String getPattern() { + return pattern; + } + + @Override + public String toString() { + return key + '=' + pattern; + } + + @PluginBuilderFactory + public static Builder newBuilder() { + return new Builder(); + } + + protected Object writeReplace() throws ObjectStreamException { + return newBuilder().setKey(this.key).setPattern(this.pattern); + } + + private void readObject(final ObjectInputStream stream) throws InvalidObjectException { + throw new InvalidObjectException("Builder proxy required"); + } + + public static class Builder implements org.apache.logging.log4j.core.util.Builder<PatternMatch>, Serializable { + + private static final long serialVersionUID = 1L; + + @PluginBuilderAttribute + private String key; + + @PluginBuilderAttribute + private String pattern; + + public Builder setKey(final String key) { + this.key = key; + return this; + } + + public Builder setPattern(final String pattern) { + this.pattern = pattern; + return this; + } + + @Override + public PatternMatch build() { + return new PatternMatch(key, pattern); + } + + protected Object readResolve() throws ObjectStreamException { + return new PatternMatch(key, pattern); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + result = prime * result + ((pattern == null) ? 0 : pattern.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PatternMatch other = (PatternMatch) obj; + if (key == null) { + if (other.key != null) { + return false; + } + } else if (!key.equals(other.key)) { + return false; + } + if (pattern == null) { + if (other.pattern != null) { + return false; + } + } else if (!pattern.equals(other.pattern)) { + return false; + } + return true; + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternSelector.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternSelector.java new file mode 100644 index 0000000..78c9b49 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternSelector.java @@ -0,0 +1,30 @@ +/* + * 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.logging.log4j.core.layout; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.pattern.PatternFormatter; + +/** + * Allows different patterns to be used with the PatternLayout based on some selection criteria. + */ +public interface PatternSelector { + + String ELEMENT_TYPE = "patternSelector"; + + PatternFormatter[] getFormatters(LogEvent event); +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-core/src/test/java/org/apache/logging/log4j/core/PatternSelectorTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/PatternSelectorTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/PatternSelectorTest.java new file mode 100644 index 0000000..06a5ef3 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/PatternSelectorTest.java @@ -0,0 +1,53 @@ +/* + * 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.logging.log4j.core; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.apache.logging.log4j.test.appender.ListAppender; +import org.junit.ClassRule; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.*; +/** + * + */ +public class PatternSelectorTest { + + + private static final String CONFIG = "log4j-patternSelector.xml"; + + @ClassRule + public static LoggerContextRule context = new LoggerContextRule(CONFIG); + + @Test + public void testPatternSelector() throws Exception { + org.apache.logging.log4j.Logger logger = LogManager.getLogger("TestPatternSelector"); + logger.entry(); + logger.info("Hello World"); + logger.exit(); + final ListAppender app = (ListAppender) context.getRequiredAppender("List"); + assertNotNull("No ListAppender", app); + List<String> messages = app.getMessages(); + assertNotNull("No Messages", messages); + assertTrue("Incorrect number of messages. Expected 3, Actual " + messages.size(), messages.size() == 3); + assertEquals("[TRACE] TestPatternSelector ====== o.a.l.l.c.PatternSelectorTest.testPatternSelector:42 entry ======\n", messages.get(0)); + assertEquals("[INFO ] TestPatternSelector Hello World\n", messages.get(1)); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java index 0c002a0..16417b9 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java @@ -98,7 +98,7 @@ public class ConsoleAppenderTest { mocks.replayAll(); systemSetter.systemSet(psMock); - final Layout<String> layout = PatternLayout.createLayout(null, null, null, null, false, false, null, null); + final Layout<String> layout = PatternLayout.createLayout(null, null, null, null, null, false, false, null, null); final ConsoleAppender app = ConsoleAppender.createAppender(layout, null, targetName, "Console", "false", "false"); app.start(); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java index bac234c..296492b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java @@ -24,14 +24,14 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.BasicConfigurationFactory; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.*; import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.lookup.MainMapLookup; +import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.Strings; import org.junit.After; @@ -263,4 +263,33 @@ public class PatternLayoutTest { .withConfiguration(ctx.getConfiguration()).withCharset(StandardCharsets.UTF_8).build(); assertEquals(StandardCharsets.UTF_8, layout.getCharset()); } + + @Test + public void testPatternSelector() throws Exception { + PatternMatch[] patterns = new PatternMatch[1]; + patterns[0] = new PatternMatch("FLOW", "%d %-5p [%t]: ====== %C{1}.%M:%L %m ======%n"); + PatternSelector selector = MarkerPatternSelector.createSelector(patterns, "%d %-5p [%t]: %m%n", true, true, ctx.getConfiguration()); + final PatternLayout layout = PatternLayout.newBuilder().withPatternSelector(selector) + .withConfiguration(ctx.getConfiguration()).build(); + final LogEvent event1 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.layout.PatternLayoutTest$FauxLogger") + .setMarker(MarkerManager.getMarker("FLOW")) + .setLevel(Level.TRACE) // + .setIncludeLocation(true) + .setMessage(new SimpleMessage("entry")).build(); + final String result1 = new FauxLogger().formatEvent(event1, layout); + assertTrue("Unexpected result: " + result1, result1.endsWith("====== PatternLayoutTest.testPatternSelector:280 entry ======\n")); + final LogEvent event2 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world 1!")).build(); + final String result2 = new String(layout.toByteArray(event2)); + assertTrue("Unexpected result: " + result2, result2.endsWith("Hello, world 1!\n")); + } + + public class FauxLogger { + public String formatEvent(LogEvent event, Layout layout) { + return new String(layout.toByteArray(event)); + } + } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-core/src/test/resources/log4j-patternSelector.xml ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/resources/log4j-patternSelector.xml b/log4j-core/src/test/resources/log4j-patternSelector.xml new file mode 100644 index 0000000..124aaf8 --- /dev/null +++ b/log4j-core/src/test/resources/log4j-patternSelector.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + --> +<Configuration status="WARN"> + <Appenders> + <List name="List"> + <PatternLayout> + <MarkerPatternSelector defaultPattern="[%-5level] %c{1.} %msg%n"> + <PatternMatch key="FLOW" pattern="[%-5level] %c{1.} ====== %C{1.}.%M:%L %msg ======%n"/> + </MarkerPatternSelector> + </PatternLayout> + </List> + </Appenders> + <Loggers> + <Root level="trace"> + <AppenderRef ref="List" /> + </Root> + </Loggers> +</Configuration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutBenchmark.java ---------------------------------------------------------------------- diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutBenchmark.java index 70ee7d1..f66637a 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutBenchmark.java @@ -58,14 +58,14 @@ public class PatternLayoutBenchmark { private static final String DEFAULT_ENCODING = CHARSET_DEFAULT.name(); private static final String STRING_SHIFT_JIS = "SHIFT_JIS"; private static final Charset CHARSET_SHIFT_JIS = Charset.forName(STRING_SHIFT_JIS); - private final PatternLayout PATTERN_M = PatternLayout.createLayout("%m%n", null, null, CHARSET_DEFAULT, false, true, null, null); - private final PatternLayout PATTERN_SPACE = PatternLayout.createLayout(" ", null, null, CHARSET_DEFAULT, false, true, null, null); - private final PatternLayout PATTERN_M_C = PatternLayout.createLayout("%c %m%n", null, null, CHARSET_DEFAULT, false, true, null, null); - private final PatternLayout PATTERN_M_C_D = PatternLayout.createLayout("%d %c %m%n", null, null, CHARSET_DEFAULT, false, true, null, null); - private final PatternLayout PATTERN_M_D = PatternLayout.createLayout("%d %m%n", null, null, CHARSET_DEFAULT, false, true, null, null); - private final PatternLayout PATTERN_M_EX = PatternLayout.createLayout("%m %ex%n", null, null, CHARSET_DEFAULT, false, true, null, null); - private final PatternLayout PATTERN_M_D_EX = PatternLayout.createLayout("%d %m%ex%n", null, null, CHARSET_DEFAULT, false, true, null, null); - private final PatternLayout PATTERN_M_C_D_EX = PatternLayout.createLayout("%d %c %m%ex%n", null, null, CHARSET_DEFAULT, false, true, null, null); + private final PatternLayout PATTERN_M = PatternLayout.createLayout("%m%n", null, null, null, CHARSET_DEFAULT, false, true, null, null); + private final PatternLayout PATTERN_SPACE = PatternLayout.createLayout(" ", null, null, null, CHARSET_DEFAULT, false, true, null, null); + private final PatternLayout PATTERN_M_C = PatternLayout.createLayout("%c %m%n", null, null, null, CHARSET_DEFAULT, false, true, null, null); + private final PatternLayout PATTERN_M_C_D = PatternLayout.createLayout("%d %c %m%n", null, null, null, CHARSET_DEFAULT, false, true, null, null); + private final PatternLayout PATTERN_M_D = PatternLayout.createLayout("%d %m%n", null, null, null, CHARSET_DEFAULT, false, true, null, null); + private final PatternLayout PATTERN_M_EX = PatternLayout.createLayout("%m %ex%n", null, null, null, CHARSET_DEFAULT, false, true, null, null); + private final PatternLayout PATTERN_M_D_EX = PatternLayout.createLayout("%d %m%ex%n", null, null, null, CHARSET_DEFAULT, false, true, null, null); + private final PatternLayout PATTERN_M_C_D_EX = PatternLayout.createLayout("%d %c %m%ex%n", null, null, null, CHARSET_DEFAULT, false, true, null, null); private static LogEvent createLogEvent() { final Marker marker = null; http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutComparisonBenchmark.java ---------------------------------------------------------------------- diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutComparisonBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutComparisonBenchmark.java index 3acd892..0919835 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutComparisonBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/PatternLayoutComparisonBenchmark.java @@ -59,7 +59,7 @@ public class PatternLayoutComparisonBenchmark { final static LogEvent LOG4J2EVENT = createLog4j2Event(); private static final Charset CHARSET_DEFAULT = Charset.defaultCharset(); private static final String LOG4JPATTERN = "%d %5p [%t] %c{1} %X{transactionId} - %m%n"; - private final PatternLayout LOG4J2_PATTERN_LAYOUT = PatternLayout.createLayout(LOG4JPATTERN, + private final PatternLayout LOG4J2_PATTERN_LAYOUT = PatternLayout.createLayout(LOG4JPATTERN, null, null, null, CHARSET_DEFAULT, false, true, null, null); private static LogEvent createLog4j2Event() { http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fe021d94/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 93ba5f1..a8a0c8c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -24,6 +24,9 @@ </properties> <body> <release version="2.4.1" date="2015-MM-DD" description="GA Release 2.4.1"> + <action issue="LOG4J2-1129" dev="rgoers" type="add"> + Allow PatternLayout to select a pattern to use based on some selection criteria" + </action> <action issue="LOG4J2-1127" dev="ggregory" type="fix"> log4j2.xml cannot be parsed on Oracle Weblogic 12c</action> <action issue="LOG4J2-1128" dev="ggregory" type="update">
