diff options
9 files changed, 137 insertions, 32 deletions
diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/StreamGobbler.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/StreamGobbler.java index 6020f255e36..52a43e170d1 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/StreamGobbler.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/StreamGobbler.java @@ -19,27 +19,26 @@ */ package org.sonar.process.monitor; -import org.apache.commons.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; - import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import javax.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Reads process output and writes to logs */ -class StreamGobbler extends Thread { +public class StreamGobbler extends Thread { + + public static final String LOGGER_GOBBLER = "gobbler"; private final InputStream is; private final Logger logger; StreamGobbler(InputStream is, String processKey) { - this(is, processKey, LoggerFactory.getLogger("gobbler")); + this(is, processKey, LoggerFactory.getLogger(LOGGER_GOBBLER)); } StreamGobbler(InputStream is, String processKey, Logger logger) { @@ -50,16 +49,13 @@ class StreamGobbler extends Thread { @Override public void run() { - BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); - try { + try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { String line; while ((line = br.readLine()) != null) { logger.info(line); } } catch (Exception ignored) { // ignored - } finally { - IOUtils.closeQuietly(br); } } diff --git a/server/sonar-process/src/main/java/org/sonar/process/LogbackHelper.java b/server/sonar-process/src/main/java/org/sonar/process/LogbackHelper.java index 8b7c8bf5150..d4496f747c1 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/LogbackHelper.java +++ b/server/sonar-process/src/main/java/org/sonar/process/LogbackHelper.java @@ -37,9 +37,12 @@ import ch.qos.logback.core.rolling.RollingFileAppender; import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy; import ch.qos.logback.core.rolling.TimeBasedRollingPolicy; import java.io.File; +import javax.annotation.CheckForNull; import org.apache.commons.lang.StringUtils; import org.slf4j.LoggerFactory; +import static java.util.Objects.requireNonNull; + /** * Helps to configure Logback in a programmatic way, without using XML. */ @@ -47,8 +50,9 @@ public class LogbackHelper { public static final String ROLLING_POLICY_PROPERTY = "sonar.log.rollingPolicy"; public static final String MAX_FILES_PROPERTY = "sonar.log.maxFiles"; + private static final String PROCESS_NAME_PLACEHOLDER = "XXXX"; private static final String THREAD_ID_PLACEHOLDER = "ZZZZ"; - private static final String LOG_FORMAT = "%d{yyyy.MM.dd HH:mm:ss} %-5level [" + THREAD_ID_PLACEHOLDER + "][%logger{20}] %msg%n"; + private static final String LOG_FORMAT = "%d{yyyy.MM.dd HH:mm:ss} %-5level " + PROCESS_NAME_PLACEHOLDER + "[" + THREAD_ID_PLACEHOLDER + "][%logger{20}] %msg%n"; public LoggerContext getRootContext() { org.slf4j.Logger logger; @@ -76,10 +80,99 @@ public class LogbackHelper { return propagator; } - public void configureRootLogger(LoggerContext ctx, Props props, String threadIdFieldPattern, String fileName) { - String logFormat = LOG_FORMAT.replace(THREAD_ID_PLACEHOLDER, threadIdFieldPattern); + public static final class RootLoggerConfig { + private final String processName; + private final String threadIdFieldPattern; + private final String fileName; + private final boolean detachConsole; + + public RootLoggerConfig(Builder builder) { + this.processName = builder.processName; + this.threadIdFieldPattern = builder.threadIdFieldPattern; + this.fileName = builder.fileName; + this.detachConsole = builder.detachConsole; + } + + public static Builder newRootLoggerConfigBuilder() { + return new Builder(); + } + + public String getProcessName() { + return processName; + } + + public String getThreadIdFieldPattern() { + return threadIdFieldPattern; + } + + public String getFileName() { + return fileName; + } + + public boolean isDetachConsole() { + return detachConsole; + } + + public static final class Builder { + @CheckForNull + public String processName; + private String threadIdFieldPattern = ""; + @CheckForNull + private String fileName; + private boolean detachConsole = true; + + private Builder() { + // prevents instantiation outside RootLoggerConfig, use static factory method + } + + public Builder setProcessName(String processName) { + checkProcessName(processName); + this.processName = processName; + return this; + } + + public Builder setThreadIdFieldPattern(String threadIdFieldPattern) { + this.threadIdFieldPattern = requireNonNull(threadIdFieldPattern, "threadIdFieldPattern can't be null"); + return this; + } + + public Builder setFileName(String fileName) { + checkFileName(fileName); + this.fileName = fileName; + return this; + } + + private static void checkFileName(String fileName) { + if (requireNonNull(fileName, "fileName can't be null").isEmpty()) { + throw new IllegalArgumentException("fileName can't be empty"); + } + } + + private static void checkProcessName(String fileName) { + if (requireNonNull(fileName, "processName can't be null").isEmpty()) { + throw new IllegalArgumentException("processName can't be empty"); + } + } + + public Builder setDetachConsole(boolean detachConsole) { + this.detachConsole = detachConsole; + return this; + } + + public RootLoggerConfig build() { + checkProcessName(this.processName); + checkFileName(this.fileName); + return new RootLoggerConfig(this); + } + } + } + + public void configureRootLogger(LoggerContext ctx, Props props, RootLoggerConfig config) { + String logFormat = LOG_FORMAT + .replace(PROCESS_NAME_PLACEHOLDER, config.getProcessName()) + .replace(THREAD_ID_PLACEHOLDER, config.getThreadIdFieldPattern()); // configure appender - LogbackHelper.RollingPolicy rollingPolicy = createRollingPolicy(ctx, props, fileName); + LogbackHelper.RollingPolicy rollingPolicy = createRollingPolicy(ctx, props, config.getFileName()); FileAppender<ILoggingEvent> fileAppender = rollingPolicy.createAppender("file"); fileAppender.setContext(ctx); PatternLayoutEncoder fileEncoder = new PatternLayoutEncoder(); @@ -92,7 +185,10 @@ public class LogbackHelper { // configure logger Logger rootLogger = ctx.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME); rootLogger.addAppender(fileAppender); - rootLogger.detachAppender("console"); +// if (config.isDetachConsole()) { +// rootLogger.detachAppender("console"); +// } + rootLogger.addAppender(newConsoleAppender(ctx, "console", logFormat)); } public ConsoleAppender newConsoleAppender(Context loggerContext, String name, String pattern, Filter... filters) { diff --git a/server/sonar-search/src/main/java/org/sonar/search/SearchLogging.java b/server/sonar-search/src/main/java/org/sonar/search/SearchLogging.java index 174733eb097..4667d67f051 100644 --- a/server/sonar-search/src/main/java/org/sonar/search/SearchLogging.java +++ b/server/sonar-search/src/main/java/org/sonar/search/SearchLogging.java @@ -23,6 +23,8 @@ import ch.qos.logback.classic.LoggerContext; import org.sonar.process.LogbackHelper; import org.sonar.process.Props; +import static org.sonar.process.LogbackHelper.RootLoggerConfig.newRootLoggerConfigBuilder; + public class SearchLogging { private LogbackHelper helper = new LogbackHelper(); @@ -31,7 +33,7 @@ public class SearchLogging { LoggerContext ctx = helper.getRootContext(); ctx.reset(); - helper.configureRootLogger(ctx, props, "", "es"); + helper.configureRootLogger(ctx, props, newRootLoggerConfigBuilder().setProcessName("es").setFileName("es").build()); return ctx; } diff --git a/server/sonar-search/src/test/java/org/sonar/search/SearchLoggingTest.java b/server/sonar-search/src/test/java/org/sonar/search/SearchLoggingTest.java index dde89d32d45..ab229e74a76 100644 --- a/server/sonar-search/src/test/java/org/sonar/search/SearchLoggingTest.java +++ b/server/sonar-search/src/test/java/org/sonar/search/SearchLoggingTest.java @@ -79,6 +79,6 @@ public class SearchLoggingTest { assertThat(fileAppender.getFile()).isEqualTo(new File(logDir, "es.log").getAbsolutePath()); assertThat(fileAppender.getEncoder()).isInstanceOf(PatternLayoutEncoder.class); PatternLayoutEncoder encoder = (PatternLayoutEncoder) fileAppender.getEncoder(); - assertThat(encoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level [][%logger{20}] %msg%n"); + assertThat(encoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level es[][%logger{20}] %msg%n"); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/ServerProcessLogging.java b/server/sonar-server/src/main/java/org/sonar/server/app/ServerProcessLogging.java index 50feea704f6..72aea06c92a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/app/ServerProcessLogging.java +++ b/server/sonar-server/src/main/java/org/sonar/server/app/ServerProcessLogging.java @@ -28,6 +28,8 @@ import org.sonar.process.LogbackHelper; import org.sonar.process.Props; import org.sonar.server.platform.ServerLogging; +import static org.sonar.process.LogbackHelper.RootLoggerConfig.newRootLoggerConfigBuilder; + public abstract class ServerProcessLogging { private static final String LOG_LEVEL_PROPERTY = "sonar.log.level"; private final String processName; @@ -44,7 +46,12 @@ public abstract class ServerProcessLogging { ctx.reset(); helper.enableJulChangePropagation(ctx); - helper.configureRootLogger(ctx, props, threadIdFieldPattern, processName); + helper.configureRootLogger(ctx, props, + newRootLoggerConfigBuilder() + .setProcessName(processName) + .setThreadIdFieldPattern(threadIdFieldPattern) + .setFileName(processName) + .build()); configureLevels(props); // Configure java.util.logging, used by Tomcat, in order to forward to slf4j diff --git a/server/sonar-server/src/test/java/org/sonar/ce/log/CeProcessLoggingTest.java b/server/sonar-server/src/test/java/org/sonar/ce/log/CeProcessLoggingTest.java index fa94f15e1b1..b2e39b3e5d8 100644 --- a/server/sonar-server/src/test/java/org/sonar/ce/log/CeProcessLoggingTest.java +++ b/server/sonar-server/src/test/java/org/sonar/ce/log/CeProcessLoggingTest.java @@ -83,7 +83,7 @@ public class CeProcessLoggingTest { assertThat(fileAppender.getFile()).isEqualTo(new File(logDir, "ce.log").getAbsolutePath()); assertThat(fileAppender.getEncoder()).isInstanceOf(PatternLayoutEncoder.class); PatternLayoutEncoder encoder = (PatternLayoutEncoder) fileAppender.getEncoder(); - assertThat(encoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level [%X{ceTaskUuid}][%logger{20}] %msg%n"); + assertThat(encoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level ce[%X{ceTaskUuid}][%logger{20}] %msg%n"); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/WebServerProcessLoggingTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/WebServerProcessLoggingTest.java index 9c9e60e6d34..170ea8b6c11 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/app/WebServerProcessLoggingTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/app/WebServerProcessLoggingTest.java @@ -83,7 +83,7 @@ public class WebServerProcessLoggingTest { assertThat(fileAppender.getFile()).isEqualTo(new File(logDir, "web.log").getAbsolutePath()); assertThat(fileAppender.getEncoder()).isInstanceOf(PatternLayoutEncoder.class); PatternLayoutEncoder encoder = (PatternLayoutEncoder) fileAppender.getEncoder(); - assertThat(encoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level [%X{UID}][%logger{20}] %msg%n"); + assertThat(encoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level web[%X{UID}][%logger{20}] %msg%n"); } @Test diff --git a/sonar-application/src/main/java/org/sonar/application/AppLogging.java b/sonar-application/src/main/java/org/sonar/application/AppLogging.java index 12cad324f57..4395f19e7fa 100644 --- a/sonar-application/src/main/java/org/sonar/application/AppLogging.java +++ b/sonar-application/src/main/java/org/sonar/application/AppLogging.java @@ -31,6 +31,8 @@ import org.slf4j.LoggerFactory; import org.sonar.process.LogbackHelper; import org.sonar.process.Props; +import static org.sonar.process.monitor.StreamGobbler.LOGGER_GOBBLER; + /** * Configure logback for the master process */ @@ -38,7 +40,6 @@ class AppLogging { static final String CONSOLE_LOGGER = "console"; static final String CONSOLE_APPENDER = "CONSOLE"; - static final String GOBBLER_LOGGER = "gobbler"; static final String GOBBLER_APPENDER = "GOBBLER"; static final String APP_PATTERN = "%d{yyyy.MM.dd HH:mm:ss} %-5level app[][%logger{20}] %msg%n"; @@ -65,7 +66,7 @@ class AppLogging { Logger consoleLogger = (Logger) LoggerFactory.getLogger(CONSOLE_LOGGER); Appender<ILoggingEvent> consoleAppender = consoleLogger.getAppender(CONSOLE_APPENDER); - Logger gobblerLogger = (Logger) LoggerFactory.getLogger(GOBBLER_LOGGER); + Logger gobblerLogger = (Logger) LoggerFactory.getLogger(LOGGER_GOBBLER); gobblerLogger.addAppender(consoleAppender); } @@ -89,7 +90,7 @@ class AppLogging { fileAppender.start(); // configure logger - Logger gobblerLogger = ctx.getLogger(GOBBLER_LOGGER); + Logger gobblerLogger = ctx.getLogger(LOGGER_GOBBLER); gobblerLogger.setAdditive(false); gobblerLogger.addAppender(fileAppender); } diff --git a/sonar-application/src/test/java/org/sonar/application/AppLoggingTest.java b/sonar-application/src/test/java/org/sonar/application/AppLoggingTest.java index 202ccf47b20..4465bcb0664 100644 --- a/sonar-application/src/test/java/org/sonar/application/AppLoggingTest.java +++ b/sonar-application/src/test/java/org/sonar/application/AppLoggingTest.java @@ -38,19 +38,22 @@ import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.process.monitor.StreamGobbler.LOGGER_GOBBLER; public class AppLoggingTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); - Props props = new Props(new Properties()); - AppLogging underTest = new AppLogging(); + private File logDir; + + private Props props = new Props(new Properties()); + private AppLogging underTest = new AppLogging(); @Before public void setUp() throws Exception { - File dir = temp.newFolder(); - props.set(ProcessProperties.PATH_LOGS, dir.getAbsolutePath()); + logDir = temp.newFolder(); + props.set(ProcessProperties.PATH_LOGS, logDir.getAbsolutePath()); } @AfterClass @@ -62,7 +65,7 @@ public class AppLoggingTest { public void configure_defaults() { LoggerContext ctx = underTest.configure(props); - Logger gobbler = ctx.getLogger(AppLogging.GOBBLER_LOGGER); + Logger gobbler = ctx.getLogger(LOGGER_GOBBLER); Appender<ILoggingEvent> appender = gobbler.getAppender(AppLogging.GOBBLER_APPENDER); assertThat(appender).isInstanceOf(RollingFileAppender.class); @@ -77,7 +80,7 @@ public class AppLoggingTest { LoggerContext ctx = underTest.configure(props); - Logger gobbler = ctx.getLogger(AppLogging.GOBBLER_LOGGER); + Logger gobbler = ctx.getLogger(LOGGER_GOBBLER); Appender<ILoggingEvent> appender = gobbler.getAppender(AppLogging.GOBBLER_APPENDER); assertThat(appender).isNotInstanceOf(RollingFileAppender.class).isInstanceOf(FileAppender.class); } @@ -87,7 +90,7 @@ public class AppLoggingTest { props.set("sonar.log.console", "true"); LoggerContext ctx = underTest.configure(props); - Logger gobbler = ctx.getLogger(AppLogging.GOBBLER_LOGGER); + Logger gobbler = ctx.getLogger(LOGGER_GOBBLER); assertThat(gobbler.getAppender(AppLogging.GOBBLER_APPENDER)).isNotNull(); assertThat(gobbler.getAppender(AppLogging.CONSOLE_APPENDER)).isNotNull(); } |