Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"eclipse-jetty:jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java": [
207
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"eclipse-jetty:jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java": [
207
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,10 @@ interface InterfaceWithTwoLoggers {

class ConfigurableLoggerProperty {

private static final Logger LOG = LoggerFactory.getLogger(ConfigurableLoggerProperty.class); // Compliant
private Logger contextLogger; // Compliant, not initialized here, it is a configurable property
private static final Logger LOG = LoggerFactory.getLogger(ConfigurableLoggerProperty.class);
// ^^^> {{Logger already declared here.}}
private Logger contextLogger; // Noncompliant {{Remove this logger and use the one already declared in this class.}}
// ^^^^^^^^^^^^^

Logger getContextLogger() {
return contextLogger;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,11 @@ private static List<VariableTree> loggerFields(ClassTree classTree) {
List<VariableTree> loggerFields = classTree.members().stream()
.filter(member -> member.is(Tree.Kind.VARIABLE))
.map(VariableTree.class::cast)
.filter(MoreThanOneLoggerCheck::isDeclaredLogger)
.filter(field -> isLoggerType(field.type().symbolType()))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] the PR title and description don't mention this change to the rule implementation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the title and description to mention the check change.

.toList();
return withoutDerivedLoggers(loggerFields);
}

/**
* A non-final logger field without an initializer is a configurable property, assigned at startup
* or injected from outside, rather than a category the class gives itself. A final one has to be
* assigned in an initializer or a constructor, so it is a category of the class.
*/
private static boolean isDeclaredLogger(VariableTree field) {
return (field.initializer() != null || field.symbol().isFinal()) && isLoggerType(field.type().symbolType());
}

/**
* Drops the loggers whose name is derived from another logger of the same class, such as
* {@code LoggerFactory.getLogger(LOG.getName() + ".config")}. Those create a child category,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,15 @@ <h2>Why is this an issue?</h2>
<p>This rule raises an issue when a class declares more than one logger field, for SLF4J, Log4j, Log4j 2, Commons Logging and
<code>java.util.logging</code>.</p>
<h3>Exceptions</h3>
<p>This rule targets production code only. A test class often declares one logger per class under test, so it can capture the output of each of them.
Those loggers belong to the classes being exercised, and keeping them does not split the logging of a production class.</p>
<p>A nested or inner class is a class of its own, so a logger it declares is not counted against the logger of the enclosing class. Only the fields
declared directly in the same class body are counted together.</p>
<p>A non-static logger field declared next to a static one still raises an issue, because the class still ends up with two loggers, regardless of the
modifiers. Rule {rule:java:S1312} covers the modifiers a logger field should have.</p>
<p>A non-final logger field that is not initialized where it is declared does not count. Such a field is a configurable property, assigned at startup
or injected from outside, often exposed through a getter and a setter. It is not a second category that the class gives itself, and it usually cannot
be removed without changing the API of the class. A <code>final</code> field is different: it can only be assigned in an initializer or a constructor
of the class, so it does count.</p>
<p>A logger whose name is derived from another logger of the same class, as in <code>LoggerFactory.getLogger(LOG.getName() + ".config")</code>, does
not count either. That call creates a child category, which inherits the level and the appenders configured for the parent, so the output of the class
is still governed as one unit and the problem described above does not arise. Reusing the name as it is, as in
not count. That call creates a child category, which inherits the level and the appenders configured for the parent, so the output of the class is
still governed as one unit and the problem described above does not arise. Reusing the name as it is, as in
<code>LoggerFactory.getLogger(LOG.getName())</code>, builds the same category rather than a child one and is still reported.</p>
<h2>How to fix it</h2>
<p>Keep one logger and remove the other field, then point the calls that used the removed logger at the remaining one.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"defaultSeverity": "Major",
"ruleSpecification": "RSPEC-9436",
"sqKey": "S9436",
"scope": "All",
"scope": "Main",
"quickfix": "infeasible",
"code": {
"impacts": {
Expand Down
Loading