diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2024-04-10 16:01:48 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-04-15 20:02:44 +0000 |
commit | 4b060fef8076c324bc0c0cfe4f64804753c91e29 (patch) | |
tree | f02d1dcae8de61b40fbf4b9431c737110c12c1dc /sonar-scanner-engine/src/main/java | |
parent | 60fee355ef174e184b5c3a477a3c81e95302c754 (diff) | |
download | sonarqube-4b060fef8076c324bc0c0cfe4f64804753c91e29.tar.gz sonarqube-4b060fef8076c324bc0c0cfe4f64804753c91e29.zip |
SONAR-22036 Add a main to the scanner engine
Diffstat (limited to 'sonar-scanner-engine/src/main/java')
3 files changed, 213 insertions, 3 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfiguration.java b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfiguration.java index a7606c4c98b..8ff58ff479f 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfiguration.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfiguration.java @@ -74,13 +74,16 @@ public final class LoggingConfiguration { } public LoggingConfiguration setVerbose(Map<String, String> props) { + verbose = isVerboseEnabled(props); + return setVerbose(verbose); + } + + public static boolean isVerboseEnabled(Map<String, String> props) { String logLevel = props.get("sonar.log.level"); String deprecatedProfilingLevel = props.get("sonar.log.profilingLevel"); - verbose = "true".equals(props.get("sonar.verbose")) || + return "true".equals(props.get("sonar.verbose")) || "DEBUG".equals(logLevel) || "TRACE".equals(logLevel) || "BASIC".equals(deprecatedProfilingLevel) || "FULL".equals(deprecatedProfilingLevel); - - return setVerbose(verbose); } public LoggingConfiguration setRootLevel(String level) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerLogbackEncoder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerLogbackEncoder.java new file mode 100644 index 00000000000..bbad390077a --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerLogbackEncoder.java @@ -0,0 +1,82 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.scanner.bootstrap; + +import ch.qos.logback.classic.pattern.ThrowableProxyConverter; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.IThrowableProxy; +import ch.qos.logback.core.CoreConstants; +import ch.qos.logback.core.encoder.EncoderBase; +import org.apache.commons.text.StringEscapeUtils; + +import static ch.qos.logback.core.CoreConstants.COMMA_CHAR; +import static ch.qos.logback.core.CoreConstants.DOUBLE_QUOTE_CHAR; +import static ch.qos.logback.core.CoreConstants.UTF_8_CHARSET; + +public class ScannerLogbackEncoder extends EncoderBase<ILoggingEvent> { + + private static final byte[] EMPTY_BYTES = new byte[0]; + private static final char OPEN_OBJ = '{'; + private static final char CLOSE_OBJ = '}'; + private static final char VALUE_SEPARATOR = COMMA_CHAR; + private static final char QUOTE = DOUBLE_QUOTE_CHAR; + private static final String QUOTE_COL = "\":"; + + private final ThrowableProxyConverter tpc = new ThrowableProxyConverter(); + + @Override + public byte[] headerBytes() { + return EMPTY_BYTES; + } + + @Override + public byte[] encode(ILoggingEvent event) { + StringBuilder sb = new StringBuilder(); + sb.append(OPEN_OBJ); + var level = event.getLevel(); + if (level != null) { + appenderMember(sb, "level", level.levelStr); + sb.append(VALUE_SEPARATOR); + } + + appenderMember(sb, "message", StringEscapeUtils.escapeJson(event.getFormattedMessage())); + + IThrowableProxy tp = event.getThrowableProxy(); + String stackTrace = null; + if (tp != null) { + sb.append(VALUE_SEPARATOR); + stackTrace = tpc.convert(event); + appenderMember(sb, "stacktrace", StringEscapeUtils.escapeJson(stackTrace)); + } + + sb.append(CLOSE_OBJ); + sb.append(CoreConstants.JSON_LINE_SEPARATOR); + return sb.toString().getBytes(UTF_8_CHARSET); + } + + private static void appenderMember(StringBuilder sb, String key, String value) { + sb.append(QUOTE).append(key).append(QUOTE_COL).append(QUOTE).append(value).append(QUOTE); + } + + @Override + public byte[] footerBytes() { + return EMPTY_BYTES; + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerMain.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerMain.java new file mode 100644 index 00000000000..405f586d654 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerMain.java @@ -0,0 +1,125 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.scanner.bootstrap; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.CheckForNull; +import org.jetbrains.annotations.NotNull; +import org.slf4j.LoggerFactory; +import org.sonar.batch.bootstrapper.EnvironmentInformation; +import org.sonar.batch.bootstrapper.LoggingConfiguration; + +import static org.sonar.batch.bootstrapper.LoggingConfiguration.LEVEL_ROOT_DEFAULT; +import static org.sonar.batch.bootstrapper.LoggingConfiguration.LEVEL_ROOT_VERBOSE; + +public class ScannerMain { + + private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ScannerMain.class); + + private static final String SCANNER_APP_KEY = "sonar.scanner.app"; + private static final String SCANNER_APP_VERSION_KEY = "sonar.scanner.appVersion"; + + public static void main(String... args) { + try { + run(System.in); + } catch (Exception e) { + LOG.error("Error during SonarScanner Engine execution", e); + System.exit(1); + } + } + + public static void run(InputStream in) { + LOG.info("Starting SonarScanner Engine..."); + + var properties = parseInputProperties(in); + + configureLogLevel(properties); + + runScannerEngine(properties); + + LOG.info("SonarScanner Engine completed successfully"); + } + + private static @NotNull Map<String, String> parseInputProperties(InputStream in) { + Map<String, String> properties = new HashMap<>(); + var input = parseJsonInput(in); + if (input != null && input.scannerProperties != null) { + input.scannerProperties.forEach(prop -> { + if (prop == null) { + LOG.warn("Ignoring null property"); + } else if (prop.key == null) { + LOG.warn("Ignoring property with null key: '{}'", prop.value); + } else { + if (properties.containsKey(prop.key)) { + LOG.warn("Duplicated properties with key: '{}'", prop.key); + } + properties.put(prop.key, prop.value); + } + }); + } + return properties; + } + + @CheckForNull + private static Input parseJsonInput(InputStream in) { + try (var reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { + return new Gson().fromJson(reader, Input.class); + } catch (Exception e) { + throw new IllegalArgumentException("Failed to parse JSON input", e); + } + } + + private static void runScannerEngine(Map<String, String> properties) { + var scannerAppKey = properties.get(SCANNER_APP_KEY); + var scannerAppVersion = properties.get(SCANNER_APP_VERSION_KEY); + var env = new EnvironmentInformation(scannerAppKey, scannerAppVersion); + SpringGlobalContainer.create(properties, List.of(env)).execute(); + } + + private static void configureLogLevel(Map<String, String> properties) { + var verbose = LoggingConfiguration.isVerboseEnabled(properties); + var rootLogger = (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); + rootLogger.setLevel(Level.toLevel(verbose ? LEVEL_ROOT_VERBOSE : LEVEL_ROOT_DEFAULT)); + } + + private static class Input { + @SerializedName("scannerProperties") + private List<ScannerProperty> scannerProperties; + } + + private static class ScannerProperty { + @SerializedName("key") + private String key; + + @SerializedName("value") + private String value; + } + +} |