aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2016-03-17 17:05:56 +0100
committerJulien HENRY <julien.henry@sonarsource.com>2016-03-18 09:35:05 +0100
commitcfcbe278f7ced12599d898d50f3fe68bfbf95155 (patch)
tree5b4116ad08a8ba87ffc5bf9f159a431b9609b48f /sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper
parent38ce80934961773a9a35ec0401994b3d726597dc (diff)
downloadsonarqube-cfcbe278f7ced12599d898d50f3fe68bfbf95155.tar.gz
sonarqube-cfcbe278f7ced12599d898d50f3fe68bfbf95155.zip
Rename batch into scanner
Diffstat (limited to 'sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper')
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/Batch.java274
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/EnvironmentInformation.java59
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/IssueListener.java167
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java57
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LogOutput.java33
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfiguration.java153
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfigurator.java76
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/package-info.java27
8 files changed, 846 insertions, 0 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/Batch.java b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/Batch.java
new file mode 100644
index 00000000000..d5d3da13087
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/Batch.java
@@ -0,0 +1,274 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.batch.bootstrapper;
+
+import org.sonar.api.utils.MessageException;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.picocontainer.annotations.Nullable;
+import org.sonar.batch.bootstrap.GlobalContainer;
+
+/**
+ * Entry point for sonar-runner 2.1.
+ *
+ * @since 2.14
+ */
+public final class Batch {
+
+ private boolean started = false;
+ private LoggingConfiguration loggingConfig;
+ private List<Object> components;
+ private Map<String, String> bootstrapProperties = Maps.newHashMap();
+ private GlobalContainer bootstrapContainer;
+
+ private Batch(Builder builder) {
+ components = Lists.newArrayList();
+ components.addAll(builder.components);
+ if (builder.environment != null) {
+ components.add(builder.environment);
+ }
+ if (builder.bootstrapProperties != null) {
+ bootstrapProperties.putAll(builder.bootstrapProperties);
+ }
+ if (builder.isEnableLoggingConfiguration()) {
+ loggingConfig = new LoggingConfiguration(builder.environment).setProperties(bootstrapProperties);
+
+ if (builder.logOutput != null) {
+ loggingConfig.setLogOutput(builder.logOutput);
+ }
+ }
+ }
+
+ public LoggingConfiguration getLoggingConfiguration() {
+ return loggingConfig;
+ }
+
+ /**
+ * @deprecated since 4.4 use {@link #start()}, {@link #executeTask(Map)} and then {@link #stop()}
+ */
+ @Deprecated
+ public synchronized Batch execute() {
+ configureLogging();
+ start();
+ boolean threw = true;
+ try {
+ executeTask(bootstrapProperties);
+ threw = false;
+ } finally {
+ doStop(threw);
+ }
+
+ return this;
+ }
+
+ /**
+ * @since 4.4
+ */
+ public synchronized Batch start() {
+ return start(false);
+ }
+
+ public synchronized Batch start(boolean preferCache) {
+ if (started) {
+ throw new IllegalStateException("Batch is already started");
+ }
+
+ configureLogging();
+ try {
+ bootstrapContainer = GlobalContainer.create(bootstrapProperties, components, preferCache);
+ bootstrapContainer.startComponents();
+ } catch (RuntimeException e) {
+ throw handleException(e);
+ }
+ this.started = true;
+
+ return this;
+ }
+
+ /**
+ * @since 4.4
+ */
+ public Batch executeTask(Map<String, String> analysisProperties, Object... components) {
+ checkStarted();
+ configureTaskLogging(analysisProperties);
+ try {
+ bootstrapContainer.executeTask(analysisProperties, components);
+ } catch (RuntimeException e) {
+ throw handleException(e);
+ }
+ return this;
+ }
+
+ /**
+ * @since 5.2
+ */
+ public Batch executeTask(Map<String, String> analysisProperties, IssueListener issueListener) {
+ checkStarted();
+ configureTaskLogging(analysisProperties);
+ try {
+ bootstrapContainer.executeTask(analysisProperties, components, issueListener);
+ } catch (RuntimeException e) {
+ throw handleException(e);
+ }
+ return this;
+ }
+
+ private void checkStarted() {
+ if (!started) {
+ throw new IllegalStateException("Batch is not started. Unable to execute task.");
+ }
+ }
+
+ private RuntimeException handleException(RuntimeException t) {
+ if (loggingConfig.isVerbose()) {
+ return t;
+ }
+
+ for (Throwable y : Throwables.getCausalChain(t)) {
+ if (y instanceof MessageException) {
+ return (MessageException) y;
+ }
+ }
+
+ return t;
+ }
+
+ /**
+ * @since 5.2
+ */
+ public Batch syncProject(String projectKey) {
+ checkStarted();
+ bootstrapContainer.syncProject(projectKey, true);
+ return this;
+ }
+
+ /**
+ * @since 4.4
+ */
+ public synchronized void stop() {
+ doStop(false);
+ }
+
+ private void doStop(boolean swallowException) {
+ checkStarted();
+ configureLogging();
+ try {
+ bootstrapContainer.stopComponents(swallowException);
+ } catch (RuntimeException e) {
+ throw handleException(e);
+ }
+ this.started = false;
+ }
+
+ private void configureLogging() {
+ if (loggingConfig != null) {
+ loggingConfig.setProperties(bootstrapProperties);
+ LoggingConfigurator.apply(loggingConfig);
+ }
+ }
+
+ private void configureTaskLogging(Map<String, String> taskProperties) {
+ if (loggingConfig != null) {
+ loggingConfig.setProperties(taskProperties, bootstrapProperties);
+ LoggingConfigurator.apply(loggingConfig);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static final class Builder {
+ private Map<String, String> bootstrapProperties;
+ private EnvironmentInformation environment;
+ private List<Object> components = Lists.newArrayList();
+ private boolean enableLoggingConfiguration = true;
+ private LogOutput logOutput;
+
+ private Builder() {
+ }
+
+ public Builder setEnvironment(EnvironmentInformation env) {
+ this.environment = env;
+ return this;
+ }
+
+ public Builder setComponents(List<Object> l) {
+ this.components = l;
+ return this;
+ }
+
+ public Builder setLogOutput(@Nullable LogOutput logOutput) {
+ this.logOutput = logOutput;
+ return this;
+ }
+
+ /**
+ * @deprecated since 3.7 use {@link #setBootstrapProperties(Map)}
+ */
+ @Deprecated
+ public Builder setGlobalProperties(Map<String, String> globalProperties) {
+ this.bootstrapProperties = globalProperties;
+ return this;
+ }
+
+ public Builder setBootstrapProperties(Map<String, String> bootstrapProperties) {
+ this.bootstrapProperties = bootstrapProperties;
+ return this;
+ }
+
+ public Builder addComponents(Object... components) {
+ Collections.addAll(this.components, components);
+ return this;
+ }
+
+ public Builder addComponent(Object component) {
+ this.components.add(component);
+ return this;
+ }
+
+ public boolean isEnableLoggingConfiguration() {
+ return enableLoggingConfiguration;
+ }
+
+ /**
+ * Logback is configured by default. It can be disabled, but n this case the batch bootstrapper must provide its
+ * own implementation of SLF4J.
+ */
+ public Builder setEnableLoggingConfiguration(boolean b) {
+ this.enableLoggingConfiguration = b;
+ return this;
+ }
+
+ public Batch build() {
+ if (components == null) {
+ throw new IllegalStateException("Batch components are not set");
+ }
+ return new Batch(this);
+ }
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/EnvironmentInformation.java b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/EnvironmentInformation.java
new file mode 100644
index 00000000000..a04da9df40a
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/EnvironmentInformation.java
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.batch.bootstrapper;
+
+import org.sonar.api.batch.BatchSide;
+
+/**
+ * Describes execution environment.
+ *
+ * @since 2.6
+ */
+@BatchSide
+public class EnvironmentInformation {
+
+ private String key;
+ private String version;
+
+ public EnvironmentInformation(String key, String version) {
+ this.key = key;
+ this.version = version;
+ }
+
+ /**
+ * @return unique key of environment, for example - "maven", "ant"
+ */
+ public String getKey() {
+ return key;
+ }
+
+ /**
+ * @return version of environment, for example Maven can have "2.2.1" or "3.0.2",
+ * but there is no guarantees about format - it's just a string.
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s/%s", key, version);
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/IssueListener.java b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/IssueListener.java
new file mode 100644
index 00000000000..bf3f399142a
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/IssueListener.java
@@ -0,0 +1,167 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.batch.bootstrapper;
+
+public interface IssueListener {
+ void handle(Issue issue);
+
+ class Issue {
+ /** @since 5.3 */
+ private Integer startLine;
+ /** @since 5.3 */
+ private Integer startLineOffset;
+ /** @since 5.3 */
+ private Integer endLine;
+ /** @since 5.3 */
+ private Integer endLineOffset;
+
+ private String key;
+ private String componentKey;
+ private String message;
+ private String ruleKey;
+ private String ruleName;
+ private String status;
+ private String resolution;
+ private boolean isNew;
+ private String assigneeLogin;
+ private String assigneeName;
+ private String severity;
+
+ public String getSeverity() {
+ return severity;
+ }
+
+ public void setSeverity(String severity) {
+ this.severity = severity;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getComponentKey() {
+ return componentKey;
+ }
+
+ public void setComponentKey(String componentKey) {
+ this.componentKey = componentKey;
+ }
+
+ public Integer getStartLine() {
+ return startLine;
+ }
+
+ public void setStartLine(Integer startLine) {
+ this.startLine = startLine;
+ }
+
+ public Integer getStartLineOffset() {
+ return startLineOffset;
+ }
+
+ public void setStartLineOffset(Integer startLineOffset) {
+ this.startLineOffset = startLineOffset;
+ }
+
+ public Integer getEndLine() {
+ return endLine;
+ }
+
+ public void setEndLine(Integer endLine) {
+ this.endLine = endLine;
+ }
+
+ public Integer getEndLineOffset() {
+ return endLineOffset;
+ }
+
+ public void setEndLineOffset(Integer endLineOffset) {
+ this.endLineOffset = endLineOffset;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getRuleKey() {
+ return ruleKey;
+ }
+
+ public void setRuleKey(String ruleKey) {
+ this.ruleKey = ruleKey;
+ }
+
+ public String getRuleName() {
+ return ruleName;
+ }
+
+ public void setRuleName(String ruleName) {
+ this.ruleName = ruleName;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getResolution() {
+ return resolution;
+ }
+
+ public void setResolution(String resolution) {
+ this.resolution = resolution;
+ }
+
+ public boolean isNew() {
+ return isNew;
+ }
+
+ public void setNew(boolean isNew) {
+ this.isNew = isNew;
+ }
+
+ public String getAssigneeLogin() {
+ return assigneeLogin;
+ }
+
+ public void setAssigneeLogin(String assigneeLogin) {
+ this.assigneeLogin = assigneeLogin;
+ }
+
+ public String getAssigneeName() {
+ return assigneeName;
+ }
+
+ public void setAssigneeName(String assigneeName) {
+ this.assigneeName = assigneeName;
+ }
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java
new file mode 100644
index 00000000000..183cd378711
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.batch.bootstrapper;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.UnsynchronizedAppenderBase;
+
+public class LogCallbackAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
+ protected LogOutput target;
+
+ public LogCallbackAppender(LogOutput target) {
+ setTarget(target);
+ }
+
+ public void setTarget(LogOutput target) {
+ this.target = target;
+ }
+
+ @Override
+ protected void append(ILoggingEvent event) {
+ target.log(event.getFormattedMessage(), translate(event.getLevel()));
+ }
+
+ private static LogOutput.Level translate(Level level) {
+ switch (level.toInt()) {
+ case Level.ERROR_INT:
+ return LogOutput.Level.ERROR;
+ case Level.WARN_INT:
+ return LogOutput.Level.WARN;
+ case Level.INFO_INT:
+ return LogOutput.Level.INFO;
+ case Level.TRACE_INT:
+ return LogOutput.Level.TRACE;
+ case Level.DEBUG_INT:
+ default:
+ return LogOutput.Level.DEBUG;
+ }
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LogOutput.java b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LogOutput.java
new file mode 100644
index 00000000000..b69c405d931
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LogOutput.java
@@ -0,0 +1,33 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.batch.bootstrapper;
+
+/**
+ * Allow to redirect batch logs to a custom output. By defaults logs are written to System.out
+ * @since 5.2
+ */
+public interface LogOutput {
+
+ void log(String formattedMessage, Level level);
+
+ enum Level {
+ ERROR, WARN, INFO, DEBUG, TRACE;
+ }
+}
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
new file mode 100644
index 00000000000..41a741bbd08
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfiguration.java
@@ -0,0 +1,153 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.batch.bootstrapper;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * @since 2.14
+ */
+public final class LoggingConfiguration {
+
+ public static final String PROPERTY_ROOT_LOGGER_LEVEL = "ROOT_LOGGER_LEVEL";
+ public static final String PROPERTY_SQL_LOGGER_LEVEL = "SQL_LOGGER_LEVEL";
+
+ public static final String PROPERTY_FORMAT = "FORMAT";
+
+ public static final String LEVEL_ROOT_VERBOSE = "DEBUG";
+ public static final String LEVEL_ROOT_DEFAULT = "INFO";
+
+ @VisibleForTesting
+ static final String FORMAT_DEFAULT = "%d{HH:mm:ss.SSS} %-5level - %msg%n";
+ @VisibleForTesting
+ static final String FORMAT_MAVEN = "[%level] [%d{HH:mm:ss.SSS}] %msg%n";
+
+ private Map<String, String> substitutionVariables = Maps.newHashMap();
+ private LogOutput logOutput = null;
+ private boolean verbose;
+
+ public LoggingConfiguration() {
+ this(null);
+ }
+
+ public LoggingConfiguration(@Nullable EnvironmentInformation environment) {
+ setVerbose(false);
+ if (environment != null && "maven".equalsIgnoreCase(environment.getKey())) {
+ setFormat(FORMAT_MAVEN);
+ } else {
+ setFormat(FORMAT_DEFAULT);
+ }
+ }
+
+ public LoggingConfiguration setProperties(Map<String, String> properties) {
+ setShowSql(properties, null);
+ setVerbose(properties, null);
+ return this;
+ }
+
+ public LoggingConfiguration setProperties(Map<String, String> properties, @Nullable Map<String, String> fallback) {
+ setShowSql(properties, fallback);
+ setVerbose(properties, fallback);
+ return this;
+ }
+
+ public LoggingConfiguration setLogOutput(@Nullable LogOutput listener) {
+ this.logOutput = listener;
+ return this;
+ }
+
+ public LoggingConfiguration setVerbose(boolean verbose) {
+ return setRootLevel(verbose ? LEVEL_ROOT_VERBOSE : LEVEL_ROOT_DEFAULT);
+ }
+
+ public boolean isVerbose() {
+ return verbose;
+ }
+
+ public LoggingConfiguration setVerbose(Map<String, String> props, @Nullable Map<String, String> fallback) {
+ String logLevel = getFallback("sonar.log.level", props, fallback);
+ String deprecatedProfilingLevel = getFallback("sonar.log.profilingLevel", props, fallback);
+ verbose = "true".equals(getFallback("sonar.verbose", props, fallback)) ||
+ "DEBUG".equals(logLevel) || "TRACE".equals(logLevel) ||
+ "BASIC".equals(deprecatedProfilingLevel) || "FULL".equals(deprecatedProfilingLevel);
+
+ return setVerbose(verbose);
+ }
+
+ @CheckForNull
+ private static String getFallback(String key, Map<String, String> properties, @Nullable Map<String, String> fallback) {
+ if (properties.containsKey(key)) {
+ return properties.get(key);
+ }
+
+ if (fallback != null) {
+ return fallback.get(key);
+ }
+
+ return null;
+ }
+
+ public LoggingConfiguration setRootLevel(String level) {
+ return addSubstitutionVariable(PROPERTY_ROOT_LOGGER_LEVEL, level);
+ }
+
+ public LoggingConfiguration setShowSql(boolean showSql) {
+ return addSubstitutionVariable(PROPERTY_SQL_LOGGER_LEVEL, showSql ? "TRACE" : "WARN");
+ }
+
+ public LoggingConfiguration setShowSql(Map<String, String> properties, @Nullable Map<String, String> fallback) {
+ String logLevel = getFallback("sonar.log.level", properties, fallback);
+ String deprecatedProfilingLevel = getFallback("sonar.log.profilingLevel", properties, fallback);
+ boolean sql = "TRACE".equals(logLevel) || "FULL".equals(deprecatedProfilingLevel);
+
+ return setShowSql(sql);
+ }
+
+ @VisibleForTesting
+ LoggingConfiguration setFormat(String format) {
+ return addSubstitutionVariable(PROPERTY_FORMAT, StringUtils.defaultIfBlank(format, FORMAT_DEFAULT));
+ }
+
+ public LoggingConfiguration addSubstitutionVariable(String key, String value) {
+ substitutionVariables.put(key, value);
+ return this;
+ }
+
+ @VisibleForTesting
+ String getSubstitutionVariable(String key) {
+ return substitutionVariables.get(key);
+ }
+
+ Map<String, String> getSubstitutionVariables() {
+ return substitutionVariables;
+ }
+
+ LogOutput getLogOutput() {
+ return logOutput;
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfigurator.java b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfigurator.java
new file mode 100644
index 00000000000..f7f45b1c6fe
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/LoggingConfigurator.java
@@ -0,0 +1,76 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.batch.bootstrapper;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import java.io.File;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.LoggerFactory;
+import org.sonar.core.config.Logback;
+
+public class LoggingConfigurator {
+ private static final String CUSTOM_APPENDER_NAME = "custom_stream";
+
+ private LoggingConfigurator() {
+ }
+
+ public static void apply(LoggingConfiguration conf, File logbackFile) {
+ Logback.configure(logbackFile, conf.getSubstitutionVariables());
+
+ if (conf.getLogOutput() != null) {
+ setCustomRootAppender(conf);
+ }
+ }
+
+ public static void apply(LoggingConfiguration conf) {
+ apply(conf, "/org/sonar/batch/bootstrapper/logback.xml");
+ }
+
+ public static void apply(LoggingConfiguration conf, String classloaderPath) {
+ Logback.configure(classloaderPath, conf.getSubstitutionVariables());
+
+ // if not set, keep default behavior (configured to stdout through the file in classpath)
+ if (conf.getLogOutput() != null) {
+ setCustomRootAppender(conf);
+ }
+ }
+
+ private static void setCustomRootAppender(LoggingConfiguration conf) {
+ Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ String level = StringUtils.defaultIfBlank(conf.getSubstitutionVariables().get(LoggingConfiguration.PROPERTY_ROOT_LOGGER_LEVEL), LoggingConfiguration.LEVEL_ROOT_DEFAULT);
+
+ if (logger.getAppender(CUSTOM_APPENDER_NAME) == null) {
+ logger.detachAndStopAllAppenders();
+ logger.addAppender(createAppender(conf.getLogOutput()));
+ }
+ logger.setLevel(Level.toLevel(level));
+ }
+
+ private static Appender<ILoggingEvent> createAppender(LogOutput target) {
+ LogCallbackAppender appender = new LogCallbackAppender(target);
+ appender.setName(CUSTOM_APPENDER_NAME);
+ appender.start();
+
+ return appender;
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/package-info.java b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/package-info.java
new file mode 100644
index 00000000000..645b8d7dfe2
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.
+ */
+/**
+ * This package is a part of bootstrap process, so we should take care about backward compatibility.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.batch.bootstrapper;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+