-
Notifications
You must be signed in to change notification settings - Fork 19
GCI1066 [Team TREE][2025] - For logging format, prefer using %s with kwargs instead of builtin formatter \"\".format() or f\"\"" #84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package org.greencodeinitiative.creedengo.python.checks; | ||
|
||
import org.sonar.check.Rule; | ||
import org.sonar.plugins.python.api.PythonSubscriptionCheck; | ||
import org.sonar.plugins.python.api.SubscriptionContext; | ||
import org.sonar.plugins.python.api.tree.*; | ||
import java.util.regex.Pattern; | ||
|
||
@Rule(key = "GCI1066") | ||
public class DetectBadLoggingFormatInterpolation extends PythonSubscriptionCheck { | ||
|
||
protected static final String MESSAGE_RULE = "For logging format, prefer using %s with kwargs instead of builtin formatter \"\".format() or f\"\""; | ||
private static final Pattern PATTERN_FORMAT = Pattern.compile("f['\"].*['\"]"); | ||
private static final Pattern PATTERN_LOGGER = Pattern.compile("logging|logger"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest making a version that is insensitive to the variable name because the user can define it, so decteion won't work: here's what I suggest:
} |
||
private static final Pattern PATTERN_LOGGING_METHOD = Pattern.compile("info|debug|error"); | ||
|
||
@Override | ||
public void initialize(Context context) { | ||
context.registerSyntaxNodeConsumer(Tree.Kind.CALL_EXPR, this::visitNodeString); | ||
} | ||
|
||
public void visitNodeString(SubscriptionContext ctx) { | ||
CallExpression callExpression = (CallExpression) ctx.syntaxNode(); | ||
|
||
QualifiedExpression qualifiedExpression = (QualifiedExpression)((CallExpression)ctx.syntaxNode()).callee(); | ||
|
||
if(PATTERN_LOGGING_METHOD.matcher(qualifiedExpression.name().name()).matches() | ||
&& PATTERN_LOGGER.matcher(((Name)qualifiedExpression.qualifier()).name()).matches() | ||
&& PATTERN_FORMAT.matcher(((RegularArgument)callExpression.arguments().get(0)).expression().firstToken().value()).matches()) { | ||
ctx.addIssue(callExpression, MESSAGE_RULE); | ||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.greencodeinitiative.creedengo.python.checks; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add corresponding header :
|
||
|
||
import org.junit.Test; | ||
import org.sonar.python.checks.utils.PythonCheckVerifier; | ||
|
||
public class DetectBadLoggingFormatInterpolationTest { | ||
|
||
@Test | ||
public void test_bad_logging_format_interpolation() { | ||
PythonCheckVerifier.verify("src/test/resources/checks/detectBadLoggingFormatInterpolationNonCompliant.py", new DetectBadLoggingFormatInterpolation()); | ||
PythonCheckVerifier.verifyNoIssue("src/test/resources/checks/detectBadLoggingFormatInterpolationCompliant.py", new DetectBadLoggingFormatInterpolation()); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import logging | ||
logger = logging.getLogger() | ||
name = "world" | ||
|
||
logging.info("Hello %s", name) # Correct | ||
logger.debug("Hello %s", name) # Correct |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import logging | ||
logger = logging.getLogger() | ||
name = "world" | ||
|
||
#logging.info("Hello {}".format(name)) # Noncompliant {{For logging format, prefer using %s with kwargs instead of builtin formatter "".format() or f""}} | ||
logger.debug(f'Hello {name}') # Noncompliant {{For logging format, prefer using %s with kwargs instead of builtin formatter "".format() or f""}} | ||
logger.error(f"Hello {name}") # Noncompliant {{For logging format, prefer using %s with kwargs instead of builtin formatter "".format() or f""}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you modify the variable name so that it is not modifiable, you will have to add the corresponding tests, for example : my_logger = logging.getLogger() my_logger.debug(f"User {user} attempted login") # Noncompliant {{For logging format, prefer using %s with kwargs instead of builtin formatter "".format() or f""}} my_logger.info("Static log with no variables") my_logger.info("User %s connected", user) if True: with open("log.txt", "w") as f: class MyService:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add corresponding header :
/*
*/