Skip to content
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

Pylint Exception logging #9077

Merged
merged 64 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
9f84ad7
add placeholders
MJoshuaB Aug 11, 2024
c81ff56
add new placeholder comments
MJoshuaB Aug 20, 2024
18762be
exploring AST unfinished - minor emergency had to leave
16234397 Aug 21, 2024
2238161
identifying some mismatched functions
16234397 Aug 28, 2024
95fe015
refactor checker and tests
MJoshuaB Aug 28, 2024
e2e664f
fix error with non-builtins decorators
MJoshuaB Aug 28, 2024
46053e6
fine tuning and testing required
16234397 Aug 29, 2024
b402a5d
add pylint report
MJoshuaB Aug 29, 2024
3d051d7
add ranked listing of reports
MJoshuaB Aug 29, 2024
fdf6db7
format report as table
MJoshuaB Aug 29, 2024
fb160d5
add new verbs
MJoshuaB Sep 1, 2024
f06c915
update report
MJoshuaB Sep 2, 2024
db697b2
update reportcounts.md
MJoshuaB Sep 2, 2024
ae66d2c
fix formatting for reportcounts.md
MJoshuaB Sep 2, 2024
233f536
update reportcounts.md
MJoshuaB Sep 2, 2024
27edb80
minimal tests added
16234397 Sep 3, 2024
112173d
Merge pull request #2 from Azure/main
JessicaBell00 Sep 8, 2024
c5ffb91
Merge branch 'Azure:main' into main
JessicaBell00 Sep 10, 2024
7dc03ca
Merge branch 'working-main' into main
JessicaBell00 Sep 12, 2024
18f09e9
Merge pull request #5 from MJoshuaB/main
JessicaBell00 Sep 12, 2024
af098f7
Merge branch 'Azure:main' into working-main
JessicaBell00 Sep 12, 2024
cfba33d
Base code and unit tests
JessicaBell00 Sep 12, 2024
f7af031
Refactored class to be more specific
JessicaBell00 Sep 16, 2024
013a408
Added to README
JessicaBell00 Sep 16, 2024
fee5009
Merge branch 'main' of https://github.com/Azure/azure-sdk-tools into …
JessicaBell00 Sep 16, 2024
bec9467
Update README / fix merging
JessicaBell00 Sep 16, 2024
6e53b16
Final Refactor
16234397 Sep 17, 2024
687f542
Fixed false positives
JessicaBell00 Sep 18, 2024
80657b4
not running multiple times picking up on different function types
16234397 Sep 19, 2024
5b69e7e
Merge branch 'main' into invalid-use-of-@overload
16234397 Sep 19, 2024
b10a3cd
add TODOs
MJoshuaB Sep 21, 2024
a0e5c18
removed code not reached
16234397 Sep 24, 2024
bf6936c
Merge remote-tracking branch 'origin/invalid-use-of-@overload' into i…
16234397 Sep 24, 2024
3ed8120
Checks at a class level
16234397 Sep 24, 2024
ac9921a
Merge branch 'main' into invalid-use-of-@overload
16234397 Sep 24, 2024
4c638df
Looking into different connection_verify assignments
16234397 Sep 25, 2024
ab62179
Placeholders added back
16234397 Sep 26, 2024
795c861
Checker base done
16234397 Sep 26, 2024
35094ba
exclue private namespaces and classes
MJoshuaB Sep 26, 2024
ed5e211
update reports
MJoshuaB Sep 27, 2024
a835da4
Checker, Tests, & Readme done
16234397 Sep 29, 2024
693ea14
Update pylint_guidelines_checker.py
JessicaBell00 Sep 30, 2024
141da43
Fix another false positive
JessicaBell00 Sep 30, 2024
202faa2
Check either sides of indices
JessicaBell00 Oct 1, 2024
3abf67a
Merge branch 'main' of https://github.com/Azure/azure-sdk-tools into …
JessicaBell00 Oct 1, 2024
ae88cee
add new prefixes
MJoshuaB Oct 1, 2024
efe6ddc
Merge branch 'main' into working-main
MJoshuaB Oct 1, 2024
0bf7340
Merge branch 'working-main' into approved_prefix
MJoshuaB Oct 2, 2024
cfaa891
update unit tests
MJoshuaB Oct 2, 2024
a6f341a
remove reports
MJoshuaB Oct 2, 2024
5947f31
remove commented code
MJoshuaB Oct 2, 2024
65e431f
add checker to README
MJoshuaB Oct 2, 2024
c50a082
Merge branch 'working-main' into do-not-hardcode-boolean-connection_v…
16234397 Oct 5, 2024
24e9647
Merge pull request #10 from MJoshuaB/do-not-hardcode-boolean-connecti…
16234397 Oct 5, 2024
1f78550
Merge branch 'working-main' into invalid-use-of-@overload
16234397 Oct 5, 2024
56176ca
Merge pull request #11 from MJoshuaB/invalid-use-of-@overload
16234397 Oct 5, 2024
8cdce20
Tidy Up
16234397 Oct 5, 2024
6a319b7
Add TODO comment re other cases to investigate
JessicaBell00 Oct 6, 2024
7e7256b
Merge pull request #13 from Azure/main
JessicaBell00 Oct 6, 2024
6d262e3
Merge branch 'working-main' into approved_prefix
MJoshuaB Oct 6, 2024
18ea2fa
Merge pull request #12 from MJoshuaB/approved_prefix
MJoshuaB Oct 6, 2024
e2dcbb9
Merge branch 'working-main' into exception-logging
JessicaBell00 Oct 6, 2024
9027a8b
Revert "Merge branch 'working-main' into exception-logging"
JessicaBell00 Oct 6, 2024
9a32416
Make checker more explicit
JessicaBell00 Oct 9, 2024
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
Expand Up @@ -54,7 +54,7 @@ In the case of a false positive, use the disable command to remove the pylint er


| Pylint checker name | How to fix this | How to disable this rule | Link to python guideline |
|----------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------| ------------------------------------------------------------------------------------------------------- |
|----------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
| client-method-should-not-use-static-method | Use module level functions instead. | # pylint:disable=client-method-should-not-use-static-method | [link](https://azure.github.io/azure-sdk/python_implementation.html#method-signatures) |
| missing-client-constructor-parameter-credential | Add a credential parameter to the client constructor. Do not use plural form "credentials". | # pylint:disable=missing-client-constructor-parameter-credential | [link](https://azure.github.io/azure-sdk/python_design.html#client-configuration) |
| missing-client-constructor-parameter-kwargs | Add a \*\*kwargs parameter to the client constructor. | # pylint:disable=missing-client-constructor-parameter-kwargs | [link](https://azure.github.io/azure-sdk/python_design.html#client-configuration) |
Expand Down Expand Up @@ -95,4 +95,5 @@ In the case of a false positive, use the disable command to remove the pylint er
| no-typing-import-in-type-check | Do not import typing under TYPE_CHECKING. | pylint:disable=no-typing-import-in-type-check | No Link. |
| do-not-log-raised-errors | Do not log errors at `error` or `warning` level when error is raised in an exception block. | pylint:disable=do-not-log-raised-errors | No Link. |
| do-not-use-legacy-typing | Do not use legacy (<Python 3.8) type hinting comments | pylint:disable=do-not-use-legacy-typing | No Link.
| do-not-import-asyncio | Do not import asyncio directly. | pylint:disable=do-not-import-asyncio | No Link. |
| do-not-import-asyncio | Do not import asyncio directly. | pylint:disable=do-not-import-asyncio | No Link. |
| do-not-log-exceptions | Do not log exceptions in levels other than debug, otherwise it can reveal sensitive information | pylint:disable=do-not-log-exceptions | [link](https://azure.github.io/azure-sdk/python_implementation.html#python-logging-sensitive-info) |
Original file line number Diff line number Diff line change
Expand Up @@ -2614,7 +2614,7 @@ def visit_functiondef(self, node):
try:
if node.returns.as_string() == "None":
# If there are residual comment typehints or no return value,
# we dont want to throw an error
# we don't want to throw an error
return
if node.name.startswith("delete") and node.parent.name.endswith("Client"):
if node.returns.as_string() != "None":
Expand Down Expand Up @@ -2865,10 +2865,79 @@ def visit_import(self, node):


# [Pylint] custom linter check for invalid use of @overload #3229
# [Pylint] Custom Linter check for Exception Logging #3227


class DoNotLogExceptions(BaseChecker):

"""Rule to check that exceptions aren't logged"""

name = "do-not-log-exceptions"
priority = -1
msgs = {"C4766": (
"Do not log exceptions. See Details:"
" https://azure.github.io/azure-sdk/python_implementation.html#python-logging-sensitive-info",
"do-not-log-exceptions",
"Do not log exceptions in levels other than debug, it can otherwise reveal sensitive information",
),
}

def visit_try(self, node):
"""Check that exceptions aren't logged in exception blocks.
Go through exception block and branches and ensure error hasn't been logged.
"""
# Return a list of exception blocks
except_block = node.handlers
# Iterate through each exception block
for nod in except_block:
# Get exception blocks with an exception name
if nod.name is not None:
exception_name = nod.name.name
self.check_for_logging(nod.body, exception_name)

def check_for_logging(self, node, exception_name):
""" Helper function - checks nodes to see if logging has occurred at all
levels.
"""
levels_matches = [".warning", ".error", ".info", ".debug"]
for j in node:
if isinstance(j, astroid.Expr):
expression = j.as_string().lower()
if any(x in expression for x in levels_matches) and "logger" in expression:
# Check for variables after strings
end_finder = expression.rfind("'")
JessicaBell00 marked this conversation as resolved.
Show resolved Hide resolved
delimiters = ["(", "{", "}", ")", "\"", ",", "'"]
if end_finder != -1:
expression_a = expression[end_finder + 1:]
# If there are variables after a string
if len(expression_a) > 1:
expression = expression_a
for delimiter in delimiters:
expression = " ".join(expression.split(delimiter))
expression1 = expression.split()
# Check for presence of exception name
for i in range(len(expression1)):
if exception_name == expression1[i]:
if i+1 < len(expression1):
if "." and "name" not in expression1[i+1]:
JessicaBell00 marked this conversation as resolved.
Show resolved Hide resolved
self.add_message(
msgid=f"do-not-log-exceptions",
node=j,
confidence=None,
)
else:
self.add_message(
msgid=f"do-not-log-exceptions",
node=j,
confidence=None,
)
if isinstance(j, astroid.If):
self.check_for_logging(j.body, exception_name)
# Check any 'elif' or 'else' branches
self.check_for_logging(j.orelse, exception_name)


# [Pylint] Address Commented out Pylint Custom Plugin Checkers #3228
# [Pylint] Add a check for connection_verify hardcoded settings #35355
# [Pylint] Refactor test suite for custom pylint checkers to use files instead of docstrings #3233
# [Pylint] Investigate pylint rule around missing dependency #3231


Expand Down Expand Up @@ -2907,12 +2976,11 @@ def register(linter):
linter.register_checker(NoImportTypingFromTypeCheck(linter))
linter.register_checker(DoNotUseLegacyTyping(linter))
linter.register_checker(DoNotLogErrorsEndUpRaising(linter))
linter.register_checker(DoNotLogExceptions(linter))

# [Pylint] custom linter check for invalid use of @overload #3229
# [Pylint] Custom Linter check for Exception Logging #3227
# [Pylint] Address Commented out Pylint Custom Plugin Checkers #3228
# [Pylint] Add a check for connection_verify hardcoded settings #35355
# [Pylint] Refactor test suite for custom pylint checkers to use files instead of docstrings #3233
# [Pylint] Investigate pylint rule around missing dependency #3231

# disabled by default, use pylint --enable=check-docstrings if you want to use it
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from plugin import logger


# test_logging_levels_logged_str_exception
def test_logging_levels_logged_str_exception():
try: # @
add = 1 + 2
except Exception as ex:
logger.error("Error" + str(ex)) # @
logger.warning(str(ex))
logger.info(str(ex))
logger.debug(str(ex))

JessicaBell00 marked this conversation as resolved.
Show resolved Hide resolved

# test_logging_levels_logged_repr_exception
def test_logging_levels_logged_repr_exception():
try: # @
add = 1 + 2
except Exception as ex:
logger.error(repr(ex)) # @
logger.warning(repr(ex))
logger.info(repr(ex))
logger.debug(repr(ex))


# test_regular_logging_ok
def test_regular_logging_ok():
try: # @
add = 1 + 2
except Exception as ex:
logger.error("Example 1") # @
logger.warning("This is another example")
logger.info("Random logging")
logger.debug("Logging")


# test_logging_str_exception_branches
def test_logging_str_exception_branches():
try: # @
add = 1 + 2
except Exception as ex:
if ex.code == "Retryable":
logger.error(str(ex))
return True
elif Exception != BaseException:
logger.warning(repr(ex))
return False
else:
logger.info(str(ex)) # @


# test_other_logging_fails
def test_other_logging_fails():
try: # @
add = 1 + 2
except Exception as ex:
if ex.code == "Retryable":
logger.error("Something went wrong: {ex}. Try again")
return True
else:
logger.warning(ex)
return False


# test_no_logging_and_no_exception_name_ok
def test_no_logging_and_no_exception_name_ok():
try:
add = 1 + 2
except Exception as ex:
self.errors.appendleft(ex)
except Exception as ex: # pylint: disable=broad-except
_logger.warning(
"Exception occurred when instrumenting: %s.",
lib_name,
exc_info=ex,
)
except (OSError, PermissionError) as e:
logger.warning(
"Failed to read on-disk cache for component due to %s. "
"Please check if the file %s is in use or current user doesn't have the permission.",
type(e).__name__,
on_disk_cache_path.as_posix(),
)


# test_logging_without_exception_name
def test_logging_without_exception_name():
try:
add = 1 + 2
except Exception as exception:
if exception.code == "Retryable":
_LOGGER.info(
"%r returns an exception %r", self._container_id, last_exception
)
else:
module_logger.debug("Skipping file upload, reason: %s", str(e.reason))
Loading