blob: d8d0f60120caed0f086bf6aa160b97f45c947c0c [file] [log] [blame]
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from __future__ import annotations
import ast
import pathlib
import re
import sys
import astor as astor
from rich.console import Console
console = Console(color_system="standard", width=200)
LOGGIN_MATCHER = re.compile(r'^log.?[a-z]*\.[a-z]*\(f.*["\']')
SELF_LOG_MATCHER = re.compile(r'^self\.log\.[a-z]*\(f.*["\']')
class LogFinder(astor.TreeWalk):
module_printed: bool = False
name: str = ""
error_count = 0
def pre_Call(self):
if isinstance(self.cur_node.func, ast.Attribute) and (
isinstance(self.cur_node.func.value, ast.Name)
and (
self.cur_node.func.value.id == "logger"
or self.cur_node.func.value.id == "logging"
or self.cur_node.func.value.id == "log"
)
or (self.cur_node.func.attr in ["log", "debug", "warning", "info", "error", "critical"])
):
line = astor.to_source(self.cur_node, add_line_information=True)
if LOGGIN_MATCHER.match(line) or SELF_LOG_MATCHER.match(line):
if not self.module_printed:
self.module_printed = True
console.print(f"[red]Error:[/] {self.name}")
console.print(f"{self.name}:{self.cur_node.lineno} -> {line}", end="")
self.error_count += 1
def check_logging() -> int:
total_error_count = 0
for file_name in sys.argv[1:]:
file_path = pathlib.Path(file_name)
module = ast.parse(file_path.read_text("utf-8"), str(file_path))
finder = LogFinder()
finder.name = file_name
finder.walk(node=module)
total_error_count += finder.error_count
if total_error_count > 0:
console.print(
"\n[yellow]Please convert all the logging instructions above "
"to use '%-formatting' rather than f-strings."
)
console.print("Why?: https://docs.python.org/3/howto/logging.html#logging-variable-data\n")
return 1 if total_error_count else 0
if __name__ == "__main__":
sys.exit(check_logging())