From 4b9f58713f2a24b2164f024b9a5a13c8a506db9b Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Wed, 30 Nov 2016 17:31:23 +0100 Subject: [PATCH] SONAR-8422 add visible error in sonar.log when DB is not ok --- .../org/sonar/ce/app/WebServerBarrier.java | 3 ++ .../server/app/ServerProcessLogging.java | 30 +++++++++++++++++-- .../platform/DatabaseServerCompatibility.java | 10 ++++++- .../sonar/ce/log/CeProcessLoggingTest.java | 16 ++++++++++ .../app/WebServerProcessLoggingTest.java | 16 ++++++++++ .../DatabaseServerCompatibilityTest.java | 14 +++++++-- 6 files changed, 84 insertions(+), 5 deletions(-) diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/app/WebServerBarrier.java b/server/sonar-ce/src/main/java/org/sonar/ce/app/WebServerBarrier.java index 86d4419c7b7..2053d9325f3 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/app/WebServerBarrier.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/app/WebServerBarrier.java @@ -25,6 +25,8 @@ import org.sonar.api.utils.log.Loggers; import org.sonar.process.DefaultProcessCommands; import org.sonar.process.ProcessId; +import static org.sonar.server.app.ServerProcessLogging.STARTUP_LOGGER_NAME; + /** * Waits for the web server to be operational (started and datastores up-to-date) */ @@ -47,6 +49,7 @@ class WebServerBarrier implements StartupBarrier { return true; } + Loggers.get(STARTUP_LOGGER_NAME).info("Compute Engine startup is on hold. Waiting for Web Server to be operational."); LOG.info("Waiting for Web Server to be operational..."); Logger logarithmicLogger = LogarithmicLogger.from(LOG).applyingCallRatio(CALL_RATIO).build(); while (!processCommands.isOperational()) { 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 baeaa88d318..f3814406a3a 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 @@ -20,18 +20,23 @@ package org.sonar.server.app; import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.ConsoleAppender; import com.google.common.collect.ImmutableSet; import java.util.Set; -import org.sonar.process.logging.LogLevelConfig; -import org.sonar.process.logging.LogbackHelper; 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.logging.RootLoggerConfig.newRootLoggerConfigBuilder; public abstract class ServerProcessLogging { + + public static final String STARTUP_LOGGER_NAME = "startup"; protected static final Set JMX_RMI_LOGGER_NAMES = ImmutableSet.of( "javax.management.remote.timeout", "javax.management.remote.misc", @@ -80,8 +85,10 @@ public abstract class ServerProcessLogging { ctx.reset(); helper.enableJulChangePropagation(ctx); + configureRootLogger(props); helper.apply(logLevelConfig, props); + configureDirectToConsoleLoggers(ctx, STARTUP_LOGGER_NAME); extendConfigure(); @@ -107,4 +114,23 @@ public abstract class ServerProcessLogging { helper.configureForSubprocessGobbler(props, logPattern); } + /** + * 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(LoggerContext context, String... loggerNames) { + RootLoggerConfig config = newRootLoggerConfigBuilder() + .setProcessId(ProcessId.APP) + .setThreadIdFieldPattern("") + .build(); + String logPattern = helper.buildLogPattern(config); + ConsoleAppender consoleAppender = helper.newConsoleAppender(context, "CONSOLE", logPattern); + + for (String loggerName : loggerNames) { + Logger consoleLogger = context.getLogger(loggerName); + consoleLogger.setAdditive(false); + consoleLogger.addAppender(consoleAppender); + } + } + } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java b/server/sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java index 89da490e50e..db5548a95fe 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java @@ -24,8 +24,11 @@ import org.sonar.api.utils.MessageException; import org.sonar.api.utils.log.Loggers; import org.sonar.db.version.DatabaseVersion; +import static org.sonar.server.app.ServerProcessLogging.STARTUP_LOGGER_NAME; + public class DatabaseServerCompatibility implements Startable { + private static final String HIGHLIGHTER = "################################################################################"; private DatabaseVersion version; public DatabaseServerCompatibility(DatabaseVersion version) { @@ -43,7 +46,12 @@ public class DatabaseServerCompatibility implements Startable { if (currentVersion != null && currentVersion < DatabaseVersion.MIN_UPGRADE_VERSION) { throw MessageException.of("Current version is too old. Please upgrade to Long Term Support version firstly."); } - Loggers.get(DatabaseServerCompatibility.class).warn("Database must be upgraded. Please backup database and browse /setup"); + String msg = "Database must be upgraded. Please backup database and browse /setup"; + Loggers.get(DatabaseServerCompatibility.class).warn(msg); + Loggers.get(STARTUP_LOGGER_NAME).warn('\n' + + HIGHLIGHTER + '\n' + + " " + msg + + '\n' + HIGHLIGHTER); } } 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 0058688f056..451aac9e379 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 @@ -25,6 +25,7 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; +import ch.qos.logback.core.ConsoleAppender; import ch.qos.logback.core.FileAppender; import ch.qos.logback.core.joran.spi.JoranException; import java.io.File; @@ -74,6 +75,21 @@ public class CeProcessLoggingTest { assertThat(appender).isNull(); } + @Test + public void startup_logger_prints_to_only_to_system_out() { + LoggerContext ctx = underTest.configure(props); + + Logger startup = ctx.getLogger("startup"); + assertThat(startup.isAdditive()).isFalse(); + Appender appender = startup.getAppender("CONSOLE"); + assertThat(appender).isInstanceOf(ConsoleAppender.class); + ConsoleAppender consoleAppender = (ConsoleAppender) appender; + assertThat(consoleAppender.getTarget()).isEqualTo("System.out"); + assertThat(consoleAppender.getEncoder()).isInstanceOf(PatternLayoutEncoder.class); + PatternLayoutEncoder patternEncoder = (PatternLayoutEncoder) consoleAppender.getEncoder(); + assertThat(patternEncoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level app[][%logger{20}] %msg%n"); + } + @Test public void log_to_ce_file() { LoggerContext ctx = underTest.configure(props); 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 02dba16937a..24d661249e7 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 @@ -25,6 +25,7 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; +import ch.qos.logback.core.ConsoleAppender; import ch.qos.logback.core.FileAppender; import ch.qos.logback.core.joran.spi.JoranException; import java.io.File; @@ -74,6 +75,21 @@ public class WebServerProcessLoggingTest { assertThat(appender).isNull(); } + @Test + public void startup_logger_prints_to_only_to_system_out() { + LoggerContext ctx = underTest.configure(props); + + Logger startup = ctx.getLogger("startup"); + assertThat(startup.isAdditive()).isFalse(); + Appender appender = startup.getAppender("CONSOLE"); + assertThat(appender).isInstanceOf(ConsoleAppender.class); + ConsoleAppender consoleAppender = (ConsoleAppender) appender; + assertThat(consoleAppender.getTarget()).isEqualTo("System.out"); + assertThat(consoleAppender.getEncoder()).isInstanceOf(PatternLayoutEncoder.class); + PatternLayoutEncoder patternEncoder = (PatternLayoutEncoder) consoleAppender.getEncoder(); + assertThat(patternEncoder.getPattern()).isEqualTo("%d{yyyy.MM.dd HH:mm:ss} %-5level app[][%logger{20}] %msg%n"); + } + @Test public void log_to_web_file() { LoggerContext ctx = underTest.configure(props); diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/DatabaseServerCompatibilityTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/DatabaseServerCompatibilityTest.java index 5bda5ae0eb5..2749a9b570a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/DatabaseServerCompatibilityTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/DatabaseServerCompatibilityTest.java @@ -23,8 +23,11 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.utils.MessageException; +import org.sonar.api.utils.log.LogTester; +import org.sonar.api.utils.log.LoggerLevel; import org.sonar.db.version.DatabaseVersion; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -32,6 +35,8 @@ public class DatabaseServerCompatibilityTest { @Rule public ExpectedException thrown = ExpectedException.none(); + @Rule + public LogTester logTester = new LogTester(); @Test public void fail_if_requires_downgrade() { @@ -60,8 +65,13 @@ public class DatabaseServerCompatibilityTest { when(version.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE); when(version.getVersion()).thenReturn(DatabaseVersion.MIN_UPGRADE_VERSION); new DatabaseServerCompatibility(version).start(); - // oh well... how to simply test logging ? - // Let's assume that this test verifies that no error is raised. + + assertThat(logTester.logs()).hasSize(2); + assertThat(logTester.logs(LoggerLevel.WARN)).contains( + "Database must be upgraded. Please backup database and browse /setup", + "\n################################################################################\n" + + " Database must be upgraded. Please backup database and browse /setup\n" + + "################################################################################"); } @Test -- 2.39.5