From aeca95d77278890fd409e79baf320de3907e63a6 Mon Sep 17 00:00:00 2001 From: Siva Kommuri Date: Thu, 21 Aug 2014 16:47:32 -0700 Subject: [PATCH] Logging: add the ability to specify an alternate logging configuration file via system property Closes #2044 --- docs/reference/setup/configuration.asciidoc | 16 ++++ .../common/logging/log4j/LogConfigurator.java | 19 ++++- .../log4j/LoggingConfigurationTests.java | 84 +++++++++++++++++-- 3 files changed, 107 insertions(+), 12 deletions(-) diff --git a/docs/reference/setup/configuration.asciidoc b/docs/reference/setup/configuration.asciidoc index 7d0ad80e1313c..d2dd991e3b989 100644 --- a/docs/reference/setup/configuration.asciidoc +++ b/docs/reference/setup/configuration.asciidoc @@ -337,3 +337,19 @@ the http://logging.apache.org/log4j/1.2/manual.html[log4j documentation]. Additional Appenders and other logging classes provided by http://logging.apache.org/log4j/extras/[log4j-extras] are also available, out of the box. + +Optionally, +the location of the configuration file can be set externally using a system +property, for example: + +[source,sh] +-------------------------------------------------- +$ elasticsearch -Des.logging=/abs/path/to/logging/file.yml +-------------------------------------------------- + +or + +[source,sh] +-------------------------------------------------- +$ elasticsearch -Des.logging=log_config_file_in_classpath.yml +-------------------------------------------------- diff --git a/src/main/java/org/elasticsearch/common/logging/log4j/LogConfigurator.java b/src/main/java/org/elasticsearch/common/logging/log4j/LogConfigurator.java index 7d422d59aea15..519feb780cf40 100644 --- a/src/main/java/org/elasticsearch/common/logging/log4j/LogConfigurator.java +++ b/src/main/java/org/elasticsearch/common/logging/log4j/LogConfigurator.java @@ -25,7 +25,9 @@ import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.rolling.SizeBasedTriggeringPolicy; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.MapBuilder; +import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; @@ -33,6 +35,7 @@ import java.io.IOException; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.EnumSet; @@ -49,6 +52,8 @@ public class LogConfigurator { static final List ALLOWED_SUFFIXES = ImmutableList.of(".yml", ".yaml", ".json", ".properties"); + static final String ES_LOGGING_SYSPROP = "es.logging"; + private static boolean loaded; private static ImmutableMap replacements = new MapBuilder() @@ -123,7 +128,15 @@ public static void reset() { public static void resolveConfig(Environment env, final ImmutableSettings.Builder settingsBuilder) { try { - Files.walkFileTree(env.configFile(), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor() { + Path startingPath; + final String esLoggingDir = System.getProperty(ES_LOGGING_SYSPROP); + if (Strings.hasText(esLoggingDir)) { + startingPath = PathUtils.get(env.resolveConfig(esLoggingDir).toURI()); + } else { + startingPath = env.configFile(); + } + + Files.walkFileTree(startingPath, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { String fileName = file.getFileName().toString(); @@ -138,8 +151,8 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO return FileVisitResult.CONTINUE; } }); - } catch (IOException ioe) { - throw new ElasticsearchException("Failed to load logging configuration", ioe); + } catch (IOException | URISyntaxException e) { + throw new ElasticsearchException("Failed to load logging configuration", e); } } diff --git a/src/test/java/org/elasticsearch/common/logging/log4j/LoggingConfigurationTests.java b/src/test/java/org/elasticsearch/common/logging/log4j/LoggingConfigurationTests.java index b53b434a49241..2d8a4d2ceb575 100644 --- a/src/test/java/org/elasticsearch/common/logging/log4j/LoggingConfigurationTests.java +++ b/src/test/java/org/elasticsearch/common/logging/log4j/LoggingConfigurationTests.java @@ -21,26 +21,21 @@ import org.apache.log4j.Appender; import org.apache.log4j.Logger; -import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.logging.ESLogger; -import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.env.FailedToResolveConfigException; import org.elasticsearch.test.ElasticsearchTestCase; -import org.hamcrest.Matchers; -import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.net.URL; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.*; /** * @@ -141,7 +136,78 @@ public void testResolveConfigInvalidFilename() throws Exception { LogConfigurator.resolveConfig(environment, builder); Settings logSettings = builder.build(); - assertThat(logSettings.get("yml"), Matchers.nullValue()); + assertThat(logSettings.get("yml"), nullValue()); + } + + @Test + public void testResolveLoggingDirFromSystemProperty() throws Exception { + Path tempDir = createTempDir(); + Path customLogConfig1 = tempDir.resolve(LoggingConfigurationTests.loggingConfiguration("yml")); + Files.write(customLogConfig1, "action: WARN".getBytes(StandardCharsets.UTF_8)); + Path customLogConfig2 = tempDir.resolve(LoggingConfigurationTests.loggingConfiguration("yml")); + Files.write(customLogConfig2, "transport: TRACE".getBytes(StandardCharsets.UTF_8)); + if (randomBoolean()) { + //gets ignored because the filename doesn't start with the "logging." prefix + Path ignoredLogConfig = tempDir.resolve("invalid_logging.yml"); + Files.write(ignoredLogConfig, "invalid: TRACE".getBytes(StandardCharsets.UTF_8)); + } + if (randomBoolean()) { + //gets ignored because the filename doesn't end with one of the allowed suffixes + Path ignoredLogConfig = tempDir.resolve("logging.unknown"); + Files.write(ignoredLogConfig, "invalid: TRACE".getBytes(StandardCharsets.UTF_8)); + } + + try { + System.setProperty(LogConfigurator.ES_LOGGING_SYSPROP, tempDir.toString()); + Environment environment = new Environment(ImmutableSettings.EMPTY); + ImmutableSettings.Builder builder = ImmutableSettings.builder(); + LogConfigurator.resolveConfig(environment, builder); + + Settings logSettings = builder.build(); + assertThat(logSettings.names().size(), equalTo(2)); + assertThat(logSettings.get("action"), is("WARN")); + assertThat(logSettings.get("transport"), is("TRACE")); + assertThat(logSettings.get("invalid"), nullValue()); + } finally { + System.clearProperty(LogConfigurator.ES_LOGGING_SYSPROP); + } + } + + @Test + public void testResolveLoggingFileFromSystemProperty() throws Exception { + Path tempDir = createTempDir(); + Path customLogConfig = tempDir.resolve(LoggingConfigurationTests.loggingConfiguration("yml")); + Files.write(customLogConfig, "action: WARN".getBytes(StandardCharsets.UTF_8)); + if (randomBoolean()) { + //gets ignored because the sysprop points directly to the above file + Path ignoredLogConfig = tempDir.resolve(LoggingConfigurationTests.loggingConfiguration("yml")); + Files.write(ignoredLogConfig, "transport: TRACE".getBytes(StandardCharsets.UTF_8)); + } + + try { + System.setProperty(LogConfigurator.ES_LOGGING_SYSPROP, customLogConfig.toString()); + Environment environment = new Environment(ImmutableSettings.EMPTY); + ImmutableSettings.Builder builder = ImmutableSettings.builder(); + LogConfigurator.resolveConfig(environment, builder); + + Settings logSettings = builder.build(); + assertThat(logSettings.names().size(), equalTo(1)); + assertThat(logSettings.get("action"), is("WARN")); + } finally { + System.clearProperty(LogConfigurator.ES_LOGGING_SYSPROP); + } + } + + @Test(expected = FailedToResolveConfigException.class) + public void testResolveNonExistingLoggingFileFromSystemProperty() throws IOException { + try { + System.setProperty(LogConfigurator.ES_LOGGING_SYSPROP, "non_existing.yml"); + Environment environment = new Environment(ImmutableSettings.builder().build()); + ImmutableSettings.Builder builder = ImmutableSettings.builder(); + LogConfigurator.resolveConfig(environment, builder); + } finally { + System.clearProperty(LogConfigurator.ES_LOGGING_SYSPROP); + } } private static String loggingConfiguration(String suffix) {