Skip to content

Commit d2ca694

Browse files
committed
Merge pull request #13933 from brwe/plugin-cli-logging
plugin cli tool should not create empty log files
2 parents 07fe08f + 9492be6 commit d2ca694

File tree

9 files changed

+131
-14
lines changed

9 files changed

+131
-14
lines changed

core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ private void setupSecurity(Settings settings, Environment environment) throws Ex
195195
private static void setupLogging(Settings settings, Environment environment) {
196196
try {
197197
Class.forName("org.apache.log4j.Logger");
198-
LogConfigurator.configure(settings);
198+
LogConfigurator.configure(settings, true);
199199
} catch (ClassNotFoundException e) {
200200
// no log4j
201201
} catch (NoClassDefFoundError e) {

core/src/main/java/org/elasticsearch/common/logging/log4j/LogConfigurator.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public class LogConfigurator {
7070
.put("socketHub", "org.apache.log4j.net.SocketHubAppender")
7171
.put("syslog", "org.apache.log4j.net.SyslogAppender")
7272
.put("telnet", "org.apache.log4j.net.TelnetAppender")
73+
.put("terminal", "org.elasticsearch.common.logging.log4j.TerminalAppender")
7374
// policies
7475
.put("timeBased", "org.apache.log4j.rolling.TimeBasedRollingPolicy")
7576
.put("sizeBased", "org.apache.log4j.rolling.SizeBasedTriggeringPolicy")
@@ -83,15 +84,24 @@ public class LogConfigurator {
8384
.put("xml", "org.apache.log4j.XMLLayout")
8485
.immutableMap();
8586

86-
public static void configure(Settings settings) {
87+
/**
88+
* Consolidates settings and converts them into actual log4j settings, then initializes loggers and appenders.
89+
*
90+
* @param settings custom settings that should be applied
91+
* @param resolveConfig controls whether the logging conf file should be read too or not.
92+
*/
93+
public static void configure(Settings settings, boolean resolveConfig) {
8794
if (loaded) {
8895
return;
8996
}
9097
loaded = true;
9198
// TODO: this is partly a copy of InternalSettingsPreparer...we should pass in Environment and not do all this...
9299
Environment environment = new Environment(settings);
100+
93101
Settings.Builder settingsBuilder = settingsBuilder();
94-
resolveConfig(environment, settingsBuilder);
102+
if (resolveConfig) {
103+
resolveConfig(environment, settingsBuilder);
104+
}
95105
settingsBuilder
96106
.putProperties("elasticsearch.", System.getProperties())
97107
.putProperties("es.", System.getProperties());
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
21+
package org.elasticsearch.common.logging.log4j;
22+
23+
import org.apache.log4j.AppenderSkeleton;
24+
import org.apache.log4j.spi.LoggingEvent;
25+
import org.elasticsearch.common.cli.Terminal;
26+
27+
/**
28+
* TerminalAppender logs event to Terminal.DEFAULT. It is used for example by the PluginManagerCliParser.
29+
* */
30+
public class TerminalAppender extends AppenderSkeleton {
31+
@Override
32+
protected void append(LoggingEvent event) {
33+
Terminal.DEFAULT.println(event.getRenderedMessage());
34+
}
35+
36+
@Override
37+
public void close() {
38+
}
39+
40+
@Override
41+
public boolean requiresLayout() {
42+
return false;
43+
}
44+
}

core/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public static Settings prepareSettings(Settings input) {
7373
* and then replacing all property placeholders. If a {@link Terminal} is provided and configuration settings are loaded,
7474
* settings with a value of <code>${prompt.text}</code> or <code>${prompt.secret}</code> will result in a prompt for
7575
* the setting to the user.
76-
* @param input The initial settings to use
76+
* @param input The custom settings to use. These are not overwritten by settings in the configuration file.
7777
* @param terminal the Terminal to use for input/output
7878
* @return the {@link Settings} and {@link Environment} as a {@link Tuple}
7979
*/

core/src/main/java/org/elasticsearch/plugins/PluginManagerCliParser.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.elasticsearch.common.cli.CliTool;
2525
import org.elasticsearch.common.cli.CliToolConfig;
2626
import org.elasticsearch.common.cli.Terminal;
27-
import org.elasticsearch.common.collect.Tuple;
2827
import org.elasticsearch.common.logging.log4j.LogConfigurator;
2928
import org.elasticsearch.common.settings.Settings;
3029
import org.elasticsearch.common.unit.TimeValue;
@@ -39,7 +38,6 @@
3938

4039
import static org.elasticsearch.common.cli.CliToolConfig.Builder.cmd;
4140
import static org.elasticsearch.common.cli.CliToolConfig.Builder.option;
42-
import static org.elasticsearch.common.settings.Settings.EMPTY;
4341

4442
public class PluginManagerCliParser extends CliTool {
4543

@@ -51,8 +49,21 @@ public class PluginManagerCliParser extends CliTool {
5149
.build();
5250

5351
public static void main(String[] args) {
54-
Environment env = InternalSettingsPreparer.prepareEnvironment(EMPTY, Terminal.DEFAULT);
55-
LogConfigurator.configure(env.settings());
52+
// initialize default for es.logger.level because we will not read the logging.yml
53+
String loggerLevel = System.getProperty("es.logger.level", "INFO");
54+
// Set the appender for all potential log files to terminal so that other components that use the logger print out the
55+
// same terminal.
56+
// The reason for this is that the plugin cli cannot be configured with a file appender because when the plugin command is
57+
// executed there is no way of knowing where the logfiles should be placed. For example, if elasticsearch
58+
// is run as service then the logs should be at /var/log/elasticsearch but when started from the tar they should be at es.home/logs.
59+
// Therefore we print to Terminal.
60+
Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.builder()
61+
.put("appender.terminal.type", "terminal")
62+
.put("rootLogger", "${es.logger.level}, terminal")
63+
.put("es.logger.level", loggerLevel)
64+
.build(), Terminal.DEFAULT);
65+
// configure but do not read the logging conf file
66+
LogConfigurator.configure(env.settings(), false);
5667
int status = new PluginManagerCliParser().execute(args).status();
5768
System.exit(status);
5869
}

core/src/test/java/org/elasticsearch/common/logging/log4j/Log4jESLoggerTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public void setUp() throws Exception {
5757
.put("path.conf", configDir.toAbsolutePath())
5858
.put("path.home", createTempDir().toString())
5959
.build();
60-
LogConfigurator.configure(settings);
60+
LogConfigurator.configure(settings, true);
6161

6262
esTestLogger = Log4jESLoggerFactory.getLogger("test");
6363
Logger testLogger = ((Log4jESLogger) esTestLogger).logger();

core/src/test/java/org/elasticsearch/common/logging/log4j/LoggingConfigurationTests.java

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232

3333
import java.nio.charset.StandardCharsets;
3434
import java.nio.file.Files;
35+
import java.nio.file.OpenOption;
3536
import java.nio.file.Path;
3637
import java.nio.file.StandardOpenOption;
38+
import java.util.Arrays;
3739

3840
import static org.hamcrest.Matchers.*;
3941

@@ -56,7 +58,7 @@ public void testResolveMultipleConfigs() throws Exception {
5658
.put("path.conf", configDir.toAbsolutePath())
5759
.put("path.home", createTempDir().toString())
5860
.build();
59-
LogConfigurator.configure(settings);
61+
LogConfigurator.configure(settings, true);
6062

6163
ESLogger esLogger = Log4jESLoggerFactory.getLogger("test");
6264
Logger logger = ((Log4jESLogger) esLogger).logger();
@@ -157,20 +159,20 @@ public void testResolveConfigInvalidFilename() throws Exception {
157159
public void testResolveOrder() throws Exception {
158160
Path tmpDir = createTempDir();
159161
Path loggingConf = tmpDir.resolve(loggingConfiguration("yaml"));
160-
Files.write(loggingConf, "logger.test: INFO, file\n".getBytes(StandardCharsets.UTF_8));
162+
Files.write(loggingConf, "logger.test_resolve_order: INFO, file\n".getBytes(StandardCharsets.UTF_8));
161163
Files.write(loggingConf, "appender.file.type: file\n".getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);
162164
Environment environment = InternalSettingsPreparer.prepareEnvironment(
163165
Settings.builder()
164166
.put("path.conf", tmpDir.toAbsolutePath())
165167
.put("path.home", createTempDir().toString())
166-
.put("logger.test", "TRACE, console")
168+
.put("logger.test_resolve_order", "TRACE, console")
167169
.put("appender.console.type", "console")
168170
.put("appender.console.layout.type", "consolePattern")
169171
.put("appender.console.layout.conversionPattern", "[%d{ISO8601}][%-5p][%-25c] %m%n")
170172
.build(), new CliToolTestCase.MockTerminal());
171-
LogConfigurator.configure(environment.settings());
173+
LogConfigurator.configure(environment.settings(), true);
172174
// args should overwrite whatever is in the config
173-
ESLogger esLogger = Log4jESLoggerFactory.getLogger("test");
175+
ESLogger esLogger = Log4jESLoggerFactory.getLogger("test_resolve_order");
174176
Logger logger = ((Log4jESLogger) esLogger).logger();
175177
Appender appender = logger.getAppender("console");
176178
assertThat(appender, notNullValue());
@@ -179,6 +181,31 @@ public void testResolveOrder() throws Exception {
179181
assertThat(appender, nullValue());
180182
}
181183

184+
// tests that config file is not read when we call LogConfigurator.configure(Settings, false)
185+
@Test
186+
public void testConfigNotRead() throws Exception {
187+
Path tmpDir = createTempDir();
188+
Path loggingConf = tmpDir.resolve(loggingConfiguration("yaml"));
189+
Files.write(loggingConf,
190+
Arrays.asList(
191+
"logger.test_config_not_read: INFO, console",
192+
"appender.console.type: console"),
193+
StandardCharsets.UTF_8);
194+
Environment environment = InternalSettingsPreparer.prepareEnvironment(
195+
Settings.builder()
196+
.put("path.conf", tmpDir.toAbsolutePath())
197+
.put("path.home", createTempDir().toString())
198+
.build(), new CliToolTestCase.MockTerminal());
199+
LogConfigurator.configure(environment.settings(), false);
200+
ESLogger esLogger = Log4jESLoggerFactory.getLogger("test_config_not_read");
201+
202+
assertNotNull(esLogger);
203+
Logger logger = ((Log4jESLogger) esLogger).logger();
204+
Appender appender = logger.getAppender("console");
205+
// config was not read
206+
assertNull(appender);
207+
}
208+
182209
private static String loggingConfiguration(String suffix) {
183210
return "logging." + randomAsciiOfLength(randomIntBetween(0, 10)) + "." + suffix;
184211
}

qa/vagrant/src/test/resources/packaging/scripts/plugin_test_cases.bash

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,3 +352,26 @@ fi
352352
@test "[$GROUP] stop elasticsearch" {
353353
stop_elasticsearch_service
354354
}
355+
356+
@test "[$GROUP] install jvm-example with different logging modes and check output" {
357+
local relativePath=${1:-$(readlink -m jvm-example-*.zip)}
358+
sudo -E -u $ESPLUGIN_COMMAND_USER "$ESHOME/bin/plugin" install "file://$relativePath" > /tmp/plugin-cli-output
359+
local loglines=$(cat /tmp/plugin-cli-output | wc -l)
360+
[ "$loglines" = "6" ] || {
361+
echo "Expected 6 lines but the output was:"
362+
cat /tmp/plugin-cli-output
363+
false
364+
}
365+
remove_jvm_example
366+
367+
local relativePath=${1:-$(readlink -m jvm-example-*.zip)}
368+
sudo -E -u $ESPLUGIN_COMMAND_USER "$ESHOME/bin/plugin" install "file://$relativePath" -Des.logger.level=DEBUG > /tmp/plugin-cli-output
369+
local loglines=$(cat /tmp/plugin-cli-output | wc -l)
370+
[ "$loglines" -gt "6" ] || {
371+
echo "Expected more than 6 lines but the output was:"
372+
cat /tmp/plugin-cli-output
373+
false
374+
}
375+
remove_jvm_example
376+
}
377+

qa/vagrant/src/test/resources/packaging/scripts/plugins.bash

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ install_plugin() {
3636

3737
assert_file_exist "$ESPLUGINS/$name"
3838
assert_file_exist "$ESPLUGINS/$name/plugin-descriptor.properties"
39+
#check we did not accidentially create a log file as root as /usr/share/elasticsearch
40+
assert_file_not_exist "/usr/share/elasticsearch/logs"
3941

4042
# At some point installing or removing plugins caused elasticsearch's logs
4143
# to be owned by root. This is bad so we want to make sure it doesn't

0 commit comments

Comments
 (0)