+++ /dev/null
-/*
- * 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.microbenchmark;
-
-import org.apache.commons.lang.StringUtils;
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Fork;
-import org.openjdk.jmh.annotations.Measurement;
-import org.openjdk.jmh.annotations.Mode;
-import org.openjdk.jmh.annotations.OutputTimeUnit;
-import org.openjdk.jmh.annotations.Scope;
-import org.openjdk.jmh.annotations.State;
-import org.openjdk.jmh.annotations.Warmup;
-import org.openjdk.jmh.runner.Runner;
-import org.openjdk.jmh.runner.RunnerException;
-import org.openjdk.jmh.runner.options.Options;
-import org.openjdk.jmh.runner.options.OptionsBuilder;
-import org.slf4j.Logger;
-
-import java.util.Date;
-import java.util.concurrent.TimeUnit;
-
-@OutputTimeUnit(TimeUnit.MILLISECONDS)
-@State(Scope.Thread)
-@Fork(1)
-@Warmup(iterations = 3)
-@Measurement(iterations = 3)
-@BenchmarkMode(Mode.Throughput)
-public class LoggingBenchmark {
-
- private Logger logger1 = org.slf4j.LoggerFactory.getLogger("microbenchmark1");
- private Logger logger2 = org.slf4j.LoggerFactory.getLogger("microbenchmark2");
-
- @Benchmark
- public void logback_converters() throws Exception {
- logger1.warn("many arguments {} {} {} {} {} {}", "foo", 7, 4.5, 1234567890L, true, new Date());
- }
-
- @Benchmark
- public void string_converters() throws Exception {
- logger2.warn(String.format("many arguments %s %d %f %d %b %tc", "foo", 7, 4.5, 1234567890L, true, new Date()));
- }
-
- @Benchmark
- public void logback_no_args() throws Exception {
- logger1.warn("no args");
- StringUtils.replaceOnce()
- }
-
-
- /**
- * You can this benchmark with maven command-line (see run.sh) or by executing this method
- * in IDE
- */
- public static void main(String[] args) throws RunnerException {
- Options opt = new OptionsBuilder()
- .include(LoggingBenchmark.class.getSimpleName())
- .build();
- new Runner(opt).run();
- }
-}
FixedWindowRollingPolicy rollingPolicy = new FixedWindowRollingPolicy();
rollingPolicy.setContext(context);
rollingPolicy.setFileNamePattern(StringUtils.replace(filePath, filenamePrefix + ".log", filenamePrefix + ".%i.log"));
- rollingPolicy.setMaxIndex(1);
- rollingPolicy.setMaxIndex(maxFiles);
+ rollingPolicy.setMinIndex(1);
rollingPolicy.setMaxIndex(maxFiles);
rollingPolicy.setParent(appender);
rollingPolicy.start();
#--------------------------------------------------------------------------------------------------
# LOGGING
-# Level of information displayed in the logs: NONE (default), BASIC (functional information)
-# and FULL (functional and technical details)
-#sonar.log.profilingLevel=NONE
-
+# Enable debug logs in file sonar.log.
#sonar.log.debug=false
# Path to log files. Can be absolute or relative to installation directory.
# - disabled if value is "none". That needs logs to be managed by an external system like logrotate.
#sonar.log.rollingPolicy=time:yyyy-MM-dd
-# Maximum number of files to keep if a rolling policy is enabled
+# Maximum number of files to keep if a rolling policy is enabled.
+# - maximum value is 20 on size rolling policy
+# - unlimited on time rolling policy. Set to zero to disable old file purging.
#sonar.log.maxFiles=7
# Access log is the list of all the HTTP requests received by server. If enabled, it is stored
<artifactId>logback-classic</artifactId>
<optional>true</optional>
</dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <optional>true</optional>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
private final PrintStream stream;
- ConsoleLogger(String unusedName) {
+ ConsoleLogger() {
this.stream = System.out;
}
thrown.printStackTrace();
}
+ @Override
+ public boolean setLevel(LoggerLevel level) {
+ return false;
+ }
+
private void log(String level, String msg) {
this.stream.println(String.format("%s %s", level, msg));
}
@Override
protected Logger newInstance(String name) {
- return new ConsoleLogger(name);
+ return new ConsoleLogger();
}
@Override
* This JUnit rule allows to configure and access logs in tests. By default
* debug logs are enabled.
* <p/>
- * Warning - not compatible with parallel execution of tests.
+ * Warning - not compatible with parallel execution of tests in the same JVM fork.
* <p/>
* Example:
* <pre>
*/
package org.sonar.api.utils.log;
+import ch.qos.logback.classic.*;
+import ch.qos.logback.classic.Logger;
+
import javax.annotation.Nullable;
/**
- * Note that logback is accessed through SLF4J
+ * Logback is used in production.
*/
class LogbackLogger extends BaseLogger {
- private final transient org.slf4j.Logger slf4j;
+ private final transient ch.qos.logback.classic.Logger logback;
- LogbackLogger(org.slf4j.Logger slf4j) {
- this.slf4j = slf4j;
+ LogbackLogger(ch.qos.logback.classic.Logger logback) {
+ this.logback = logback;
}
@Override
public boolean isDebugEnabled() {
- return slf4j.isDebugEnabled();
+ return logback.isDebugEnabled();
}
@Override
protected void doDebug(String msg) {
- slf4j.debug(msg);
+ logback.debug(msg);
}
@Override
protected void doDebug(String msg, @Nullable Object arg) {
- slf4j.debug(msg, arg);
+ logback.debug(msg, arg);
}
@Override
protected void doDebug(String msg, @Nullable Object arg1, @Nullable Object arg2) {
- slf4j.debug(msg, arg1, arg2);
+ logback.debug(msg, arg1, arg2);
}
@Override
protected void doDebug(String msg, Object... args) {
- slf4j.debug(msg, args);
+ logback.debug(msg, args);
}
@Override
protected void doInfo(String msg) {
- slf4j.info(msg);
+ logback.info(msg);
}
@Override
protected void doInfo(String msg, @Nullable Object arg) {
- slf4j.info(msg, arg);
+ logback.info(msg, arg);
}
@Override
protected void doInfo(String msg, @Nullable Object arg1, @Nullable Object arg2) {
- slf4j.info(msg, arg1, arg2);
+ logback.info(msg, arg1, arg2);
}
@Override
protected void doInfo(String msg, Object... args) {
- slf4j.info(msg, args);
+ logback.info(msg, args);
}
@Override
protected void doWarn(String msg) {
- slf4j.warn(msg);
+ logback.warn(msg);
}
@Override
protected void doWarn(String msg, @Nullable Object arg) {
- slf4j.warn(msg, arg);
+ logback.warn(msg, arg);
}
@Override
protected void doWarn(String msg, @Nullable Object arg1, @Nullable Object arg2) {
- slf4j.warn(msg, arg1, arg2);
+ logback.warn(msg, arg1, arg2);
}
@Override
protected void doWarn(String msg, Object... args) {
- slf4j.warn(msg, args);
+ logback.warn(msg, args);
}
@Override
protected void doError(String msg) {
- slf4j.error(msg);
+ logback.error(msg);
}
@Override
protected void doError(String msg, @Nullable Object arg) {
- slf4j.error(msg, arg);
+ logback.error(msg, arg);
}
@Override
protected void doError(String msg, @Nullable Object arg1, @Nullable Object arg2) {
- slf4j.error(msg, arg1, arg2);
+ logback.error(msg, arg1, arg2);
}
@Override
protected void doError(String msg, Object... args) {
- slf4j.error(msg, args);
+ logback.error(msg, args);
}
@Override
protected void doError(String msg, Throwable thrown) {
- slf4j.error(msg, thrown);
+ logback.error(msg, thrown);
+ }
+
+ @Override
+ public boolean setLevel(LoggerLevel level) {
+ switch (level) {
+ 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;
+ }
+ return true;
+ }
+
+ Logger logbackLogger() {
+ return logback;
}
}
@Override
protected Logger newInstance(String name) {
- return new LogbackLogger(LoggerFactory.getLogger(name));
+ // logback is accessed through SLF4J
+ return new LogbackLogger((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(name));
}
@Override
/**
* SonarQube plugins are not coupled with external logging libraries like SLF4J or Logback.
- *
+ * <p/>
* Example:
* <pre>
* public class MyClass {
* }
* }
* </pre>
+ * <p/>
+ * Message arguments are defined with <code>{}</code>, but not with {@link java.util.Formatter} syntax.
*
+ * <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)
+ * <p/>
* See {@link org.sonar.api.utils.log.LogTester} for testing facilities.
* @since 5.1
*/
boolean isDebugEnabled();
/**
- * Logs a DEBUG level message. Debug messages must
- * be valuable for production environments and are not for development debugging.
+ * Logs a DEBUG message. Debug messages must
+ * be valuable for diagnosing production problems. They must not be used for development debugging.
*/
void debug(String msg);
+ /**
+ * @see #debug(String)
+ */
void debug(String pattern, @Nullable Object arg);
+ /**
+ * @see #debug(String)
+ */
void debug(String msg, @Nullable Object arg1, @Nullable Object arg2);
+ /**
+ * @see #debug(String)
+ */
void debug(String msg, Object... args);
/**
*/
void info(String msg);
+ /**
+ * @see #info(String)
+ */
void info(String msg, @Nullable Object arg);
+ /**
+ * @see #info(String)
+ */
void info(String msg, @Nullable Object arg1, @Nullable Object arg2);
+ /**
+ * @see #info(String)
+ */
void info(String msg, Object... args);
/**
*/
void warn(String msg);
+ /**
+ * @see #warn(String)
+ */
void warn(String msg, @Nullable Object arg);
+ /**
+ * @see #warn(String)
+ */
void warn(String msg, @Nullable Object arg1, @Nullable Object arg2);
+ /**
+ * @see #warn(String)
+ */
void warn(String msg, Object... args);
/**
*/
void error(String msg);
+ /**
+ * @see #error(String)
+ */
void error(String msg, @Nullable Object arg);
+ /**
+ * @see #error(String)
+ */
void error(String msg, @Nullable Object arg1, @Nullable Object arg2);
+ /**
+ * @see #error(String)
+ */
void error(String msg, Object... args);
/**
- * Logs an ERROR level message.
+ * @see #error(String)
*/
void error(String msg, Throwable thrown);
+
+ /**
+ * Attempt to change logger level. Return true if it succeeded, false if
+ * the underlying logging facility does not allow to change level at
+ * runtime.
+ * <p/>
+ * This method must not be used to enable debug logs in tests. Use
+ * {@link org.sonar.api.utils.log.LogTester#enableDebug(boolean)}.
+ * <p/>
+ * The standard use-case is to customize logging of embedded 3rd-party
+ * libraries.
+ */
+ boolean setLevel(LoggerLevel level);
}
--- /dev/null
+/*
+ * 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;
+
+public enum LoggerLevel {
+ DEBUG, INFO, WARN, ERROR
+}
sut.error("message", new IllegalArgumentException());
verify(stream, times(5)).println(startsWith("ERROR "));
}
+
+ @Test
+ public void level_change_not_implemented_yet() throws Exception {
+ assertThat(sut.setLevel(LoggerLevel.DEBUG)).isFalse();
+ }
}
*/
package org.sonar.api.utils.log;
+import ch.qos.logback.classic.Level;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.LoggerFactory;
public class LogbackLoggerTest {
- LogbackLogger sut = new LogbackLogger(LoggerFactory.getLogger(getClass()));
+ LogbackLogger sut = new LogbackLogger((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(getClass()));
@Rule
public LogTester tester = new LogTester();
sut.error("message {} {}", "foo", "bar");
sut.error("message {} {} {}", "foo", "bar", "baz");
sut.error("message", new IllegalArgumentException(""));
+ }
+
+ @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.setLevel(LoggerLevel.DEBUG)).isTrue();
+ assertThat(sut.logbackLogger().getLevel()).isEqualTo(Level.DEBUG);
+ assertThat(sut.isDebugEnabled()).isTrue();
}
}
public class NullInterceptorTest {
@Test
- public void do_nothing() throws Exception {
+ public void do_not_throws_exception() throws Exception {
// verify that... it does nothing
NullInterceptor.NULL_INSTANCE.log("foo");
NullInterceptor.NULL_INSTANCE.log("foo {}", 42);