diff options
author | Jacek <jacek.poreda@sonarsource.com> | 2021-08-09 17:35:50 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-08-11 20:08:08 +0000 |
commit | c3c730f06025f4a83b9a69cc84668c9876594955 (patch) | |
tree | 1d21ef19abc8d72928eb2b9f0f43678cb1695347 /server/sonar-process | |
parent | bb03cec435d188cc7fd5576eced84eaa2c634212 (diff) | |
download | sonarqube-c3c730f06025f4a83b9a69cc84668c9876594955.tar.gz sonarqube-c3c730f06025f4a83b9a69cc84668c9876594955.zip |
SONAR-11094 Add nodename to logs for DCE only
Diffstat (limited to 'server/sonar-process')
8 files changed, 98 insertions, 13 deletions
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; } } |