From c3c730f06025f4a83b9a69cc84668c9876594955 Mon Sep 17 00:00:00 2001 From: Jacek Date: Mon, 9 Aug 2021 17:35:50 +0200 Subject: [PATCH] SONAR-11094 Add nodename to logs for DCE only --- .../org/sonar/application/AppLogging.java | 25 ++++++++++++---- .../org/sonar/application/es/EsLogging.java | 18 ++++++++++-- .../sonar/application/es/EsLoggingTest.java | 12 ++++++++ .../process/logging/AbstractLogHelper.java | 16 +++++----- .../logging/Log4JPropertiesBuilder.java | 9 +++++- .../sonar/process/logging/LogbackHelper.java | 4 +-- .../process/logging/LogbackJsonLayout.java | 7 ++++- .../process/logging/RootLoggerConfig.java | 14 +++++++++ .../logging/Log4JPropertiesBuilderTest.java | 29 +++++++++++++++++++ .../process/logging/LogbackHelperTest.java | 10 +++++++ .../logging/LogbackJsonLayoutTest.java | 22 +++++++++++++- .../server/log/ServerProcessLogging.java | 12 ++++++++ .../app/WebServerProcessLoggingTest.java | 18 ++++++++++++ 13 files changed, 175 insertions(+), 21 deletions(-) diff --git a/server/sonar-main/src/main/java/org/sonar/application/AppLogging.java b/server/sonar-main/src/main/java/org/sonar/application/AppLogging.java index 4b0ef55060c..a745eb53bf7 100644 --- a/server/sonar-main/src/main/java/org/sonar/application/AppLogging.java +++ b/server/sonar-main/src/main/java/org/sonar/application/AppLogging.java @@ -26,9 +26,11 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.ConsoleAppender; import ch.qos.logback.core.FileAppender; import ch.qos.logback.core.encoder.Encoder; +import javax.annotation.CheckForNull; import org.sonar.application.config.AppSettings; import org.sonar.application.process.StreamGobbler; import org.sonar.process.ProcessId; +import org.sonar.process.Props; import org.sonar.process.logging.LogLevelConfig; import org.sonar.process.logging.LogbackHelper; import org.sonar.process.logging.PatternLayoutEncoder; @@ -36,6 +38,8 @@ import org.sonar.process.logging.RootLoggerConfig; import static org.slf4j.Logger.ROOT_LOGGER_NAME; import static org.sonar.application.process.StreamGobbler.LOGGER_GOBBLER; +import static org.sonar.process.ProcessProperties.Property.CLUSTER_ENABLED; +import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_NAME; import static org.sonar.process.logging.RootLoggerConfig.newRootLoggerConfigBuilder; /** @@ -114,15 +118,24 @@ public class AppLogging { private static final String CONSOLE_PLAIN_APPENDER = "CONSOLE"; private static final String APP_CONSOLE_APPENDER = "APP_CONSOLE"; private static final String GOBBLER_PLAIN_CONSOLE = "GOBBLER_CONSOLE"; - private static final RootLoggerConfig APP_ROOT_LOGGER_CONFIG = newRootLoggerConfigBuilder() - .setProcessId(ProcessId.APP) - .build(); + private final RootLoggerConfig rootLoggerConfig; private final LogbackHelper helper = new LogbackHelper(); private final AppSettings appSettings; public AppLogging(AppSettings appSettings) { this.appSettings = appSettings; + rootLoggerConfig = newRootLoggerConfigBuilder() + .setNodeNameField(getNodeNameWhenCluster(appSettings.getProps())) + .setProcessId(ProcessId.APP) + .build(); + } + + @CheckForNull + private static String getNodeNameWhenCluster(Props props) { + boolean clusterEnabled = props.valueAsBoolean(CLUSTER_ENABLED.getKey(), + Boolean.parseBoolean(CLUSTER_ENABLED.getDefaultValue())); + return clusterEnabled ? props.value(CLUSTER_NODE_NAME.getKey(), CLUSTER_NODE_NAME.getDefaultValue()) : null; } public LoggerContext configure() { @@ -195,7 +208,7 @@ public class AppLogging { // logs are written to the console because we want them to be in sonar.log and the wrapper will write any log // from APP's System.out and System.err to sonar.log Logger rootLogger = ctx.getLogger(ROOT_LOGGER_NAME); - Encoder encoder = helper.createEncoder(appSettings.getProps(), APP_ROOT_LOGGER_CONFIG, ctx); + Encoder encoder = helper.createEncoder(appSettings.getProps(), rootLoggerConfig, ctx); rootLogger.addAppender(createAppConsoleAppender(ctx, encoder)); // in regular configuration, sub processes are not copying their logs to their System.out, so, the only logs to be @@ -209,8 +222,8 @@ public class AppLogging { private void configureRootWithLogbackWritingToFile(LoggerContext ctx) { Logger rootLogger = ctx.getLogger(ROOT_LOGGER_NAME); - Encoder encoder = helper.createEncoder(appSettings.getProps(), APP_ROOT_LOGGER_CONFIG, ctx); - FileAppender fileAppender = helper.newFileAppender(ctx, appSettings.getProps(), APP_ROOT_LOGGER_CONFIG, encoder); + Encoder encoder = helper.createEncoder(appSettings.getProps(), rootLoggerConfig, ctx); + FileAppender fileAppender = helper.newFileAppender(ctx, appSettings.getProps(), rootLoggerConfig, encoder); rootLogger.addAppender(fileAppender); rootLogger.addAppender(createAppConsoleAppender(ctx, encoder)); } diff --git a/server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java b/server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java index 75e105fa18b..8eb93609a05 100644 --- a/server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java +++ b/server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java @@ -22,6 +22,7 @@ package org.sonar.application.es; import ch.qos.logback.classic.Level; import java.io.File; import java.util.Properties; +import javax.annotation.CheckForNull; import org.sonar.process.ProcessId; import org.sonar.process.ProcessProperties; import org.sonar.process.Props; @@ -29,6 +30,8 @@ import org.sonar.process.logging.Log4JPropertiesBuilder; import org.sonar.process.logging.LogLevelConfig; import org.sonar.process.logging.RootLoggerConfig; +import static org.sonar.process.ProcessProperties.Property.CLUSTER_ENABLED; +import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_NAME; import static org.sonar.process.ProcessProperties.Property.LOG_CONSOLE; import static org.sonar.process.ProcessProperties.Property.LOG_JSON_OUTPUT; import static org.sonar.process.logging.RootLoggerConfig.newRootLoggerConfigBuilder; @@ -37,7 +40,11 @@ public class EsLogging { public Properties createProperties(Props props, File logDir) { Log4JPropertiesBuilder log4JPropertiesBuilder = new Log4JPropertiesBuilder(props); - RootLoggerConfig config = newRootLoggerConfigBuilder().setProcessId(ProcessId.ELASTICSEARCH).build(); + RootLoggerConfig config = newRootLoggerConfigBuilder() + .setNodeNameField(getNodeNameWhenCluster(props)) + .setProcessId(ProcessId.ELASTICSEARCH) + .build(); + String logPattern = log4JPropertiesBuilder.buildLogPattern(config); return log4JPropertiesBuilder.internalLogLevel(Level.ERROR) @@ -59,7 +66,14 @@ public class EsLogging { private static boolean isJsonOutput(Props props) { return props.valueAsBoolean(LOG_JSON_OUTPUT.getKey(), - Boolean.parseBoolean(LOG_JSON_OUTPUT.getDefaultValue())); + Boolean.parseBoolean(LOG_JSON_OUTPUT.getDefaultValue())); + } + + @CheckForNull + private static String getNodeNameWhenCluster(Props props) { + boolean clusterEnabled = props.valueAsBoolean(CLUSTER_ENABLED.getKey(), + Boolean.parseBoolean(CLUSTER_ENABLED.getDefaultValue())); + return clusterEnabled ? props.value(CLUSTER_NODE_NAME.getKey(), CLUSTER_NODE_NAME.getDefaultValue()) : null; } /** diff --git a/server/sonar-main/src/test/java/org/sonar/application/es/EsLoggingTest.java b/server/sonar-main/src/test/java/org/sonar/application/es/EsLoggingTest.java index f62d65b3766..7c4380e2468 100644 --- a/server/sonar-main/src/test/java/org/sonar/application/es/EsLoggingTest.java +++ b/server/sonar-main/src/test/java/org/sonar/application/es/EsLoggingTest.java @@ -112,6 +112,18 @@ public class EsLoggingTest { assertThat(properties.getProperty("rootLogger.level")).isEqualTo("TRACE"); } + @Test + public void createProperties_adds_nodename_if_cluster_property_is_set() throws IOException { + File logDir = temporaryFolder.newFolder(); + Properties properties = underTest.createProperties( + newProps( + "sonar.cluster.enabled", "true", + "sonar.cluster.node.name", "my-node"), + logDir); + + assertThat(properties.getProperty("appender.file_es.layout.pattern")).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level my-node es[][%logger{1.}] %msg%n"); + } + private static Props newProps(String... propertyKeysAndValues) { assertThat(propertyKeysAndValues.length % 2).describedAs("Number of parameters must be even").isZero(); Properties properties = new Properties(); diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java b/server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java index f08417eb852..bb3b795796f 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java @@ -29,10 +29,8 @@ import static java.lang.String.format; public abstract class AbstractLogHelper { static final Level[] ALLOWED_ROOT_LOG_LEVELS = new Level[] {Level.TRACE, Level.DEBUG, Level.INFO}; - private static final String PROCESS_NAME_PLACEHOLDER = "XXXX"; - private static final String THREAD_ID_PLACEHOLDER = "ZZZZ"; - private static final String LOGGER_NAME_PLACEHOLDER = "YYYY"; - private static final String LOG_FORMAT = "%d{yyyy.MM.dd HH:mm:ss} %-5level " + PROCESS_NAME_PLACEHOLDER + "[" + THREAD_ID_PLACEHOLDER + "][YYYY] %msg%n"; + private static final String PREFIX_LOG_FORMAT = "%d{yyyy.MM.dd HH:mm:ss} %-5level "; + private static final String SUFFIX_LOG_FORMAT = " %msg%n"; private final String loggerNamePattern; protected AbstractLogHelper(String loggerNamePattern) { @@ -42,10 +40,12 @@ public abstract class AbstractLogHelper { public abstract String getRootLoggerName(); public String buildLogPattern(RootLoggerConfig config) { - return LOG_FORMAT - .replace(PROCESS_NAME_PLACEHOLDER, config.getProcessId().getKey()) - .replace(THREAD_ID_PLACEHOLDER, config.getThreadIdFieldPattern()) - .replace(LOGGER_NAME_PLACEHOLDER, loggerNamePattern); + return PREFIX_LOG_FORMAT + + (config.getNodeNameField().isBlank() ? "" : (config.getNodeNameField() + " ")) + + config.getProcessId().getKey() + + "[" + config.getThreadIdFieldPattern() + "]" + + "[" + loggerNamePattern + "]" + + SUFFIX_LOG_FORMAT; } /** diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java b/server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java index c450d940d62..8bd5b836c9c 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java @@ -238,7 +238,14 @@ public class Log4JPropertiesBuilder extends AbstractLogHelper { * json pattern based on https://github.com/elastic/elasticsearch/blob/7.13/server/src/main/java/org/elasticsearch/common/logging/ESJsonLayout.java */ private String getJsonPattern() { - return "{" + String json = "{"; + if (!"".equals(config.getNodeNameField())) { + json = json + + jsonKey("nodename") + + inQuotes(config.getNodeNameField()) + + ","; + } + return json + jsonKey("process") + inQuotes(config.getProcessId().getKey()) + "," diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java b/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java index e95fb20eda0..f9738bb12bd 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java @@ -52,10 +52,10 @@ import org.sonar.process.Props; import static java.lang.String.format; import static org.slf4j.Logger.ROOT_LOGGER_NAME; import static org.sonar.process.ProcessProperties.Property.LOG_CONSOLE; +import static org.sonar.process.ProcessProperties.Property.LOG_JSON_OUTPUT; import static org.sonar.process.ProcessProperties.Property.LOG_LEVEL; import static org.sonar.process.ProcessProperties.Property.LOG_MAX_FILES; import static org.sonar.process.ProcessProperties.Property.LOG_ROLLING_POLICY; -import static org.sonar.process.ProcessProperties.Property.LOG_JSON_OUTPUT; import static org.sonar.process.ProcessProperties.Property.PATH_LOGS; /** @@ -232,7 +232,7 @@ public class LogbackHelper extends AbstractLogHelper { public Encoder createEncoder(Props props, RootLoggerConfig config, LoggerContext context) { if (props.valueAsBoolean(LOG_JSON_OUTPUT.getKey(), Boolean.parseBoolean(LOG_JSON_OUTPUT.getDefaultValue()))) { LayoutWrappingEncoder encoder = new LayoutWrappingEncoder<>(); - encoder.setLayout(new LogbackJsonLayout(config.getProcessId().getKey())); + encoder.setLayout(new LogbackJsonLayout(config.getProcessId().getKey(), config.getNodeNameField())); encoder.setContext(context); encoder.start(); return encoder; diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackJsonLayout.java b/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackJsonLayout.java index d0ed49a5f1d..d25ce3a5b44 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackJsonLayout.java +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/LogbackJsonLayout.java @@ -51,9 +51,11 @@ public class LogbackJsonLayout extends LayoutBase { private static final Pattern NEWLINE_REGEXP = Pattern.compile("\n"); private final String processKey; + private final String nodeName; - public LogbackJsonLayout(String processKey) { + public LogbackJsonLayout(String processKey, String nodeName) { this.processKey = requireNonNull(processKey); + this.nodeName = nodeName; } String getProcessKey() { @@ -65,6 +67,9 @@ public class LogbackJsonLayout extends LayoutBase { StringWriter output = new StringWriter(); try (JsonWriter json = new JsonWriter(output)) { json.beginObject(); + if (!"".equals(nodeName)) { + json.name("nodename").value(nodeName); + } json.name("process").value(processKey); for (Map.Entry entry : event.getMDCPropertyMap().entrySet()) { if (entry.getValue() != null) { diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/RootLoggerConfig.java b/server/sonar-process/src/main/java/org/sonar/process/logging/RootLoggerConfig.java index 00ceba2dd6c..02b74d06b71 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/logging/RootLoggerConfig.java +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/RootLoggerConfig.java @@ -19,7 +19,9 @@ */ package org.sonar.process.logging; +import java.util.Optional; import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import org.sonar.process.ProcessId; import static java.util.Objects.requireNonNull; @@ -27,16 +29,22 @@ import static java.util.Objects.requireNonNull; public final class RootLoggerConfig { private final ProcessId processId; private final String threadIdFieldPattern; + private final String nodeNameField; private RootLoggerConfig(Builder builder) { this.processId = requireNonNull(builder.processId); this.threadIdFieldPattern = builder.threadIdFieldPattern; + this.nodeNameField = Optional.ofNullable(builder.nodeNameField).orElse(""); } public static Builder newRootLoggerConfigBuilder() { return new Builder(); } + public String getNodeNameField() { + return nodeNameField; + } + public ProcessId getProcessId() { return processId; } @@ -49,11 +57,17 @@ public final class RootLoggerConfig { @CheckForNull private ProcessId processId; private String threadIdFieldPattern = ""; + private String nodeNameField; private Builder() { // prevents instantiation outside RootLoggerConfig, use static factory method } + public Builder setNodeNameField(@Nullable String nodeNameField) { + this.nodeNameField = nodeNameField; + return this; + } + public Builder setProcessId(ProcessId processId) { this.processId = processId; return this; diff --git a/server/sonar-process/src/test/java/org/sonar/process/logging/Log4JPropertiesBuilderTest.java b/server/sonar-process/src/test/java/org/sonar/process/logging/Log4JPropertiesBuilderTest.java index 975eba70c3f..bd0ceae2e9d 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/logging/Log4JPropertiesBuilderTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/logging/Log4JPropertiesBuilderTest.java @@ -353,6 +353,35 @@ public class Log4JPropertiesBuilderTest { "appender.file_es.type", "File"); } + @Test + public void enable_json_output_should_include_hostname_if_set() throws IOException { + File logDir = temporaryFolder.newFolder(); + RootLoggerConfig esRootLoggerConfigWithHostname = newRootLoggerConfigBuilder() + .setProcessId(ProcessId.ELASTICSEARCH) + .setNodeNameField("my-node") + .build(); + String expectedPattern = "{\"nodename\": \"my-node\",\"process\": \"es\",\"timestamp\": \"%d{yyyy-MM-dd'T'HH:mm:ss.SSSZZ}\"," + + "\"severity\": \"%p\",\"logger\": \"%c{1.}\",\"message\": \"%notEmpty{%enc{%marker}{JSON} }%enc{%.-10000m}{JSON}\"%exceptionAsJson }" + System.lineSeparator(); + + Log4JPropertiesBuilder underTest = newLog4JPropertiesBuilder(ROLLING_POLICY_PROPERTY, "none") + .enableAllLogsToConsole(true) + .rootLoggerConfig(esRootLoggerConfigWithHostname) + .jsonOutput(true) + .logDir(logDir); + verifyProperties(underTest.build(), + "appender.stdout.type", "Console", + "appender.stdout.name", "stdout", + "appender.stdout.layout.type", "PatternLayout", + "appender.stdout.layout.pattern", expectedPattern, + "rootLogger.appenderRef.stdout.ref", "stdout", + "appender.file_es.layout.type", "PatternLayout", + "appender.file_es.layout.pattern", expectedPattern, + "appender.file_es.fileName", new File(logDir, "es.log").getAbsolutePath(), + "appender.file_es.name", "file_es", + "rootLogger.appenderRef.file_es.ref", "file_es", + "appender.file_es.type", "File"); + } + @Test public void apply_fails_with_IAE_if_LogLevelConfig_does_not_have_rootLoggerName_of_Log4J() throws IOException { LogLevelConfig logLevelConfig = LogLevelConfig.newBuilder(randomAlphanumeric(2)).build(); diff --git a/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java b/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java index 7806aaa0a78..022587fcd73 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java @@ -99,6 +99,16 @@ public class LogbackHelperTest { assertThat(pattern).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level es[][%logger{20}] %msg%n"); } + @Test + public void buildLogPattern_adds_nodename() { + String pattern = underTest.buildLogPattern(newRootLoggerConfigBuilder() + .setProcessId(ProcessId.ELASTICSEARCH) + .setNodeNameField("my-nodename") + .build()); + + assertThat(pattern).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level my-nodename es[][%logger{20}] %msg%n"); + } + @Test public void buildLogPattern_puts_threadIdFieldPattern_from_RootLoggerConfig_non_null() { String threadIdFieldPattern = RandomStringUtils.randomAlphabetic(5); diff --git a/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackJsonLayoutTest.java b/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackJsonLayoutTest.java index 6a207d6a746..4c05a92684f 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackJsonLayoutTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/logging/LogbackJsonLayoutTest.java @@ -33,7 +33,7 @@ import static org.sonar.process.logging.LogbackJsonLayout.DATE_FORMATTER; public class LogbackJsonLayoutTest { - private final LogbackJsonLayout underTest = new LogbackJsonLayout("web"); + private final LogbackJsonLayout underTest = new LogbackJsonLayout("web", ""); @Test public void test_simple_log() { @@ -49,6 +49,25 @@ public class LogbackJsonLayoutTest { assertThat(json.message).isEqualTo("the message"); assertThat(json.stacktrace).isNull(); assertThat(json.fromMdc).isNull(); + assertThat(json.nodename).isNull(); + } + + @Test + public void test_simple_log_with_hostname() { + LoggingEvent event = new LoggingEvent("org.foundation.Caller", (Logger) LoggerFactory.getLogger("the.logger"), Level.WARN, "the message", null, new Object[0]); + + LogbackJsonLayout underTestWithNodeName = new LogbackJsonLayout("web", "my-nodename"); + String log = underTestWithNodeName.doLayout(event); + + JsonLog json = new Gson().fromJson(log, JsonLog.class); + assertThat(json.process).isEqualTo("web"); + assertThat(json.timestamp).isEqualTo(DATE_FORMATTER.format(Instant.ofEpochMilli(event.getTimeStamp()))); + assertThat(json.severity).isEqualTo("WARN"); + assertThat(json.logger).isEqualTo("the.logger"); + assertThat(json.message).isEqualTo("the message"); + assertThat(json.stacktrace).isNull(); + assertThat(json.fromMdc).isNull(); + assertThat(json.nodename).isEqualTo("my-nodename"); } @Test @@ -140,5 +159,6 @@ public class LogbackJsonLayoutTest { private String message; private String fromMdc; private String[] stacktrace; + private String nodename; } } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/log/ServerProcessLogging.java b/server/sonar-server-common/src/main/java/org/sonar/server/log/ServerProcessLogging.java index d2d82065df0..8066360424f 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/log/ServerProcessLogging.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/log/ServerProcessLogging.java @@ -27,12 +27,15 @@ import ch.qos.logback.core.ConsoleAppender; import ch.qos.logback.core.encoder.Encoder; import com.google.common.collect.ImmutableSet; import java.util.Set; +import javax.annotation.CheckForNull; import org.sonar.process.ProcessId; import org.sonar.process.Props; import org.sonar.process.logging.LogLevelConfig; import org.sonar.process.logging.LogbackHelper; import org.sonar.process.logging.RootLoggerConfig; +import static org.sonar.process.ProcessProperties.Property.CLUSTER_ENABLED; +import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_NAME; import static org.sonar.process.logging.RootLoggerConfig.newRootLoggerConfigBuilder; public abstract class ServerProcessLogging { @@ -132,6 +135,7 @@ public abstract class ServerProcessLogging { private void configureRootLogger(Props props) { RootLoggerConfig config = newRootLoggerConfigBuilder() .setProcessId(processId) + .setNodeNameField(getNodeNameWhenCluster(props)) .setThreadIdFieldPattern(threadIdFieldPattern) .build(); Encoder encoder = helper.createEncoder(props, config, helper.getRootContext()); @@ -139,12 +143,20 @@ public abstract class ServerProcessLogging { helper.configureForSubprocessGobbler(props, encoder); } + @CheckForNull + private static String getNodeNameWhenCluster(Props props) { + boolean clusterEnabled = props.valueAsBoolean(CLUSTER_ENABLED.getKey(), + Boolean.parseBoolean(CLUSTER_ENABLED.getDefaultValue())); + return clusterEnabled ? props.value(CLUSTER_NODE_NAME.getKey(), CLUSTER_NODE_NAME.getDefaultValue()) : null; + } + /** * Setup one or more specified loggers to be non additive and to print to System.out which will be caught by the Main * Process and written to sonar.log. */ private void configureDirectToConsoleLoggers(Props props, LoggerContext context, String... loggerNames) { RootLoggerConfig config = newRootLoggerConfigBuilder() + .setNodeNameField(getNodeNameWhenCluster(props)) .setProcessId(ProcessId.APP) .setThreadIdFieldPattern("") .build(); diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/app/WebServerProcessLoggingTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/app/WebServerProcessLoggingTest.java index 8b44a82f0e3..52f87a55e75 100644 --- a/server/sonar-webserver-core/src/test/java/org/sonar/server/app/WebServerProcessLoggingTest.java +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/app/WebServerProcessLoggingTest.java @@ -132,6 +132,24 @@ public class WebServerProcessLoggingTest { assertThat(encoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level web[%X{HTTP_REQUEST_ID}][%logger{20}] %msg%n"); } + @Test + public void log_for_cluster_changes_layout_in_file_and_console() { + props.set("sonar.cluster.enabled", "true"); + props.set("sonar.cluster.node.name", "my-node"); + LoggerContext ctx = underTest.configure(props); + + Logger root = ctx.getLogger(Logger.ROOT_LOGGER_NAME); + FileAppender fileAppender = (FileAppender) root.getAppender("file_web"); + PatternLayoutEncoder encoder = (PatternLayoutEncoder) fileAppender.getEncoder(); + + assertThat(encoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level my-node web[%X{HTTP_REQUEST_ID}][%logger{20}] %msg%n"); + + Logger startup = ctx.getLogger("startup"); + ConsoleAppender consoleAppender = (ConsoleAppender) startup.getAppender("CONSOLE"); + PatternLayoutEncoder patternEncoder = (PatternLayoutEncoder) consoleAppender.getEncoder(); + assertThat(patternEncoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level my-node app[][%logger{20}] %msg%n"); + } + @Test public void default_level_for_root_logger_is_INFO() { LoggerContext ctx = underTest.configure(props); -- 2.39.5