aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-main/src/main/java/org/sonar/application/AppLogging.java25
-rw-r--r--server/sonar-main/src/main/java/org/sonar/application/es/EsLogging.java18
-rw-r--r--server/sonar-main/src/test/java/org/sonar/application/es/EsLoggingTest.java12
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/logging/AbstractLogHelper.java16
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/logging/Log4JPropertiesBuilder.java9
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/logging/LogbackHelper.java4
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/logging/LogbackJsonLayout.java7
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/logging/RootLoggerConfig.java14
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/logging/Log4JPropertiesBuilderTest.java29
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/logging/LogbackHelperTest.java10
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/logging/LogbackJsonLayoutTest.java22
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/log/ServerProcessLogging.java12
-rw-r--r--server/sonar-webserver-core/src/test/java/org/sonar/server/app/WebServerProcessLoggingTest.java18
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<ILoggingEvent> encoder = helper.createEncoder(appSettings.getProps(), APP_ROOT_LOGGER_CONFIG, ctx);
+ Encoder<ILoggingEvent> 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<ILoggingEvent> encoder = helper.createEncoder(appSettings.getProps(), APP_ROOT_LOGGER_CONFIG, ctx);
- FileAppender<ILoggingEvent> fileAppender = helper.newFileAppender(ctx, appSettings.getProps(), APP_ROOT_LOGGER_CONFIG, encoder);
+ Encoder<ILoggingEvent> encoder = helper.createEncoder(appSettings.getProps(), rootLoggerConfig, ctx);
+ FileAppender<ILoggingEvent> 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<ILoggingEvent> 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<ILoggingEvent> {
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<ILoggingEvent> {
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<String, String> 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
@@ -354,6 +354,35 @@ public class Log4JPropertiesBuilderTest {
}
@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();
File logDir = temporaryFolder.newFolder();
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
@@ -100,6 +100,16 @@ public class LogbackHelperTest {
}
@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);
String pattern = underTest.buildLogPattern(
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<ILoggingEvent> 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
@@ -133,6 +133,24 @@ public class WebServerProcessLoggingTest {
}
@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<ILoggingEvent> consoleAppender = (ConsoleAppender<ILoggingEvent>) 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);