aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-plugin-api
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2015-02-18 12:13:34 +0100
committerSimon Brandhof <simon.brandhof@sonarsource.com>2015-02-19 12:08:25 +0100
commitd5a8ab383c56026165e995d62fbbeb0bed790d53 (patch)
tree81085987cadbaca5d1ed3bba4fe8a62e6fdf5ab0 /sonar-plugin-api
parent6adb553ddc2711cb88632be9bd96b4e91c51082e (diff)
downloadsonarqube-d5a8ab383c56026165e995d62fbbeb0bed790d53.tar.gz
sonarqube-d5a8ab383c56026165e995d62fbbeb0bed790d53.zip
SONAR-6194 SONAR-5009 profiling api + unique property sonar.log.level
Diffstat (limited to 'sonar-plugin-api')
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/TimeProfiler.java25
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/BaseLogger.java95
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLogger.java36
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLoggers.java12
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/DefaultProfiler.java180
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ListInterceptor.java4
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogInterceptor.java13
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogTester.java32
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLogger.java37
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLoggers.java18
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Logger.java29
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LoggerLevel.java10
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Loggers.java6
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/NullProfiler.java96
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Profiler.java80
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/TimeProfilerTest.java2
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggerTest.java29
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggersTest.java13
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/log/DefaultProfilerTest.java183
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogTesterTest.java23
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogbackLoggerTest.java42
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/log/NullProfilerTest.java48
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ProfilerTest.java58
23 files changed, 953 insertions, 118 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/TimeProfiler.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/TimeProfiler.java
index ce86e880cdb..29ffa1c55cf 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/TimeProfiler.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/TimeProfiler.java
@@ -19,44 +19,35 @@
*/
package org.sonar.api.utils;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
+import org.slf4j.LoggerFactory;
/**
* A very simple profiler to log the time elapsed performing some tasks.
* This implementation is not thread-safe.
*
+ * @deprecated since 5.1. Replaced by {@link org.sonar.api.utils.log.Profiler}
* @since 2.0
*/
public class TimeProfiler {
- private Logger logger;
+ private org.slf4j.Logger logger;
private long start = 0;
private String name;
private boolean debug = false;
- public TimeProfiler(Logger logger) {
- this.logger = logger;
- }
-
- /**
- * @deprecated do not use SLF4J but org.sonar.api.utils.log.Logger
- * @since 5.1
- */
- @Deprecated
public TimeProfiler(org.slf4j.Logger logger) {
- this.logger = Loggers.get(logger.getName());
+ this.logger = logger;
}
public TimeProfiler(Class clazz) {
- this.logger = Loggers.get(clazz);
+ this.logger = LoggerFactory.getLogger(clazz);
}
/**
* Use the default Sonar logger
*/
public TimeProfiler() {
- this.logger = Loggers.get(getClass());
+ this.logger = LoggerFactory.getLogger(getClass());
}
public TimeProfiler start(String name) {
@@ -70,12 +61,12 @@ public class TimeProfiler {
return this;
}
- public TimeProfiler setLogger(Logger logger) {
+ public TimeProfiler setLogger(org.slf4j.Logger logger) {
this.logger = logger;
return this;
}
- public Logger getLogger() {
+ public org.slf4j.Logger getLogger() {
return logger;
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/BaseLogger.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/BaseLogger.java
index 7dbec222096..f4c7e3c95f9 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/BaseLogger.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/BaseLogger.java
@@ -23,107 +23,139 @@ import javax.annotation.Nullable;
abstract class BaseLogger implements Logger {
@Override
+ public void trace(String msg) {
+ LogInterceptor.instance().log(msg);
+ doTrace(msg);
+ }
+
+ @Override
+ public void trace(String pattern, @Nullable Object arg) {
+ LogInterceptor.instance().log(pattern, arg);
+ doTrace(pattern, arg);
+ }
+
+ @Override
+ public void trace(String msg, @Nullable Object arg1, @Nullable Object arg2) {
+ LogInterceptor.instance().log(msg, arg1, arg2);
+ doTrace(msg, arg1, arg2);
+ }
+
+ @Override
+ public void trace(String msg, Object... args) {
+ LogInterceptor.instance().log(msg, args);
+ doTrace(msg, args);
+ }
+
+ @Override
public void debug(String msg) {
- LogInterceptor.instance.log(msg);
+ LogInterceptor.instance().log(msg);
doDebug(msg);
}
@Override
public void debug(String pattern, @Nullable Object arg) {
- LogInterceptor.instance.log(pattern, arg);
+ LogInterceptor.instance().log(pattern, arg);
doDebug(pattern, arg);
}
@Override
public void debug(String msg, @Nullable Object arg1, @Nullable Object arg2) {
- LogInterceptor.instance.log(msg, arg1, arg2);
+ LogInterceptor.instance().log(msg, arg1, arg2);
doDebug(msg, arg1, arg2);
}
@Override
public void debug(String msg, Object... args) {
- LogInterceptor.instance.log(msg, args);
+ LogInterceptor.instance().log(msg, args);
doDebug(msg, args);
}
@Override
public void info(String msg) {
- LogInterceptor.instance.log(msg);
+ LogInterceptor.instance().log(msg);
doInfo(msg);
}
@Override
public void info(String msg, @Nullable Object arg) {
- LogInterceptor.instance.log(msg, arg);
+ LogInterceptor.instance().log(msg, arg);
doInfo(msg, arg);
}
@Override
public void info(String msg, @Nullable Object arg1, @Nullable Object arg2) {
- LogInterceptor.instance.log(msg, arg1, arg2);
+ LogInterceptor.instance().log(msg, arg1, arg2);
doInfo(msg, arg1, arg2);
}
@Override
public void info(String msg, Object... args) {
- LogInterceptor.instance.log(msg, args);
+ LogInterceptor.instance().log(msg, args);
doInfo(msg, args);
}
@Override
public void warn(String msg) {
- LogInterceptor.instance.log(msg);
+ LogInterceptor.instance().log(msg);
doWarn(msg);
}
@Override
public void warn(String msg, @Nullable Object arg) {
- LogInterceptor.instance.log(msg, arg);
+ LogInterceptor.instance().log(msg, arg);
doWarn(msg, arg);
}
@Override
public void warn(String msg, @Nullable Object arg1, @Nullable Object arg2) {
- LogInterceptor.instance.log(msg, arg1, arg2);
+ LogInterceptor.instance().log(msg, arg1, arg2);
doWarn(msg, arg1, arg2);
}
@Override
public void warn(String msg, Object... args) {
- LogInterceptor.instance.log(msg, args);
+ LogInterceptor.instance().log(msg, args);
doWarn(msg, args);
}
@Override
public void error(String msg) {
- LogInterceptor.instance.log(msg);
+ LogInterceptor.instance().log(msg);
doError(msg);
}
@Override
public void error(String msg, @Nullable Object arg) {
- LogInterceptor.instance.log(msg, arg);
+ LogInterceptor.instance().log(msg, arg);
doError(msg, arg);
}
@Override
public void error(String msg, @Nullable Object arg1, @Nullable Object arg2) {
- LogInterceptor.instance.log(msg, arg1, arg2);
+ LogInterceptor.instance().log(msg, arg1, arg2);
doError(msg, arg1, arg2);
}
@Override
public void error(String msg, Object... args) {
- LogInterceptor.instance.log(msg, args);
+ LogInterceptor.instance().log(msg, args);
doError(msg, args);
}
@Override
public void error(String msg, Throwable thrown) {
- LogInterceptor.instance.log(msg, thrown);
+ LogInterceptor.instance().log(msg, thrown);
doError(msg, thrown);
}
+ abstract void doTrace(String msg);
+
+ abstract void doTrace(String msg, @Nullable Object arg);
+
+ abstract void doTrace(String msg, @Nullable Object arg1, @Nullable Object arg2);
+
+ abstract void doTrace(String msg, Object... args);
+
abstract void doDebug(String msg);
abstract void doDebug(String msg, @Nullable Object arg);
@@ -132,9 +164,6 @@ abstract class BaseLogger implements Logger {
abstract void doDebug(String msg, Object... args);
- /**
- * Logs an INFO level message.
- */
abstract void doInfo(String msg);
abstract void doInfo(String msg, @Nullable Object arg);
@@ -143,9 +172,6 @@ abstract class BaseLogger implements Logger {
abstract void doInfo(String msg, Object... args);
- /**
- * Logs a WARN level message.
- */
abstract void doWarn(String msg);
abstract void doWarn(String msg, @Nullable Object arg);
@@ -154,9 +180,6 @@ abstract class BaseLogger implements Logger {
abstract void doWarn(String msg, Object... args);
- /**
- * Logs an ERROR level message.
- */
abstract void doError(String msg);
abstract void doError(String msg, @Nullable Object arg);
@@ -166,4 +189,24 @@ abstract class BaseLogger implements Logger {
abstract void doError(String msg, Object... args);
abstract void doError(String msg, Throwable thrown);
+
+ void log(LoggerLevel level, String msg) {
+ switch (level) {
+ case TRACE:
+ trace(msg);
+ break;
+ case DEBUG:
+ debug(msg);
+ break;
+ case INFO:
+ info(msg);
+ break;
+ case WARN:
+ warn(msg);
+ break;
+ case ERROR:
+ error(msg);
+ break;
+ }
+ }
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLogger.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLogger.java
index 1dee60c11d6..35757ebb256 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLogger.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLogger.java
@@ -44,8 +44,42 @@ class ConsoleLogger extends BaseLogger {
}
@Override
+ public boolean isTraceEnabled() {
+ return Loggers.getFactory().getLevel() == LoggerLevel.TRACE;
+ }
+
+ @Override
+ protected void doTrace(String msg) {
+ if (isTraceEnabled()) {
+ log("TRACE", msg);
+ }
+ }
+
+ @Override
+ protected void doTrace(String pattern, @Nullable Object arg) {
+ if (isTraceEnabled()) {
+ trace(format(pattern, arg));
+ }
+ }
+
+ @Override
+ protected void doTrace(String pattern, @Nullable Object arg1, @Nullable Object arg2) {
+ if (isTraceEnabled()) {
+ trace(format(pattern, arg1, arg2));
+ }
+ }
+
+ @Override
+ protected void doTrace(String pattern, Object... args) {
+ if (isTraceEnabled()) {
+ trace(format(pattern, args));
+ }
+ }
+
+ @Override
public boolean isDebugEnabled() {
- return Loggers.getFactory().isDebugEnabled();
+ LoggerLevel level = Loggers.getFactory().getLevel();
+ return level == LoggerLevel.TRACE || level == LoggerLevel.DEBUG;
}
@Override
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLoggers.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLoggers.java
index 726321e2956..e920bcd49b6 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLoggers.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ConsoleLoggers.java
@@ -21,7 +21,7 @@ package org.sonar.api.utils.log;
class ConsoleLoggers extends Loggers {
- private boolean debugEnabled = false;
+ private LoggerLevel level = LoggerLevel.INFO;
@Override
protected Logger newInstance(String name) {
@@ -29,12 +29,14 @@ class ConsoleLoggers extends Loggers {
}
@Override
- protected boolean isDebugEnabled() {
- return debugEnabled;
+ protected LoggerLevel getLevel() {
+ return level;
}
@Override
- protected void enableDebug(boolean b) {
- this.debugEnabled = b;
+ protected void setLevel(LoggerLevel level) {
+ this.level = level;
}
+
+
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/DefaultProfiler.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/DefaultProfiler.java
new file mode 100644
index 00000000000..e72bf231c8b
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/DefaultProfiler.java
@@ -0,0 +1,180 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.api.utils.log;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.utils.System2;
+
+import javax.annotation.Nullable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+class DefaultProfiler extends Profiler {
+
+ private static final String CONTEXT_SEPARATOR = " | ";
+
+ private final LinkedHashMap<String, Object> context = new LinkedHashMap<>();
+ private final BaseLogger logger;
+
+ private long startTime = 0L;
+ private String startMessage = null;
+ private LoggerLevel startLevel = null;
+
+ public DefaultProfiler(BaseLogger logger) {
+ this.logger = logger;
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return logger.isDebugEnabled();
+ }
+
+ @Override
+ public boolean isTraceEnabled() {
+ return logger.isTraceEnabled();
+ }
+
+ @Override
+ public Profiler start() {
+ this.startTime = System2.INSTANCE.now();
+ this.startMessage = null;
+ this.startLevel = null;
+ return this;
+ }
+
+ @Override
+ public Profiler startTrace(String message) {
+ this.startTime = System2.INSTANCE.now();
+ this.startMessage = message;
+ this.startLevel = LoggerLevel.TRACE;
+ StringBuilder sb = new StringBuilder();
+ sb.append(message);
+ appendContext(sb);
+ logger.trace(sb.toString());
+ return this;
+ }
+
+ @Override
+ public Profiler startDebug(String message) {
+ this.startTime = System2.INSTANCE.now();
+ this.startMessage = message;
+ this.startLevel = LoggerLevel.DEBUG;
+ StringBuilder sb = new StringBuilder();
+ sb.append(message);
+ appendContext(sb);
+ logger.debug(sb.toString());
+ return this;
+ }
+
+ @Override
+ public Profiler startInfo(String message) {
+ this.startTime = System2.INSTANCE.now();
+ this.startMessage = message;
+ this.startLevel = LoggerLevel.INFO;
+ StringBuilder sb = new StringBuilder();
+ sb.append(message);
+ appendContext(sb);
+ logger.info(sb.toString());
+ return this;
+ }
+
+
+ @Override
+ public Profiler stopTrace() {
+ return doStopWithoutMessage(LoggerLevel.TRACE);
+ }
+
+ @Override
+ public Profiler stopDebug() {
+ return doStopWithoutMessage(LoggerLevel.DEBUG);
+ }
+
+ @Override
+ public Profiler stopInfo() {
+ return doStopWithoutMessage(LoggerLevel.INFO);
+ }
+
+ private Profiler doStopWithoutMessage(LoggerLevel level) {
+ if (startMessage == null) {
+ throw new IllegalStateException("Profiler#stopXXX() can't be called without any message defined in start methods");
+ }
+ doStop(level, startMessage, " (done)");
+ return this;
+ }
+
+ @Override
+ public Profiler stopTrace(String message) {
+ doStop(LoggerLevel.TRACE, message, "");
+ return this;
+ }
+
+ @Override
+ public Profiler stopDebug(String message) {
+ doStop(LoggerLevel.DEBUG, message, "");
+ return this;
+ }
+
+ @Override
+ public Profiler stopInfo(String message) {
+ doStop(LoggerLevel.INFO, message, "");
+ return this;
+ }
+
+ private void doStop(LoggerLevel level, @Nullable String message, String messageSuffix) {
+ if (startTime == 0L) {
+ throw new IllegalStateException("Profiler must be started before being stopped");
+ }
+ long duration = System2.INSTANCE.now() - startTime;
+ StringBuilder sb = new StringBuilder();
+ if (!StringUtils.isEmpty(message)) {
+ sb.append(message);
+ sb.append(messageSuffix);
+ sb.append(CONTEXT_SEPARATOR);
+ }
+ sb.append("time=").append(duration).append("ms");
+ appendContext(sb);
+ logger.log(level, sb.toString());
+ startTime = 0L;
+ startMessage = null;
+ startLevel = null;
+ context.clear();
+ }
+
+ private void appendContext(StringBuilder sb) {
+ for (Map.Entry<String, Object> entry : context.entrySet()) {
+ if (sb.length() > 0) {
+ sb.append(CONTEXT_SEPARATOR);
+ }
+ sb.append(entry.getKey()).append("=").append(Objects.toString(entry.getValue()));
+ }
+ }
+
+ @Override
+ public Profiler addContext(String key, @Nullable Object value) {
+ if (value == null) {
+ context.remove(key);
+ } else {
+ context.put(key, value);
+ }
+ return this;
+ }
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ListInterceptor.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ListInterceptor.java
index 94aa6dad39a..58c86d8387a 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ListInterceptor.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/ListInterceptor.java
@@ -54,4 +54,8 @@ class ListInterceptor extends LogInterceptor {
public List<String> logs() {
return logs;
}
+
+ public void clear() {
+ logs.clear();
+ }
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogInterceptor.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogInterceptor.java
index aab01e6a359..ff844379d9e 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogInterceptor.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogInterceptor.java
@@ -19,9 +19,11 @@
*/
package org.sonar.api.utils.log;
+import com.google.common.base.Preconditions;
+
abstract class LogInterceptor {
- static LogInterceptor instance = NullInterceptor.NULL_INSTANCE;
+ private static LogInterceptor instance = NullInterceptor.NULL_INSTANCE;
abstract void log(String msg);
@@ -32,4 +34,13 @@ abstract class LogInterceptor {
abstract void log(String msg, Object... args);
abstract void log(String msg, Throwable thrown);
+
+ static LogInterceptor instance() {
+ return instance;
+ }
+
+ static void setInstance(LogInterceptor li) {
+ Preconditions.checkArgument(li != null);
+ instance = li;
+ }
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogTester.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogTester.java
index 98ddc36cbf5..ac63133bfc2 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogTester.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogTester.java
@@ -27,7 +27,7 @@ import java.util.List;
* <b>For tests only</b>
* <p/>
* This JUnit rule allows to configure and access logs in tests. By default
- * debug logs are enabled.
+ * trace level is enabled.
* <p/>
* Warning - not compatible with parallel execution of tests in the same JVM fork.
* <p/>
@@ -58,36 +58,33 @@ import java.util.List;
*/
public class LogTester extends ExternalResource {
- private boolean initialDebugMode;
+ private LoggerLevel initialLevel;
@Override
protected void before() throws Throwable {
- initialDebugMode = Loggers.getFactory().isDebugEnabled();
+ initialLevel = Loggers.getFactory().getLevel();
// this shared instance breaks compatibility with parallel execution of tests
- LogInterceptor.instance = new ListInterceptor();
- enableDebug(true);
+ LogInterceptor.setInstance(new ListInterceptor());
+ setLevel(LoggerLevel.TRACE);
}
@Override
protected void after() {
- enableDebug(initialDebugMode);
- LogInterceptor.instance = NullInterceptor.NULL_INSTANCE;
+ LogInterceptor.setInstance(NullInterceptor.NULL_INSTANCE);
+ setLevel(initialLevel);
}
- /**
- * @see #enableDebug(boolean)
- */
- public boolean isDebugEnabled() {
- return Loggers.getFactory().isDebugEnabled();
+ protected LoggerLevel getLevel() {
+ return Loggers.getFactory().getLevel();
}
/**
* Enable/disable debug logs. Info, warn and error logs are always enabled.
* By default debug logs are enabled when LogTester is started.
*/
- public LogTester enableDebug(boolean b) {
- Loggers.getFactory().enableDebug(b);
+ public LogTester setLevel(LoggerLevel level) {
+ Loggers.getFactory().setLevel(level);
return this;
}
@@ -95,6 +92,11 @@ public class LogTester extends ExternalResource {
* Logs in chronological order (item at index 0 is the oldest one)
*/
public List<String> logs() {
- return ((ListInterceptor) LogInterceptor.instance).logs();
+ return ((ListInterceptor) LogInterceptor.instance()).logs();
+ }
+
+ public LogTester clear() {
+ ((ListInterceptor) LogInterceptor.instance()).clear();
+ return this;
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLogger.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLogger.java
index 7b42e877ac5..3d4c8aa732c 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLogger.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLogger.java
@@ -36,10 +36,36 @@ class LogbackLogger extends BaseLogger {
}
@Override
+ public boolean isTraceEnabled() {
+ return logback.isTraceEnabled();
+ }
+
+ @Override
+ void doTrace(String msg) {
+ logback.trace(msg);
+ }
+
+ @Override
+ void doTrace(String msg, @Nullable Object arg) {
+ logback.trace(msg, arg);
+ }
+
+ @Override
+ void doTrace(String msg, @Nullable Object arg1, @Nullable Object arg2) {
+ logback.trace(msg, arg1, arg2);
+ }
+
+ @Override
+ void doTrace(String msg, Object... args) {
+ logback.trace(msg, args);
+ }
+
+ @Override
public boolean isDebugEnabled() {
return logback.isDebugEnabled();
}
+
@Override
protected void doDebug(String msg) {
logback.debug(msg);
@@ -128,18 +154,17 @@ class LogbackLogger extends BaseLogger {
@Override
public boolean setLevel(LoggerLevel level) {
switch (level) {
+ case TRACE:
+ logback.setLevel(Level.TRACE);
+ break;
case DEBUG:
logback.setLevel(Level.DEBUG);
break;
case INFO:
logback.setLevel(Level.INFO);
break;
- case WARN:
- logback.setLevel(Level.WARN);
- break;
- case ERROR:
- logback.setLevel(Level.ERROR);
- break;
+ default:
+ throw new IllegalArgumentException("Only TRACE, DEBUG and INFO logging levels are supported. Got: " + level);
}
return true;
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLoggers.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLoggers.java
index 7d8ce45f94e..3c8c8e3d03d 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLoggers.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogbackLoggers.java
@@ -31,17 +31,25 @@ class LogbackLoggers extends Loggers {
@Override
protected Logger newInstance(String name) {
// logback is accessed through SLF4J
- return new LogbackLogger((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(name));
+ return new LogbackLogger((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(name));
}
@Override
- protected boolean isDebugEnabled() {
- return LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME).isDebugEnabled();
+ protected LoggerLevel getLevel() {
+ ch.qos.logback.classic.Logger logback = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
+ switch (logback.getLevel().levelInt) {
+ case Level.TRACE_INT:
+ return LoggerLevel.TRACE;
+ case Level.DEBUG_INT:
+ return LoggerLevel.DEBUG;
+ default:
+ return LoggerLevel.INFO;
+ }
}
@Override
- protected void enableDebug(boolean b) {
+ protected void setLevel(LoggerLevel level) {
ch.qos.logback.classic.Logger logback = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
- logback.setLevel(b ? Level.DEBUG : Level.INFO);
+ new LogbackLogger(logback).setLevel(level);
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Logger.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Logger.java
index d729a4b7f08..27a22668910 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Logger.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Logger.java
@@ -40,14 +40,38 @@ import javax.annotation.Nullable;
*
* <p/>
* INFO, WARN and ERROR levels are always enabled. They can't be disabled by users.
- * DEBUG level can be enabled with properties <code>sonar.log.debug</code> (on server, see sonar.properties)
- * and <code>sonar.verbose</code> (on batch)
+ * DEBUG and TRACE levels are enabled on demand with the property <code>sonar.log.level</code>.
* <p/>
* See {@link org.sonar.api.utils.log.LogTester} for testing facilities.
* @since 5.1
*/
public interface Logger {
+ boolean isTraceEnabled();
+
+ /**
+ * Logs a TRACE message. TRACE messages must
+ * be valuable for diagnosing production problems. They must not be used for development debugging.
+ * They can significantly slow down performances. The standard use-case is logging of
+ * SQL and Elasticsearch requests.
+ */
+ void trace(String msg);
+
+ /**
+ * @see #trace(String)
+ */
+ void trace(String pattern, @Nullable Object arg);
+
+ /**
+ * @see #trace(String)
+ */
+ void trace(String msg, @Nullable Object arg1, @Nullable Object arg2);
+
+ /**
+ * @see #trace(String)
+ */
+ void trace(String msg, Object... args);
+
boolean isDebugEnabled();
/**
@@ -148,4 +172,5 @@ public interface Logger {
* libraries.
*/
boolean setLevel(LoggerLevel level);
+
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LoggerLevel.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LoggerLevel.java
index 5ff6fd27f54..5f8ee88ff5e 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LoggerLevel.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LoggerLevel.java
@@ -20,5 +20,13 @@
package org.sonar.api.utils.log;
public enum LoggerLevel {
- DEBUG, INFO, WARN, ERROR
+ TRACE,
+
+ DEBUG,
+
+ INFO,
+
+ WARN,
+
+ ERROR
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Loggers.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Loggers.java
index 4f2627fc5e9..dc82b8b3f2b 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Loggers.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Loggers.java
@@ -28,7 +28,7 @@ public abstract class Loggers {
static {
try {
- Class.forName("org.slf4j.Logger");
+ Class.forName("ch.qos.logback.classic.Logger");
factory = new LogbackLoggers();
} catch (Throwable e) {
// no slf4j -> testing environment
@@ -50,8 +50,8 @@ public abstract class Loggers {
protected abstract Logger newInstance(String name);
- protected abstract boolean isDebugEnabled();
+ protected abstract LoggerLevel getLevel();
- protected abstract void enableDebug(boolean b);
+ protected abstract void setLevel(LoggerLevel level);
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/NullProfiler.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/NullProfiler.java
new file mode 100644
index 00000000000..65a943e9447
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/NullProfiler.java
@@ -0,0 +1,96 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.api.utils.log;
+
+import javax.annotation.Nullable;
+
+class NullProfiler extends Profiler {
+
+ static final NullProfiler NULL_INSTANCE = new NullProfiler();
+
+ private NullProfiler() {
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isTraceEnabled() {
+ return false;
+ }
+
+ @Override
+ public Profiler start() {
+ return this;
+ }
+
+ @Override
+ public Profiler startTrace(String message) {
+ return this;
+ }
+
+ @Override
+ public Profiler startDebug(String message) {
+ return this;
+ }
+
+ @Override
+ public Profiler startInfo(String message) {
+ return this;
+ }
+
+ @Override
+ public Profiler stopTrace() {
+ return this;
+ }
+
+ @Override
+ public Profiler stopDebug() {
+ return this;
+ }
+
+ @Override
+ public Profiler stopInfo() {
+ return this;
+ }
+
+ @Override
+ public Profiler stopTrace(String message) {
+ return this;
+ }
+
+ @Override
+ public Profiler stopDebug(String message) {
+ return this;
+ }
+
+ @Override
+ public Profiler stopInfo(String message) {
+ return this;
+ }
+
+ @Override
+ public Profiler addContext(String key, @Nullable Object value) {
+ // nothing to do
+ return this;
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Profiler.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Profiler.java
new file mode 100644
index 00000000000..c22d4ed2939
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/log/Profiler.java
@@ -0,0 +1,80 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.api.utils.log;
+
+import javax.annotation.Nullable;
+
+/**
+ *
+ * @since 5.1
+ */
+public abstract class Profiler {
+
+ public static Profiler create(Logger logger) {
+ return new DefaultProfiler((BaseLogger) logger);
+ }
+
+ public static Profiler createIfTrace(Logger logger) {
+ if (logger.isTraceEnabled()) {
+ return create(logger);
+ }
+ return NullProfiler.NULL_INSTANCE;
+ }
+
+ public static Profiler createIfDebug(Logger logger) {
+ if (logger.isDebugEnabled()) {
+ return create(logger);
+ }
+ return NullProfiler.NULL_INSTANCE;
+ }
+
+ public abstract boolean isDebugEnabled();
+
+ public abstract boolean isTraceEnabled();
+
+ public abstract Profiler start();
+
+ public abstract Profiler startTrace(String message);
+
+ public abstract Profiler startDebug(String message);
+
+ public abstract Profiler startInfo(String message);
+
+ /**
+ * Works only if a message have been set in startXXX() methods.
+ */
+ public abstract Profiler stopTrace();
+
+ public abstract Profiler stopDebug();
+
+ public abstract Profiler stopInfo();
+
+ public abstract Profiler stopTrace(String message);
+
+ public abstract Profiler stopDebug(String message);
+
+ public abstract Profiler stopInfo(String message);
+
+ /**
+ * Context information is removed if value is <code>null</code>.
+ */
+ public abstract Profiler addContext(String key, @Nullable Object value);
+
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/TimeProfilerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/TimeProfilerTest.java
index 3d7e3ac6177..713b4677abf 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/TimeProfilerTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/TimeProfilerTest.java
@@ -21,7 +21,7 @@ package org.sonar.api.utils;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.utils.log.Logger;
+import org.slf4j.Logger;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggerTest.java
index 3f59d8d87e5..56d5f242dab 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggerTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggerTest.java
@@ -38,8 +38,9 @@ public class ConsoleLoggerTest {
@Test
public void debug_enabled() throws Exception {
- tester.enableDebug(true);
+ tester.setLevel(LoggerLevel.DEBUG);
assertThat(sut.isDebugEnabled()).isTrue();
+ assertThat(sut.isTraceEnabled()).isFalse();
sut.debug("message");
sut.debug("message {}", "foo");
sut.debug("message {} {}", "foo", "bar");
@@ -49,8 +50,9 @@ public class ConsoleLoggerTest {
@Test
public void debug_disabled() throws Exception {
- tester.enableDebug(false);
+ tester.setLevel(LoggerLevel.INFO);
assertThat(sut.isDebugEnabled()).isFalse();
+ assertThat(sut.isTraceEnabled()).isFalse();
sut.debug("message");
sut.debug("message {}", "foo");
sut.debug("message {} {}", "foo", "bar");
@@ -59,6 +61,29 @@ public class ConsoleLoggerTest {
}
@Test
+ public void trace_enabled() throws Exception {
+ tester.setLevel(LoggerLevel.TRACE);
+ assertThat(sut.isDebugEnabled()).isTrue();
+ assertThat(sut.isTraceEnabled()).isTrue();
+ sut.trace("message");
+ sut.trace("message {}", "foo");
+ sut.trace("message {} {}", "foo", "bar");
+ sut.trace("message {} {} {}", "foo", "bar", "baz");
+ verify(stream, times(4)).println(anyString());
+ }
+
+ @Test
+ public void trace_disabled() throws Exception {
+ tester.setLevel(LoggerLevel.DEBUG);
+ assertThat(sut.isTraceEnabled()).isFalse();
+ sut.trace("message");
+ sut.trace("message {}", "foo");
+ sut.trace("message {} {}", "foo", "bar");
+ sut.trace("message {} {} {}", "foo", "bar", "baz");
+ verifyZeroInteractions(stream);
+ }
+
+ @Test
public void log() throws Exception {
sut.info("message");
sut.info("message {}", "foo");
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggersTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggersTest.java
index 64fa4cc7b96..a77cd98a18a 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggersTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleLoggersTest.java
@@ -34,14 +34,11 @@ public class ConsoleLoggersTest {
}
@Test
- public void debugMode() throws Exception {
- // disabled by default
- assertThat(sut.isDebugEnabled()).isFalse();
+ public void level() throws Exception {
+ // INFO by default
+ assertThat(sut.getLevel()).isEqualTo(LoggerLevel.INFO);
- sut.enableDebug(true);
- assertThat(sut.isDebugEnabled()).isTrue();
-
- sut.enableDebug(false);
- assertThat(sut.isDebugEnabled()).isFalse();
+ sut.setLevel(LoggerLevel.DEBUG);
+ assertThat(sut.getLevel()).isEqualTo(LoggerLevel.DEBUG);
}
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/DefaultProfilerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/DefaultProfilerTest.java
new file mode 100644
index 00000000000..3bf72652db7
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/DefaultProfilerTest.java
@@ -0,0 +1,183 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.api.utils.log;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
+public class DefaultProfilerTest {
+
+ @Rule
+ public LogTester tester = new LogTester();
+
+ Profiler sut = Profiler.create(Loggers.get("DefaultProfilerTest"));
+
+ @Test
+ public void test_levels() throws Exception {
+ // trace by default
+ assertThat(sut.isDebugEnabled()).isTrue();
+ assertThat(sut.isTraceEnabled()).isTrue();
+
+ tester.setLevel(LoggerLevel.DEBUG);
+ assertThat(sut.isDebugEnabled()).isTrue();
+ assertThat(sut.isTraceEnabled()).isFalse();
+
+ tester.setLevel(LoggerLevel.INFO);
+ assertThat(sut.isDebugEnabled()).isFalse();
+ assertThat(sut.isTraceEnabled()).isFalse();
+ }
+
+ @Test
+ public void stop_reuses_start_message() throws Exception {
+ tester.setLevel(LoggerLevel.TRACE);
+
+ // trace
+ sut.startTrace("Register rules");
+ assertThat(tester.logs()).containsOnly("Register rules");
+ sut.stopTrace();
+ assertThat(tester.logs()).hasSize(2);
+ assertThat(tester.logs().get(1)).startsWith("Register rules (done) | time=");
+ tester.clear();
+
+ // debug
+ sut.startDebug("Register rules");
+ assertThat(tester.logs()).containsOnly("Register rules");
+ sut.stopTrace();
+ assertThat(tester.logs()).hasSize(2);
+ assertThat(tester.logs().get(1)).startsWith("Register rules (done) | time=");
+ tester.clear();
+
+ // info
+ sut.startInfo("Register rules");
+ assertThat(tester.logs()).containsOnly("Register rules");
+ sut.stopTrace();
+ assertThat(tester.logs()).hasSize(2);
+ assertThat(tester.logs().get(1)).startsWith("Register rules (done) | time=");
+ }
+
+ @Test
+ public void different_start_and_stop_messages() throws Exception {
+ tester.setLevel(LoggerLevel.TRACE);
+
+ // start TRACE and stop DEBUG
+ sut.startTrace("Register rules");
+ sut.stopDebug("Rules registered");
+ assertThat(tester.logs()).hasSize(2);
+ assertThat(tester.logs().get(0)).contains("Register rules");
+ assertThat(tester.logs().get(1)).startsWith("Rules registered | time=");
+ tester.clear();
+
+ // start DEBUG and stop INFO
+ sut.startDebug("Register rules");
+ sut.stopInfo("Rules registered");
+ assertThat(tester.logs()).hasSize(2);
+ assertThat(tester.logs().get(0)).contains("Register rules");
+ assertThat(tester.logs().get(1)).startsWith("Rules registered | time=");
+ tester.clear();
+
+ // start INFO and stop TRACE
+ sut.startInfo("Register rules");
+ sut.stopTrace("Rules registered");
+ assertThat(tester.logs()).hasSize(2);
+ assertThat(tester.logs().get(0)).contains("Register rules");
+ assertThat(tester.logs().get(1)).startsWith("Rules registered | time=");
+ }
+
+ @Test
+ public void log_on_at_stop() throws Exception {
+ tester.setLevel(LoggerLevel.TRACE);
+
+ // trace
+ sut.start();
+ sut.stopTrace("Rules registered");
+ assertThat(tester.logs()).hasSize(1);
+ assertThat(tester.logs().get(0)).startsWith("Rules registered | time=");
+ tester.clear();
+
+ // debug
+ sut.start();
+ sut.stopDebug("Rules registered");
+ assertThat(tester.logs()).hasSize(1);
+ assertThat(tester.logs().get(0)).startsWith("Rules registered | time=");
+ tester.clear();
+
+ // info
+ sut.start();
+ sut.stopInfo("Rules registered");
+ assertThat(tester.logs()).hasSize(1);
+ assertThat(tester.logs().get(0)).startsWith("Rules registered | time=");
+ }
+
+ @Test
+ public void add_context() throws Exception {
+ Profiler profiler = Profiler.create(Loggers.get("DefaultProfilerTest"));
+ profiler.addContext("a_string", "bar");
+ profiler.addContext("null_value", null);
+ profiler.addContext("an_int", 42);
+ profiler.start();
+ // do not write context as there's no message
+ assertThat(tester.logs()).isEmpty();
+
+ profiler.addContext("after_start", true);
+ profiler.stopInfo("Rules registered");
+ assertThat(tester.logs()).hasSize(1);
+ assertThat(tester.logs().get(0))
+ .startsWith("Rules registered | time=")
+ .endsWith("ms | a_string=bar | an_int=42 | after_start=true");
+ }
+
+ @Test
+ public void empty_message() throws Exception {
+ sut.addContext("foo", "bar");
+ sut.startInfo("");
+ assertThat(tester.logs()).containsOnly("foo=bar");
+
+ sut.addContext("after_start", true);
+ sut.stopInfo("");
+ assertThat(tester.logs()).hasSize(2);
+ assertThat(tester.logs().get(1))
+ .startsWith("time=")
+ .endsWith("ms | foo=bar | after_start=true");
+ }
+
+ @Test
+ public void fail_if_stop_without_message() throws Exception {
+ sut.start();
+ try {
+ sut.stopInfo();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("Profiler#stopXXX() can't be called without any message defined in start methods");
+ }
+ }
+
+ @Test
+ public void fail_if_stop_without_start() throws Exception {
+ try {
+ sut.stopDebug("foo");
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("Profiler must be started before being stopped");
+ }
+ }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogTesterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogTesterTest.java
index 32bb1000bd6..8b10230815b 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogTesterTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogTesterTest.java
@@ -29,22 +29,22 @@ public class LogTesterTest {
@Test
public void debugLevel() throws Throwable {
- boolean initial = sut.isDebugEnabled();
+ LoggerLevel initial = sut.getLevel();
// when LogTester is used, then debug logs are enabled by default
sut.before();
- assertThat(sut.isDebugEnabled()).isTrue();
- assertThat(Loggers.getFactory().isDebugEnabled()).isTrue();
+ assertThat(sut.getLevel()).isEqualTo(LoggerLevel.TRACE);
+ assertThat(Loggers.getFactory().getLevel()).isEqualTo(LoggerLevel.TRACE);
// change
- sut.enableDebug(false);
- assertThat(sut.isDebugEnabled()).isFalse();
- assertThat(Loggers.getFactory().isDebugEnabled()).isFalse();
+ sut.setLevel(LoggerLevel.INFO);
+ assertThat(sut.getLevel()).isEqualTo(LoggerLevel.INFO);
+ assertThat(Loggers.getFactory().getLevel()).isEqualTo(LoggerLevel.INFO);
- // reset to initial level
+ // reset to initial level after execution of test
sut.after();
- assertThat(sut.isDebugEnabled()).isEqualTo(initial);
- assertThat(Loggers.getFactory().isDebugEnabled()).isEqualTo(initial);
+ assertThat(sut.getLevel()).isEqualTo(initial);
+ assertThat(Loggers.getFactory().getLevel()).isEqualTo(initial);
}
@Test
@@ -55,7 +55,10 @@ public class LogTesterTest {
assertThat(sut.logs()).containsExactly("an information", "warning: 42");
+ sut.clear();
+ assertThat(sut.logs()).isEmpty();
+
sut.after();
- assertThat(LogInterceptor.instance).isSameAs(NullInterceptor.NULL_INSTANCE);
+ assertThat(LogInterceptor.instance()).isSameAs(NullInterceptor.NULL_INSTANCE);
}
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogbackLoggerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogbackLoggerTest.java
index 7bb3ff87068..f17cb9f799f 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogbackLoggerTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogbackLoggerTest.java
@@ -25,6 +25,7 @@ import org.junit.Test;
import org.slf4j.LoggerFactory;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
public class LogbackLoggerTest {
@@ -34,17 +35,13 @@ public class LogbackLoggerTest {
public LogTester tester = new LogTester();
@Test
- public void debug_enabling() throws Exception {
- tester.enableDebug(true);
- assertThat(sut.isDebugEnabled()).isTrue();
-
- tester.enableDebug(false);
- assertThat(sut.isDebugEnabled()).isFalse();
- }
-
- @Test
public void log() throws Exception {
// no assertions. Simply verify that calls do not fail.
+ sut.trace("message");
+ sut.trace("message {}", "foo");
+ sut.trace("message {} {}", "foo", "bar");
+ sut.trace("message {} {} {}", "foo", "bar", "baz");
+
sut.debug("message");
sut.debug("message {}", "foo");
sut.debug("message {} {}", "foo", "bar");
@@ -69,17 +66,32 @@ public class LogbackLoggerTest {
@Test
public void change_level() throws Exception {
- assertThat(sut.setLevel(LoggerLevel.ERROR)).isTrue();
- assertThat(sut.logbackLogger().getLevel()).isEqualTo(Level.ERROR);
-
- assertThat(sut.setLevel(LoggerLevel.WARN)).isTrue();
- assertThat(sut.logbackLogger().getLevel()).isEqualTo(Level.WARN);
-
assertThat(sut.setLevel(LoggerLevel.INFO)).isTrue();
assertThat(sut.logbackLogger().getLevel()).isEqualTo(Level.INFO);
+ assertThat(sut.isDebugEnabled()).isFalse();
+ assertThat(sut.isTraceEnabled()).isFalse();
assertThat(sut.setLevel(LoggerLevel.DEBUG)).isTrue();
+ assertThat(sut.isDebugEnabled()).isTrue();
+ assertThat(sut.isTraceEnabled()).isFalse();
assertThat(sut.logbackLogger().getLevel()).isEqualTo(Level.DEBUG);
+
+ assertThat(sut.setLevel(LoggerLevel.TRACE)).isTrue();
assertThat(sut.isDebugEnabled()).isTrue();
+ assertThat(sut.isTraceEnabled()).isTrue();
+ assertThat(sut.logbackLogger().getLevel()).isEqualTo(Level.TRACE);
+ }
+
+ @Test
+ public void info_level_can_not_be_disabled() throws Exception {
+ try {
+ sut.setLevel(LoggerLevel.ERROR);
+ fail();
+
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Only TRACE, DEBUG and INFO logging levels are supported. Got: ERROR");
+ }
+
+
}
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/NullProfilerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/NullProfilerTest.java
new file mode 100644
index 00000000000..a094ebb368e
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/NullProfilerTest.java
@@ -0,0 +1,48 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.api.utils.log;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class NullProfilerTest {
+
+ NullProfiler sut = NullProfiler.NULL_INSTANCE;
+
+ @Test
+ public void do_not_fail() throws Exception {
+ assertThat(sut.start()).isSameAs(sut);
+ assertThat(sut.startTrace("")).isSameAs(sut);
+ assertThat(sut.startDebug("")).isSameAs(sut);
+ assertThat(sut.startInfo("")).isSameAs(sut);
+
+ assertThat(sut.stopTrace()).isSameAs(sut);
+ assertThat(sut.stopTrace("")).isSameAs(sut);
+ assertThat(sut.stopDebug("")).isSameAs(sut);
+ assertThat(sut.stopDebug()).isSameAs(sut);
+ assertThat(sut.stopInfo()).isSameAs(sut);
+ assertThat(sut.stopInfo("")).isSameAs(sut);
+
+ assertThat(sut.isDebugEnabled()).isFalse();
+ assertThat(sut.isTraceEnabled()).isFalse();
+ assertThat(sut.addContext("foo", "bar")).isSameAs(sut);
+ }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ProfilerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ProfilerTest.java
new file mode 100644
index 00000000000..6a9e0b9c36d
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ProfilerTest.java
@@ -0,0 +1,58 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.api.utils.log;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProfilerTest {
+ @Rule
+ public LogTester tester = new LogTester();
+
+ @Test
+ public void create() throws Exception {
+ Profiler profiler = Profiler.create(Loggers.get("foo"));
+ assertThat(profiler).isInstanceOf(DefaultProfiler.class);
+ }
+
+ @Test
+ public void create_null_profiler_if_trace_level_is_disabled() throws Exception {
+ tester.setLevel(LoggerLevel.TRACE);
+ Profiler profiler = Profiler.createIfTrace(Loggers.get("foo"));
+ assertThat(profiler).isInstanceOf(DefaultProfiler.class);
+
+ tester.setLevel(LoggerLevel.DEBUG);
+ profiler = Profiler.createIfTrace(Loggers.get("foo"));
+ assertThat(profiler).isInstanceOf(NullProfiler.class);
+ }
+
+ @Test
+ public void create_null_profiler_if_debug_level_is_disabled() throws Exception {
+ tester.setLevel(LoggerLevel.TRACE);
+ Profiler profiler = Profiler.createIfDebug(Loggers.get("foo"));
+ assertThat(profiler).isInstanceOf(DefaultProfiler.class);
+
+ tester.setLevel(LoggerLevel.INFO);
+ profiler = Profiler.createIfDebug(Loggers.get("foo"));
+ assertThat(profiler).isInstanceOf(NullProfiler.class);
+ }
+}