Fix prefix logging

Today we add a prefix when logging within Elasticsearch. This prefix
contains the node name, and index and shard-level components if
appropriate.

Due to some implementation details with Log4j 2 , this does not work for
integration tests; instead what we see is the node name for the last
node to startup. The implementation detail here is that Log4j 2 there is
only one logger for a name, message factory pair, and the key derived
from the message factory is the class name of the message factory. So,
when the last node starts up and starts setting prefixes on its message
factories, it will impact the loggers for the other nodes.

Additionally, the prefixes are lost when logging an exception. This is
due to another implementation detail in Log4j 2. Namely, since we log
exceptions using a parameterized message, Log4j 2 decides that that
means that we do not want to use the message factory that we have
provided (the prefix message factory) and so logs the exception without
the prefix.

This commit fixes both of these issues.

Relates #20429
This commit is contained in:
Jason Tedor 2016-09-13 14:46:34 -04:00 committed by GitHub
parent 1a60e1c3d2
commit fbe27664a6
17 changed files with 158 additions and 271 deletions

View File

@ -22,17 +22,18 @@ package org.elasticsearch.common.logging;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import java.util.Locale;
import java.util.function.Function;
/**
* Factory to get {@link Logger}s
*/
public abstract class ESLoggerFactory {
public final class ESLoggerFactory {
private ESLoggerFactory() {
}
public static final Setting<Level> LOG_DEFAULT_LEVEL_SETTING =
new Setting<>("logger.level", Level.INFO.name(), Level::valueOf, Property.NodeScope);
@ -42,23 +43,12 @@ public abstract class ESLoggerFactory {
public static Logger getLogger(String prefix, String name) {
name = name.intern();
final Logger logger = getLogger(new PrefixMessageFactory(), name);
final MessageFactory factory = logger.getMessageFactory();
// in some cases, we initialize the logger before we are ready to set the prefix
// we can not re-initialize the logger, so the above getLogger might return an existing
// instance without the prefix set; thus, we hack around this by resetting the prefix
if (prefix != null && factory instanceof PrefixMessageFactory) {
((PrefixMessageFactory) factory).setPrefix(prefix.intern());
}
return logger;
}
public static Logger getLogger(MessageFactory messageFactory, String name) {
return LogManager.getLogger(name, messageFactory);
final Logger logger = LogManager.getLogger(name);
return new PrefixLogger((ExtendedLogger)logger, name, prefix);
}
public static Logger getLogger(String name) {
return getLogger((String)null, name);
return getLogger(null, name);
}
public static DeprecationLogger getDeprecationLogger(String name) {
@ -73,8 +63,4 @@ public abstract class ESLoggerFactory {
return LogManager.getRootLogger();
}
private ESLoggerFactory() {
// Utility class can't be built.
}
}

View File

@ -97,7 +97,8 @@ public class Loggers {
}
public static Logger getLogger(Logger parentLogger, String s) {
return ESLoggerFactory.getLogger(parentLogger.<MessageFactory>getMessageFactory(), getLoggerName(parentLogger.getName() + s));
assert parentLogger instanceof PrefixLogger;
return ESLoggerFactory.getLogger(((PrefixLogger)parentLogger).prefix(), getLoggerName(parentLogger.getName() + s));
}
public static Logger getLogger(String s) {

View File

@ -0,0 +1,70 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.common.logging;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
class PrefixLogger extends ExtendedLoggerWrapper {
// we can not use the built-in Marker tracking (MarkerManager) because the MarkerManager holds
// a permanent reference to the marker; however, we have transient markers from index-level and
// shard-level components so this would effectively be a memory leak
private static final WeakHashMap<String, WeakReference<Marker>> markers = new WeakHashMap<>();
private final Marker marker;
public String prefix() {
return marker.getName();
}
PrefixLogger(final ExtendedLogger logger, final String name, final String prefix) {
super(logger, name, null);
final String actualPrefix = (prefix == null ? "" : prefix).intern();
final Marker actualMarker;
// markers is not thread-safe, so we synchronize access
synchronized (markers) {
final WeakReference<Marker> marker = markers.get(actualPrefix);
final Marker maybeMarker = marker == null ? null : marker.get();
if (maybeMarker == null) {
actualMarker = new MarkerManager.Log4jMarker(actualPrefix);
markers.put(actualPrefix, new WeakReference<>(actualMarker));
} else {
actualMarker = maybeMarker;
}
}
this.marker = actualMarker;
}
@Override
public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable t) {
assert marker == null;
super.logMessage(fqcn, level, this.marker, message, t);
}
}

View File

@ -1,221 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.common.logging;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.MessageFactory2;
import org.apache.logging.log4j.message.ObjectMessage;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.message.SimpleMessage;
public class PrefixMessageFactory implements MessageFactory2 {
private String prefix = "";
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
@Override
public Message newMessage(Object message) {
return new PrefixObjectMessage(prefix, message);
}
private static class PrefixObjectMessage extends ObjectMessage {
private final String prefix;
private final Object object;
private String prefixObjectString;
private PrefixObjectMessage(String prefix, Object object) {
super(object);
this.prefix = prefix;
this.object = object;
}
@Override
public String getFormattedMessage() {
if (prefixObjectString == null) {
prefixObjectString = prefix + super.getFormattedMessage();
}
return prefixObjectString;
}
@Override
public void formatTo(StringBuilder buffer) {
buffer.append(prefix);
super.formatTo(buffer);
}
@Override
public Object[] getParameters() {
return new Object[]{prefix, object};
}
}
@Override
public Message newMessage(String message) {
return new PrefixSimpleMessage(prefix, message);
}
private static class PrefixSimpleMessage extends SimpleMessage {
private final String prefix;
private String prefixMessage;
PrefixSimpleMessage(String prefix, String message) {
super(message);
this.prefix = prefix;
}
PrefixSimpleMessage(String prefix, CharSequence charSequence) {
super(charSequence);
this.prefix = prefix;
}
@Override
public String getFormattedMessage() {
if (prefixMessage == null) {
prefixMessage = prefix + super.getFormattedMessage();
}
return prefixMessage;
}
@Override
public void formatTo(StringBuilder buffer) {
buffer.append(prefix);
super.formatTo(buffer);
}
@Override
public int length() {
return prefixMessage.length();
}
@Override
public char charAt(int index) {
return prefixMessage.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return prefixMessage.subSequence(start, end);
}
}
@Override
public Message newMessage(String message, Object... params) {
return new PrefixParameterizedMessage(prefix, message, params);
}
private static class PrefixParameterizedMessage extends ParameterizedMessage {
private static ThreadLocal<StringBuilder> threadLocalStringBuilder = ThreadLocal.withInitial(StringBuilder::new);
private final String prefix;
private String formattedMessage;
private PrefixParameterizedMessage(String prefix, String messagePattern, Object... arguments) {
super(messagePattern, arguments);
this.prefix = prefix;
}
@Override
public String getFormattedMessage() {
if (formattedMessage == null) {
final StringBuilder buffer = threadLocalStringBuilder.get();
buffer.setLength(0);
formatTo(buffer);
formattedMessage = buffer.toString();
}
return formattedMessage;
}
@Override
public void formatTo(StringBuilder buffer) {
buffer.append(prefix);
super.formatTo(buffer);
}
}
@Override
public Message newMessage(CharSequence charSequence) {
return new PrefixSimpleMessage(prefix, charSequence);
}
@Override
public Message newMessage(String message, Object p0) {
return new PrefixParameterizedMessage(prefix, message, p0);
}
@Override
public Message newMessage(String message, Object p0, Object p1) {
return new PrefixParameterizedMessage(prefix, message, p0, p1);
}
@Override
public Message newMessage(String message, Object p0, Object p1, Object p2) {
return new PrefixParameterizedMessage(prefix, message, p0, p1, p2);
}
@Override
public Message newMessage(String message, Object p0, Object p1, Object p2, Object p3) {
return new PrefixParameterizedMessage(prefix, message, p0, p1, p2, p3);
}
@Override
public Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4) {
return new PrefixParameterizedMessage(prefix, message, p0, p1, p2, p3, p4);
}
@Override
public Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5) {
return new PrefixParameterizedMessage(prefix, message, p0, p1, p2, p3, p4, p5);
}
@Override
public Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6) {
return new PrefixParameterizedMessage(prefix, message, p0, p1, p2, p3, p4, p5, p6);
}
@Override
public Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7) {
return new PrefixParameterizedMessage(prefix, message, p0, p1, p2, p3, p4, p5, p6, p7);
}
@Override
public Message newMessage(
String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8) {
return new PrefixParameterizedMessage(prefix, message, p0, p1, p2, p3, p4, p5, p6, p7, p8);
}
@Override
public Message newMessage(
String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8, Object p9) {
return new PrefixParameterizedMessage(prefix, message, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
}
}

View File

@ -61,7 +61,6 @@ import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.FileSystemUtils;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.logging.PrefixMessageFactory;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.settings.Settings;
@ -1510,13 +1509,13 @@ public class InternalEngineTests extends ESTestCase {
public boolean sawIndexWriterIFDMessage;
public MockAppender(final String name) throws IllegalAccessException {
super(name, RegexFilter.createFilter(".*(\n.*)*", new String[0], true, null, null), null);
super(name, RegexFilter.createFilter(".*(\n.*)*", new String[0], false, null, null), null);
}
@Override
public void append(LogEvent event) {
final String formattedMessage = event.getMessage().getFormattedMessage();
if (event.getLevel() == Level.TRACE && formattedMessage.contains("[index][1] ")) {
if (event.getLevel() == Level.TRACE && event.getMarker().getName().contains("[index][1] ")) {
if (event.getLoggerName().endsWith("lucene.iw") &&
formattedMessage.contains("IW: apply all deletes during flush")) {
sawIndexWriterMessage = true;
@ -1556,7 +1555,7 @@ public class InternalEngineTests extends ESTestCase {
} finally {
Loggers.removeAppender(rootLogger, mockAppender);
Loggers.setLevel(rootLogger, savedLevel.toString());
Loggers.setLevel(rootLogger, savedLevel);
}
}
@ -1566,13 +1565,13 @@ public class InternalEngineTests extends ESTestCase {
MockAppender mockAppender = new MockAppender("testIndexWriterIFDInfoStream");
final Logger iwIFDLogger;
if (LogManager.getContext(false).hasLogger("org.elasticsearch.index.engine.lucene.iw.ifd", new PrefixMessageFactory())) {
if (LogManager.getContext(false).hasLogger("org.elasticsearch.index.engine.lucene.iw.ifd")) {
// Works when running this test inside Intellij:
iwIFDLogger = LogManager.getLogger("org.elasticsearch.index.engine.lucene.iw.ifd");
assertNotNull(iwIFDLogger);
} else {
// Works when running this test from command line:
assertTrue(LogManager.getContext(false).hasLogger("index.engine.lucene.iw.ifd", new PrefixMessageFactory()));
assertTrue(LogManager.getContext(false).hasLogger("index.engine.lucene.iw.ifd"));
iwIFDLogger = LogManager.getLogger("index.engine.lucene.iw.ifd");
}

View File

@ -358,7 +358,7 @@ public class UpdateSettingsIT extends ESIntegTestCase {
public boolean sawUpdateAutoThrottle;
public MockAppender(final String name) throws IllegalAccessException {
super(name, RegexFilter.createFilter(".*(\n.*)*", new String[0], true, null, null), null);
super(name, RegexFilter.createFilter(".*(\n.*)*", new String[0], false, null, null), null);
}
@Override

View File

@ -40,7 +40,7 @@ public class MockLogAppender extends AbstractAppender {
private List<LoggingExpectation> expectations;
public MockLogAppender() throws IllegalAccessException {
super("mock", RegexFilter.createFilter(".*(\n.*)*", new String[0], true, null, null), null);
super("mock", RegexFilter.createFilter(".*(\n.*)*", new String[0], false, null, null), null);
expectations = new ArrayList<>();
}

View File

@ -7,13 +7,13 @@ logger.action.level = debug
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%m%n
appender.rolling.type = RollingFile
appender.rolling.name = rolling
appender.rolling.fileName = ${sys:es.logs}.log
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n
appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%.10000m%n
appender.rolling.filePattern = ${sys:es.logs}-%d{yyyy-MM-dd}.log
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
@ -28,7 +28,7 @@ appender.deprecation_rolling.type = RollingFile
appender.deprecation_rolling.name = deprecation_rolling
appender.deprecation_rolling.fileName = ${sys:es.logs}_deprecation.log
appender.deprecation_rolling.layout.type = PatternLayout
appender.deprecation_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n
appender.deprecation_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%.10000m%n
appender.deprecation_rolling.filePattern = ${sys:es.logs}_deprecation-%i.log.gz
appender.deprecation_rolling.policies.type = Policies
appender.deprecation_rolling.policies.size.type = SizeBasedTriggeringPolicy
@ -45,7 +45,7 @@ appender.index_search_slowlog_rolling.type = RollingFile
appender.index_search_slowlog_rolling.name = index_search_slowlog_rolling
appender.index_search_slowlog_rolling.fileName = ${sys:es.logs}_index_search_slowlog.log
appender.index_search_slowlog_rolling.layout.type = PatternLayout
appender.index_search_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n
appender.index_search_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%.10000m%n
appender.index_search_slowlog_rolling.filePattern = ${sys:es.logs}_index_search_slowlog-%d{yyyy-MM-dd}.log
appender.index_search_slowlog_rolling.policies.type = Policies
appender.index_search_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy
@ -61,7 +61,7 @@ appender.index_indexing_slowlog_rolling.type = RollingFile
appender.index_indexing_slowlog_rolling.name = index_indexing_slowlog_rolling
appender.index_indexing_slowlog_rolling.fileName = ${sys:es.logs}_index_indexing_slowlog.log
appender.index_indexing_slowlog_rolling.layout.type = PatternLayout
appender.index_indexing_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n
appender.index_indexing_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%.10000m%n
appender.index_indexing_slowlog_rolling.filePattern = ${sys:es.logs}_index_indexing_slowlog-%d{yyyy-MM-dd}.log
appender.index_indexing_slowlog_rolling.policies.type = Policies
appender.index_indexing_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy

View File

@ -27,6 +27,7 @@ import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.CountingNoOpAppender;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
@ -34,8 +35,9 @@ import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.hamcrest.RegexMatcher;
import javax.management.MBeanServerPermission;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.AccessControlException;
@ -46,6 +48,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
public class EvilLoggerTests extends ESTestCase {
@ -108,6 +111,35 @@ public class EvilLoggerTests extends ESTestCase {
assertThat(countingNoOpAppender.getName(), equalTo("counting_no_op"));
}
public void testPrefixLogger() throws IOException, IllegalAccessException {
setupLogging("prefix");
final String prefix = randomBoolean() ? null : randomAsciiOfLength(16);
final Logger logger = Loggers.getLogger("prefix", prefix);
logger.info("test");
logger.info("{}", "test");
final Exception e = new Exception("exception");
logger.info(new ParameterizedMessage("{}", "test"), e);
final String path = System.getProperty("es.logs") + ".log";
final List<String> events = Files.readAllLines(PathUtils.get(path));
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
final int stackTraceLength = sw.toString().split(System.getProperty("line.separator")).length;
final int expectedLogLines = 3;
assertThat(events.size(), equalTo(expectedLogLines + stackTraceLength));
for (int i = 0; i < expectedLogLines; i++) {
if (prefix == null) {
assertThat(events.get(i), startsWith("test"));
} else {
assertThat(events.get(i), startsWith("[" + prefix + "] test"));
}
}
}
public void testLog4jShutdownHack() {
final AtomicBoolean denied = new AtomicBoolean();
final SecurityManager sm = System.getSecurityManager();

View File

@ -3,13 +3,13 @@ status = error
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%m%n
appender.file.type = File
appender.file.name = file
appender.file.fileName = ${sys:es.logs}.log
appender.file.layout.type = PatternLayout
appender.file.layout.pattern = [%p][%l] %m%n
appender.file.layout.pattern = [%p][%l] %marker%m%n
rootLogger.level = info
rootLogger.appenderRef.console.ref = console
@ -25,7 +25,7 @@ appender.deprecation_file.type = File
appender.deprecation_file.name = deprecation_file
appender.deprecation_file.fileName = ${sys:es.logs}_deprecation.log
appender.deprecation_file.layout.type = PatternLayout
appender.deprecation_file.layout.pattern = [%p][%l] %m%n
appender.deprecation_file.layout.pattern = [%p][%l] %marker%m%n
logger.deprecation.name = deprecation
logger.deprecation.level = warn

View File

@ -1,7 +1,7 @@
appender.console2.type = Console
appender.console2.name = console2
appender.console2.layout.type = PatternLayout
appender.console2.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.console2.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marke%m%n
logger.second.name = second
logger.second.level = debug

View File

@ -1,7 +1,7 @@
appender.console3.type = Console
appender.console3.name = console3
appender.console3.layout.type = PatternLayout
appender.console3.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.console3.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%m%n
logger.third.name = third
logger.third.level = debug

View File

@ -3,13 +3,13 @@ status = error
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%m%n
appender.file.type = File
appender.file.name = file
appender.file.fileName = ${sys:es.logs}.log
appender.file.layout.type = PatternLayout
appender.file.layout.pattern = [%p][%l] %m%n
appender.file.layout.pattern = [%p][%l] %marker%m%n
rootLogger.level = info
rootLogger.appenderRef.console.ref = console
@ -19,7 +19,7 @@ appender.deprecation_file.type = File
appender.deprecation_file.name = deprecation_file
appender.deprecation_file.fileName = ${sys:es.logs}_deprecation.log
appender.deprecation_file.layout.type = PatternLayout
appender.deprecation_file.layout.pattern = [%p][%l] %m%n
appender.deprecation_file.layout.pattern = [%p][%l] %marker%m%n
logger.deprecation.name = deprecation
logger.deprecation.level = warn

View File

@ -3,7 +3,7 @@ status = error
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%m%n
logger.has_console_appender.name = has_console_appender
logger.has_console_appender.level = trace

View File

@ -3,13 +3,13 @@ status = error
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%m%n
appender.file.type = File
appender.file.name = file
appender.file.fileName = ${sys:es.logs}.log
appender.file.layout.type = PatternLayout
appender.file.layout.pattern = [%p][%l] %m%n
appender.file.layout.pattern = [%p][%l] %marker%m%n
rootLogger.level = info
rootLogger.appenderRef.console.ref = console

View File

@ -0,0 +1,20 @@
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%m%n
appender.file.type = File
appender.file.name = file
appender.file.fileName = ${sys:es.logs}.log
appender.file.layout.type = PatternLayout
appender.file.layout.pattern = %marker%m%n
rootLogger.level = info
rootLogger.appenderRef.console.ref = console
rootLogger.appenderRef.file.ref = file
logger.prefix.name = prefix
logger.prefix.level = info
logger.prefix.appenderRef.console.ref = console
logger.prefix.appenderRef.file.ref = file
logger.prefix.additivity = false

View File

@ -3,7 +3,7 @@ status = error
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%m%n
rootLogger.level = info
rootLogger.appenderRef.console.ref = console