diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2015-02-18 12:13:34 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2015-02-19 12:08:25 +0100 |
commit | d5a8ab383c56026165e995d62fbbeb0bed790d53 (patch) | |
tree | 81085987cadbaca5d1ed3bba4fe8a62e6fdf5ab0 /sonar-plugin-api | |
parent | 6adb553ddc2711cb88632be9bd96b4e91c51082e (diff) | |
download | sonarqube-d5a8ab383c56026165e995d62fbbeb0bed790d53.tar.gz sonarqube-d5a8ab383c56026165e995d62fbbeb0bed790d53.zip |
SONAR-6194 SONAR-5009 profiling api + unique property sonar.log.level
Diffstat (limited to 'sonar-plugin-api')
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); + } +} |