From 9112c817aaf6d3273888cc3ef82245f4fcda3b4b Mon Sep 17 00:00:00 2001 From: Jacek Date: Fri, 26 Jun 2020 15:41:48 +0200 Subject: [PATCH] SONAR-13461 fix SSF-112 --- .../ce/logging/CeProcessLoggingTest.java | 2 +- .../org/sonar/application/AppLogging.java | 2 +- .../org/sonar/application/AppLoggingTest.java | 2 +- .../logging/EscapedMessageConverter.java | 44 +++++++ .../sonar/process/logging/LogbackHelper.java | 1 - .../process/logging/PatternLayoutEncoder.java | 49 ++++++++ .../logging/EscapedMessageConverterTest.java | 65 +++++++++++ .../process/logging/LogbackHelperTest.java | 1 - .../logging/PatternLayoutEncoderTest.java | 49 ++++++++ .../process/logging/TestILoggingEvent.java | 110 ++++++++++++++++++ .../app/WebServerProcessLoggingTest.java | 6 +- 11 files changed, 323 insertions(+), 8 deletions(-) create mode 100644 server/sonar-process/src/main/java/org/sonar/process/logging/EscapedMessageConverter.java create mode 100644 server/sonar-process/src/main/java/org/sonar/process/logging/PatternLayoutEncoder.java create mode 100644 server/sonar-process/src/test/java/org/sonar/process/logging/EscapedMessageConverterTest.java create mode 100644 server/sonar-process/src/test/java/org/sonar/process/logging/PatternLayoutEncoderTest.java create mode 100644 server/sonar-process/src/test/java/org/sonar/process/logging/TestILoggingEvent.java diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/logging/CeProcessLoggingTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/logging/CeProcessLoggingTest.java index 2e5d60207a7..e8ad68179f3 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/logging/CeProcessLoggingTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/logging/CeProcessLoggingTest.java @@ -22,7 +22,6 @@ package org.sonar.ce.logging; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; 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; @@ -40,6 +39,7 @@ import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.sonar.process.Props; import org.sonar.process.logging.LogbackHelper; +import org.sonar.process.logging.PatternLayoutEncoder; import static org.assertj.core.api.Assertions.assertThat; import static org.slf4j.Logger.ROOT_LOGGER_NAME; 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 9d2c9a2b2e3..974efbb4773 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 @@ -22,7 +22,6 @@ package org.sonar.application; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; 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.ConsoleAppender; import ch.qos.logback.core.FileAppender; @@ -32,6 +31,7 @@ import org.sonar.application.process.StreamGobbler; import org.sonar.process.ProcessId; import org.sonar.process.logging.LogLevelConfig; import org.sonar.process.logging.LogbackHelper; +import org.sonar.process.logging.PatternLayoutEncoder; import org.sonar.process.logging.RootLoggerConfig; import static org.slf4j.Logger.ROOT_LOGGER_NAME; diff --git a/server/sonar-main/src/test/java/org/sonar/application/AppLoggingTest.java b/server/sonar-main/src/test/java/org/sonar/application/AppLoggingTest.java index a675a68f58b..c5b185de488 100644 --- a/server/sonar-main/src/test/java/org/sonar/application/AppLoggingTest.java +++ b/server/sonar-main/src/test/java/org/sonar/application/AppLoggingTest.java @@ -22,7 +22,6 @@ package org.sonar.application; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; 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; @@ -44,6 +43,7 @@ import org.sonar.application.config.AppSettings; import org.sonar.application.config.TestAppSettings; import org.sonar.process.logging.LogbackHelper; import org.sonar.process.logging.LogbackJsonLayout; +import org.sonar.process.logging.PatternLayoutEncoder; import static org.assertj.core.api.Assertions.assertThat; import static org.slf4j.Logger.ROOT_LOGGER_NAME; diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/EscapedMessageConverter.java b/server/sonar-process/src/main/java/org/sonar/process/logging/EscapedMessageConverter.java new file mode 100644 index 00000000000..e66f105dde6 --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/EscapedMessageConverter.java @@ -0,0 +1,44 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process.logging; + +import ch.qos.logback.classic.pattern.ClassicConverter; +import ch.qos.logback.classic.spi.ILoggingEvent; +import java.util.regex.Pattern; + +/** + * Escapes log message which contains CR LF sequence + */ +public class EscapedMessageConverter extends ClassicConverter { + + private static final Pattern CR_PATTERN = Pattern.compile("\r"); + private static final Pattern LF_PATTERN = Pattern.compile("\n"); + + public String convert(ILoggingEvent event) { + String formattedMessage = event.getFormattedMessage(); + if (formattedMessage != null) { + String result = CR_PATTERN.matcher(formattedMessage).replaceAll("\\\\r"); + result = LF_PATTERN.matcher(result).replaceAll("\\\\n"); + return result; + } + return null; + } + +} 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 85bb1a40779..588f7e3e1ba 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 @@ -22,7 +22,6 @@ package org.sonar.process.logging; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.classic.jul.LevelChangePropagator; import ch.qos.logback.classic.spi.ILoggingEvent; diff --git a/server/sonar-process/src/main/java/org/sonar/process/logging/PatternLayoutEncoder.java b/server/sonar-process/src/main/java/org/sonar/process/logging/PatternLayoutEncoder.java new file mode 100644 index 00000000000..9cc88bdd6c3 --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/logging/PatternLayoutEncoder.java @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process.logging; + +import ch.qos.logback.classic.PatternLayout; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.pattern.PatternLayoutEncoderBase; +import com.google.common.collect.ImmutableMap; +import java.util.Map; + +public class PatternLayoutEncoder extends PatternLayoutEncoderBase { + + @Override + public void start() { + PatternLayout patternLayout = new PatternLayout(); + patternLayout.getDefaultConverterMap().putAll(getEscapedMessageConverterConfig()); + patternLayout.setContext(context); + patternLayout.setPattern(getPattern()); + patternLayout.setOutputPatternAsHeader(outputPatternAsHeader); + patternLayout.start(); + this.layout = patternLayout; + super.start(); + } + + private static Map getEscapedMessageConverterConfig() { + return ImmutableMap.of( + "m", EscapedMessageConverter.class.getName(), + "msg", EscapedMessageConverter.class.getName(), + "message", EscapedMessageConverter.class.getName()); + } + +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/logging/EscapedMessageConverterTest.java b/server/sonar-process/src/test/java/org/sonar/process/logging/EscapedMessageConverterTest.java new file mode 100644 index 00000000000..7411209b503 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/logging/EscapedMessageConverterTest.java @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process.logging; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class EscapedMessageConverterTest { + + private final EscapedMessageConverter underTest = new EscapedMessageConverter(); + + @Test + public void convert_null_message() { + ILoggingEvent event = createILoggingEvent(null); + assertThat(underTest.convert(event)).isNull(); + } + + @Test + public void convert_simple_message() { + ILoggingEvent event = createILoggingEvent("simple message"); + assertThat(underTest.convert(event)).isEqualTo("simple message"); + } + + @Test + public void convert_message_with_CR() { + ILoggingEvent event = createILoggingEvent("simple\r message\r with\r CR\r"); + assertThat(underTest.convert(event)).isEqualTo("simple\\r message\\r with\\r CR\\r"); + } + + @Test + public void convert_message_with_LF() { + ILoggingEvent event = createILoggingEvent("simple\n message\n with\n LF"); + assertThat(underTest.convert(event)).isEqualTo("simple\\n message\\n with\\n LF"); + } + + @Test + public void convert_message_with_CRLF() { + ILoggingEvent event = createILoggingEvent("simple\n\r\n message\r with\r\n CR LF"); + assertThat(underTest.convert(event)).isEqualTo("simple\\n\\r\\n message\\r with\\r\\n CR LF"); + } + + private static ILoggingEvent createILoggingEvent(String message) { + return new TestILoggingEvent(message); + } + +} 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 6603260c9ad..3fa05bebd51 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 @@ -21,7 +21,6 @@ package org.sonar.process.logging; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.LoggerContextListener; import ch.qos.logback.core.Appender; diff --git a/server/sonar-process/src/test/java/org/sonar/process/logging/PatternLayoutEncoderTest.java b/server/sonar-process/src/test/java/org/sonar/process/logging/PatternLayoutEncoderTest.java new file mode 100644 index 00000000000..55d5edba599 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/logging/PatternLayoutEncoderTest.java @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process.logging; + +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +public class PatternLayoutEncoderTest { + + PatternLayoutEncoder underTest = new PatternLayoutEncoder(); + + @Before + public void before() { + underTest.start(); + } + + @Test + public void start_should_initialize_escaped_message_converter() { + assertThat(underTest.getLayout()) + .isInstanceOf(ch.qos.logback.classic.PatternLayout.class); + + assertThat(((ch.qos.logback.classic.PatternLayout) underTest.getLayout()).getDefaultConverterMap()) + .contains( + entry("m", EscapedMessageConverter.class.getName()), + entry("msg", EscapedMessageConverter.class.getName()), + entry("message", EscapedMessageConverter.class.getName())); + } + +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/logging/TestILoggingEvent.java b/server/sonar-process/src/test/java/org/sonar/process/logging/TestILoggingEvent.java new file mode 100644 index 00000000000..92144303f88 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/logging/TestILoggingEvent.java @@ -0,0 +1,110 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process.logging; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.IThrowableProxy; +import ch.qos.logback.classic.spi.LoggerContextVO; +import java.util.Map; +import org.slf4j.Marker; + +public class TestILoggingEvent implements ILoggingEvent { + private String formattedMessage; + + public TestILoggingEvent(String formattedMessage) { + this.formattedMessage = formattedMessage; + } + + @Override + public String getThreadName() { + return null; + } + + @Override + public Level getLevel() { + return null; + } + + @Override + public String getMessage() { + return null; + } + + @Override + public Object[] getArgumentArray() { + return null; + } + + @Override + public String getFormattedMessage() { + return this.formattedMessage; + } + + @Override + public String getLoggerName() { + return null; + } + + @Override + public LoggerContextVO getLoggerContextVO() { + return null; + } + + @Override + public IThrowableProxy getThrowableProxy() { + return null; + } + + @Override + public StackTraceElement[] getCallerData() { + return new StackTraceElement[0]; + } + + @Override + public boolean hasCallerData() { + return false; + } + + @Override + public Marker getMarker() { + return null; + } + + @Override + public Map getMDCPropertyMap() { + return null; + } + + @Override + public Map getMdc() { + return null; + } + + @Override + public long getTimeStamp() { + return 0; + } + + @Override + public void prepareForDeferredProcessing() { + + } +} 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 c47feaaf1ba..62bc9287bba 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 @@ -22,7 +22,6 @@ 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.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import ch.qos.logback.core.AppenderBase; @@ -48,6 +47,7 @@ import org.junit.rules.TemporaryFolder; import org.sonar.process.Props; import org.sonar.process.logging.LogbackHelper; import org.sonar.process.logging.LogbackJsonLayout; +import org.sonar.process.logging.PatternLayoutEncoder; import static org.assertj.core.api.Assertions.assertThat; import static org.slf4j.Logger.ROOT_LOGGER_NAME; @@ -508,10 +508,10 @@ public class WebServerProcessLoggingTest { LoggerContext context = underTest.configure(props); Logger rootLogger = context.getLogger(ROOT_LOGGER_NAME); - OutputStreamAppender appender = (OutputStreamAppender)rootLogger.getAppender("file_web"); + OutputStreamAppender appender = (OutputStreamAppender) rootLogger.getAppender("file_web"); Encoder encoder = appender.getEncoder(); assertThat(encoder).isInstanceOf(LayoutWrappingEncoder.class); - assertThat(((LayoutWrappingEncoder)encoder).getLayout()).isInstanceOf(LogbackJsonLayout.class); + assertThat(((LayoutWrappingEncoder) encoder).getLayout()).isInstanceOf(LogbackJsonLayout.class); } private void verifyRootLogLevel(LoggerContext ctx, Level expected) { -- 2.39.5