/*
* 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.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
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.cli.UserException;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.node.Node;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.hamcrest.RegexMatcher;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
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 {
@Override
public void setUp() throws Exception {
super.setUp();
LogConfigurator.registerErrorListener();
}
@Override
public void tearDown() throws Exception {
LoggerContext context = (LoggerContext) LogManager.getContext(false);
Configurator.shutdown(context);
super.tearDown();
}
public void testLocationInfoTest() throws IOException, UserException {
setupLogging("location_info");
final Logger testLogger = ESLoggerFactory.getLogger("test");
testLogger.error("This is an error message");
testLogger.warn("This is a warning message");
testLogger.info("This is an info message");
testLogger.debug("This is a debug message");
testLogger.trace("This is a trace message");
final String path =
System.getProperty("es.logs.base_path") +
System.getProperty("file.separator") +
System.getProperty("es.logs.cluster_name") +
".log";
final List<String> events = Files.readAllLines(PathUtils.get(path));
assertThat(events.size(), equalTo(5));
final String location = "org.elasticsearch.common.logging.EvilLoggerTests.testLocationInfoTest";
// the first message is a warning for unsupported configuration files
assertLogLine(events.get(0), Level.ERROR, location, "This is an error message");
assertLogLine(events.get(1), Level.WARN, location, "This is a warning message");
assertLogLine(events.get(2), Level.INFO, location, "This is an info message");
assertLogLine(events.get(3), Level.DEBUG, location, "This is a debug message");
assertLogLine(events.get(4), Level.TRACE, location, "This is a trace message");
}
public void testDeprecationLogger() throws IOException, UserException {
setupLogging("deprecation");
final DeprecationLogger deprecationLogger = new DeprecationLogger(ESLoggerFactory.getLogger("deprecation"));
deprecationLogger.deprecated("This is a deprecation message");
final String deprecationPath =
System.getProperty("es.logs.base_path") +
System.getProperty("file.separator") +
System.getProperty("es.logs.cluster_name") +
"_deprecation.log";
final List<String> deprecationEvents = Files.readAllLines(PathUtils.get(deprecationPath));
assertThat(deprecationEvents.size(), equalTo(1));
assertLogLine(
deprecationEvents.get(0),
Level.WARN,
"org.elasticsearch.common.logging.DeprecationLogger.deprecated",
"This is a deprecation message");
assertWarnings("This is a deprecation message");
}
public void testFindAppender() throws IOException, UserException {
setupLogging("find_appender");
final Logger hasConsoleAppender = ESLoggerFactory.getLogger("has_console_appender");
final Appender testLoggerConsoleAppender = Loggers.findAppender(hasConsoleAppender, ConsoleAppender.class);
assertNotNull(testLoggerConsoleAppender);
assertThat(testLoggerConsoleAppender.getName(), equalTo("console"));
final Logger hasCountingNoOpAppender = ESLoggerFactory.getLogger("has_counting_no_op_appender");
assertNull(Loggers.findAppender(hasCountingNoOpAppender, ConsoleAppender.class));
final Appender countingNoOpAppender = Loggers.findAppender(hasCountingNoOpAppender, CountingNoOpAppender.class);
assertThat(countingNoOpAppender.getName(), equalTo("counting_no_op"));
}
public void testPrefixLogger() throws IOException, IllegalAccessException, UserException {
setupLogging("prefix");
final String prefix = randomBoolean() ? null : randomAlphaOfLength(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.base_path") +
System.getProperty("file.separator") +
System.getProperty("es.logs.cluster_name") +
".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 testProperties() throws IOException, UserException {
final Settings.Builder builder = Settings.builder().put("cluster.name", randomAlphaOfLength(16));
if (randomBoolean()) {
builder.put("node.name", randomAlphaOfLength(16));
}
final Settings settings = builder.build();
setupLogging("minimal", settings);
assertNotNull(System.getProperty("es.logs.base_path"));
assertThat(System.getProperty("es.logs.cluster_name"), equalTo(ClusterName.CLUSTER_NAME_SETTING.get(settings).value()));
if (Node.NODE_NAME_SETTING.exists(settings)) {
assertThat(System.getProperty("es.logs.node_name"), equalTo(Node.NODE_NAME_SETTING.get(settings)));
} else {
assertNull(System.getProperty("es.logs.node_name"));
}
}
private void setupLogging(final String config) throws IOException, UserException {
setupLogging(config, Settings.EMPTY);
}
private void setupLogging(final String config, final Settings settings) throws IOException, UserException {
assert !Environment.PATH_CONF_SETTING.exists(settings);
assert !Environment.PATH_HOME_SETTING.exists(settings);
final Path configDir = getDataPath(config);
// need to set custom path.conf so we can use a custom log4j2.properties file for the test
final Settings mergedSettings = Settings.builder()
.put(settings)
.put(Environment.PATH_CONF_SETTING.getKey(), configDir.toAbsolutePath())
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString())
.build();
final Environment environment = new Environment(mergedSettings);
LogConfigurator.configure(environment);
}
private void assertLogLine(final String logLine, final Level level, final String location, final String message) {
final Matcher matcher = Pattern.compile("\\[(.*)\\]\\[(.*)\\(.*\\)\\] (.*)").matcher(logLine);
assertTrue(logLine, matcher.matches());
assertThat(matcher.group(1), equalTo(level.toString()));
assertThat(matcher.group(2), RegexMatcher.matches(location));
assertThat(matcher.group(3), RegexMatcher.matches(message));
}
}