[core] Use slf4j-api and slf4j-simple

Support "--debug" flag for slf4j-simple
This commit is contained in:
Andreas Dangel
2022-01-27 17:27:32 +01:00
parent 488f8c716f
commit e1d66e2f42
6 changed files with 106 additions and 48 deletions

View File

@ -75,6 +75,10 @@
<scope>provided</scope> <!-- only needed for generating the parser via ant --> <scope>provided</scope> <!-- only needed for generating the parser via ant -->
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.antlr</groupId> <groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId> <artifactId>antlr4-runtime</artifactId>
@ -114,6 +118,11 @@
<artifactId>pcollections</artifactId> <artifactId>pcollections</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>com.github.tomakehurst</groupId> <groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId> <artifactId>wiremock</artifactId>

View File

@ -21,9 +21,10 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level; import org.slf4j.Logger;
import java.util.logging.Logger; import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import net.sourceforge.pmd.Report.GlobalReportBuilderListener; import net.sourceforge.pmd.Report.GlobalReportBuilderListener;
import net.sourceforge.pmd.benchmark.TextTimingReportRenderer; import net.sourceforge.pmd.benchmark.TextTimingReportRenderer;
@ -35,6 +36,7 @@ import net.sourceforge.pmd.benchmark.TimingReportRenderer;
import net.sourceforge.pmd.cache.NoopAnalysisCache; import net.sourceforge.pmd.cache.NoopAnalysisCache;
import net.sourceforge.pmd.cli.PMDCommandLineInterface; import net.sourceforge.pmd.cli.PMDCommandLineInterface;
import net.sourceforge.pmd.cli.PmdParametersParseResult; import net.sourceforge.pmd.cli.PmdParametersParseResult;
import net.sourceforge.pmd.internal.Slf4jSimpleConfiguration;
import net.sourceforge.pmd.internal.util.AssertionUtil; import net.sourceforge.pmd.internal.util.AssertionUtil;
import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageFilenameFilter; import net.sourceforge.pmd.lang.LanguageFilenameFilter;
@ -52,7 +54,6 @@ import net.sourceforge.pmd.util.database.DBURI;
import net.sourceforge.pmd.util.database.SourceObject; import net.sourceforge.pmd.util.database.SourceObject;
import net.sourceforge.pmd.util.datasource.DataSource; import net.sourceforge.pmd.util.datasource.DataSource;
import net.sourceforge.pmd.util.datasource.ReaderDataSource; import net.sourceforge.pmd.util.datasource.ReaderDataSource;
import net.sourceforge.pmd.util.log.ScopedLogHandlersManager;
/** /**
* This is the main class for interacting with PMD. The primary flow of all Rule * This is the main class for interacting with PMD. The primary flow of all Rule
@ -62,7 +63,8 @@ import net.sourceforge.pmd.util.log.ScopedLogHandlersManager;
*/ */
public final class PMD { public final class PMD {
private static final Logger LOG = Logger.getLogger(PMD.class.getName()); // not final, in order to re-initialize logging
private static Logger log = LoggerFactory.getLogger(PMD.class);
/** /**
* The line delimiter used by PMD in outputs. Usually the platform specific * The line delimiter used by PMD in outputs. Usually the platform specific
@ -97,19 +99,17 @@ public final class PMD {
try { try {
DBURI dbUri = new DBURI(uriString); DBURI dbUri = new DBURI(uriString);
DBMSMetadata dbmsMetadata = new DBMSMetadata(dbUri); DBMSMetadata dbmsMetadata = new DBMSMetadata(dbUri);
LOG.log(Level.FINE, "DBMSMetadata retrieved"); log.debug("DBMSMetadata retrieved");
List<SourceObject> sourceObjectList = dbmsMetadata.getSourceObjectList(); List<SourceObject> sourceObjectList = dbmsMetadata.getSourceObjectList();
LOG.log(Level.FINE, "Located {0} database source objects", sourceObjectList.size()); log.debug("Located {} database source objects", sourceObjectList.size());
for (SourceObject sourceObject : sourceObjectList) { for (SourceObject sourceObject : sourceObjectList) {
String falseFilePath = sourceObject.getPseudoFileName(); String falseFilePath = sourceObject.getPseudoFileName();
LOG.log(Level.FINEST, "Adding database source object {0}", falseFilePath); log.trace("Adding database source object {}", falseFilePath);
try { try {
dataSources.add(new ReaderDataSource(dbmsMetadata.getSourceCode(sourceObject), falseFilePath)); dataSources.add(new ReaderDataSource(dbmsMetadata.getSourceCode(sourceObject), falseFilePath));
} catch (SQLException ex) { } catch (SQLException ex) {
if (LOG.isLoggable(Level.WARNING)) { log.warn("Cannot get SourceCode for {} - skipping ...", falseFilePath, ex);
LOG.log(Level.WARNING, "Cannot get SourceCode for " + falseFilePath + " - skipping ...", ex);
}
} }
} }
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
@ -160,14 +160,9 @@ public final class PMD {
} }
return violationCounter.getResult(); return violationCounter.getResult();
} catch (final Exception e) { } catch (final Exception e) {
String message = e.getMessage(); log.error("Exception during processing: {}", e.toString()); // only exception without stacktrace
if (message == null) { log.debug("Exception during processing", e); // with stacktrace
LOG.log(Level.SEVERE, "Exception during processing", e); log.info(PMDCommandLineInterface.buildUsageText());
} else {
LOG.severe(message);
}
LOG.log(Level.FINE, "Exception during processing", e);
LOG.info(PMDCommandLineInterface.buildUsageText());
return PMDCommandLineInterface.NO_ERRORS_STATUS; return PMDCommandLineInterface.NO_ERRORS_STATUS;
} finally { } finally {
/* /*
@ -190,11 +185,11 @@ public final class PMD {
if (isEmpty(ruleSets)) { if (isEmpty(ruleSets)) {
String msg = "No rules found. Maybe you misspelled a rule name? (" String msg = "No rules found. Maybe you misspelled a rule name? ("
+ String.join(",", rulesetPaths) + ')'; + String.join(",", rulesetPaths) + ')';
LOG.log(Level.SEVERE, msg); log.error(msg);
throw new IllegalArgumentException(msg); throw new IllegalArgumentException(msg);
} }
} catch (RuleSetLoadException rsnfe) { } catch (RuleSetLoadException rsnfe) {
LOG.log(Level.SEVERE, "Ruleset not found", rsnfe); log.error("Ruleset not found", rsnfe);
throw rsnfe; throw rsnfe;
} }
return ruleSets; return ruleSets;
@ -211,10 +206,10 @@ public final class PMD {
* @param rulesets the RuleSets to print * @param rulesets the RuleSets to print
*/ */
private static void printRuleNamesInDebug(List<RuleSet> rulesets) { private static void printRuleNamesInDebug(List<RuleSet> rulesets) {
if (LOG.isLoggable(Level.FINER)) { if (log.isDebugEnabled()) {
for (RuleSet rset : rulesets) { for (RuleSet rset : rulesets) {
for (Rule r : rset.getRules()) { for (Rule r : rset.getRules()) {
LOG.finer("Loaded rule " + r.getName()); log.debug("Loaded rule {}", r.getName());
} }
} }
} }
@ -335,10 +330,7 @@ public final class PMD {
ruleSets.removeDysfunctionalRules(brokenRules); ruleSets.removeDysfunctionalRules(brokenRules);
for (final Rule rule : brokenRules) { for (final Rule rule : brokenRules) {
if (LOG.isLoggable(Level.WARNING)) { log.warn("Removed misconfigured rule: {} cause: {}", rule.getName(), rule.dysfunctionReason());
LOG.log(Level.WARNING,
"Removed misconfigured rule: " + rule.getName() + " cause: " + rule.dysfunctionReason());
}
} }
return brokenRules; return brokenRules;
@ -368,11 +360,11 @@ public final class PMD {
private static void encourageToUseIncrementalAnalysis(final PMDConfiguration configuration) { private static void encourageToUseIncrementalAnalysis(final PMDConfiguration configuration) {
if (!configuration.isIgnoreIncrementalAnalysis() if (!configuration.isIgnoreIncrementalAnalysis()
&& configuration.getAnalysisCache() instanceof NoopAnalysisCache && configuration.getAnalysisCache() instanceof NoopAnalysisCache
&& LOG.isLoggable(Level.WARNING)) { && log.isWarnEnabled()) {
final String version = final String version =
PMDVersion.isUnknown() || PMDVersion.isSnapshot() ? "latest" : "pmd-" + PMDVersion.VERSION; PMDVersion.isUnknown() || PMDVersion.isSnapshot() ? "latest" : "pmd-" + PMDVersion.VERSION;
LOG.warning("This analysis could be faster, please consider using Incremental Analysis: " log.warn("This analysis could be faster, please consider using Incremental Analysis: "
+ "https://pmd.github.io/" + version + "/pmd_userdocs_incremental_analysis.html"); + "https://pmd.github.io/{}/pmd_userdocs_incremental_analysis.html", version);
} }
} }
@ -433,7 +425,7 @@ public final class PMD {
String filePaths = FileUtil.readFilelist(file); String filePaths = FileUtil.readFilelist(file);
files.removeAll(FileUtil.collectFiles(filePaths, fileSelector)); files.removeAll(FileUtil.collectFiles(filePaths, fileSelector));
} catch (IOException ex) { } catch (IOException ex) {
LOG.log(Level.SEVERE, "Problem with Ignore File", ex); log.error("Problem with Ignore File", ex);
throw new RuntimeException("Problem with Ignore File Path: " + ignoreFilePath, ex); throw new RuntimeException("Problem with Ignore File Path: " + ignoreFilePath, ex);
} }
} }
@ -451,9 +443,7 @@ public final class PMD {
final LanguageVersion version = discoverer.getDefaultLanguageVersion(ruleLanguage); final LanguageVersion version = discoverer.getDefaultLanguageVersion(ruleLanguage);
if (RuleSet.applies(rule, version)) { if (RuleSet.applies(rule, version)) {
languages.add(ruleLanguage); languages.add(ruleLanguage);
if (LOG.isLoggable(Level.FINE)) { log.debug("Using {} version: {}", ruleLanguage.getShortName(), version.getShortName());
LOG.fine("Using " + ruleLanguage.getShortName() + " version: " + version.getShortName());
}
} }
} }
} }
@ -506,8 +496,8 @@ public final class PMD {
if (!parseResult.getDeprecatedOptionsUsed().isEmpty()) { if (!parseResult.getDeprecatedOptionsUsed().isEmpty()) {
Entry<String, String> first = parseResult.getDeprecatedOptionsUsed().entrySet().iterator().next(); Entry<String, String> first = parseResult.getDeprecatedOptionsUsed().entrySet().iterator().next();
LOG.warning("Some deprecated options were used on the command-line, including " + first.getKey()); log.warn("Some deprecated options were used on the command-line, including {}", first.getKey());
LOG.warning("Consider replacing it with " + first.getValue()); log.warn("Consider replacing it with {}", first.getValue());
} }
if (parseResult.isVersion()) { if (parseResult.isVersion()) {
@ -541,12 +531,15 @@ public final class PMD {
TimeTracker.startGlobalTracking(); TimeTracker.startGlobalTracking();
} }
final Level logLevel = configuration.isDebug() ? Level.FINER : Level.INFO; final Level logLevel = configuration.isDebug() ? Level.DEBUG : Level.INFO;
final ScopedLogHandlersManager logHandlerManager = new ScopedLogHandlersManager(logLevel, new ConsoleHandler()); Slf4jSimpleConfiguration.reconfigureDefaultLogLevel(logLevel);
final Level oldLogLevel = LOG.getLevel(); // need to reload the logger with the new configuration
// Need to do this, since the static logger has already been initialized log = LoggerFactory.getLogger(PMD.class);
// at this point if (configuration.isDebug()) {
LOG.setLevel(logLevel); log.debug("Loglevel is at {}", logLevel);
} else {
log.info("Loglevel is at {}", logLevel);
}
StatusCode status; StatusCode status;
try { try {
@ -562,9 +555,6 @@ public final class PMD {
System.err.println(e.getMessage()); System.err.println(e.getMessage());
status = StatusCode.ERROR; status = StatusCode.ERROR;
} finally { } finally {
logHandlerManager.close();
LOG.setLevel(oldLogLevel);
if (configuration.isBenchmark()) { if (configuration.isBenchmark()) {
final TimingReport timingReport = TimeTracker.stopGlobalTracking(); final TimingReport timingReport = TimeTracker.stopGlobalTracking();

View File

@ -0,0 +1,37 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.internal;
import java.lang.reflect.Method;
import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;
import org.slf4j.LoggerFactoryFriend;
import org.slf4j.event.Level;
public final class Slf4jSimpleConfiguration {
private Slf4jSimpleConfiguration() { }
public static void reconfigureDefaultLogLevel(Level level) {
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", level.toString());
// Call SimpleLogger.init() by reflection.
// Alternatively: move the CLI related classes into an own module, add
// slf4j-simple as a runtime dependency and create a PmdSlf4jSimpleFriend class in
// the package org.slf4j.simple to gain access to this package-private init method.
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
Class<? extends ILoggerFactory> loggerFactoryClass = loggerFactory.getClass();
try {
Class<?> simpleLoggerClass = loggerFactoryClass.getClassLoader().loadClass("org.slf4j.simple.SimpleLogger");
Method initMethod = simpleLoggerClass.getDeclaredMethod("init");
initMethod.setAccessible(true);
initMethod.invoke(null);
} catch (ReflectiveOperationException ex) {
System.err.println("Error while initializing logging: " + ex);
}
LoggerFactoryFriend.reset();
}
}

View File

@ -21,10 +21,10 @@ import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.contrib.java.lang.system.RestoreSystemProperties; import org.junit.contrib.java.lang.system.RestoreSystemProperties;
import org.junit.contrib.java.lang.system.SystemErrRule;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.junit.JavaUtilLoggingRule;
/** /**
* *
@ -39,7 +39,7 @@ public class CoreCliTest {
@Rule @Rule
public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
@Rule @Rule
public JavaUtilLoggingRule loggingRule = new JavaUtilLoggingRule(PMD.class.getPackage().getName()).mute(); public SystemErrRule loggingRule = new SystemErrRule().enableLog().muteForSuccessfulTests();
private Path srcDir; private Path srcDir;
@ -163,6 +163,18 @@ public class CoreCliTest {
} }
} }
@Test
public void debugLogging() {
runPmdSuccessfully("--debug", "--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET);
loggingRule.getLog().contains("[main] DEBUG net.sourceforge.pmd.PMD - Loglevel is at DEBUG");
}
@Test
public void defaultLogging() {
runPmdSuccessfully("--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET);
loggingRule.getLog().contains("[main] INFO net.sourceforge.pmd.PMD - Loglevel is at INFO");
}
// utilities // utilities

View File

@ -49,6 +49,10 @@
<artifactId>system-rules</artifactId> <artifactId>system-rules</artifactId>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>

View File

@ -98,6 +98,7 @@
<ant.version>1.10.12</ant.version> <ant.version>1.10.12</ant.version>
<javadoc.plugin.version>3.2.0</javadoc.plugin.version> <javadoc.plugin.version>3.2.0</javadoc.plugin.version>
<antlr.version>4.8</antlr.version> <antlr.version>4.8</antlr.version>
<slf4j.version>2.0.0-alpha6</slf4j.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@ -717,7 +718,12 @@
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
<version>1.7.32</version> <version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.codehaus.groovy</groupId> <groupId>org.codehaus.groovy</groupId>