From 0fdf2adfc6a0f339fb9283a5a1ade00a6a21e1a6 Mon Sep 17 00:00:00 2001 From: HTony03 Date: Fri, 12 Apr 2024 23:19:33 +0800 Subject: [PATCH] ooooh final ver! --- README.md | 20 +++- loggerjava/__init__.py | 6 +- loggerjava/exceptionhandler.py | 165 +++++++++++++-------------------- loggerjava/test_loggerjava.py | 12 +++ pyproject.toml | 2 +- 5 files changed, 100 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 92af6de..5103935 100644 --- a/README.md +++ b/README.md @@ -66,22 +66,38 @@ and using `logger.inportconfig(inputconfig)` to inport your config ### Exception handler using the `loggerjava.exceptionhandler.exception(exc)` function to process an Exception +remember to register the defs/classes after you created them + ```python import loggerjava import loggerjava.exceptionhandler def test1(a): print(b) +class test2(): + def printa(self): + print(self.b) +loggerjava.exceptionhandler.register_def(test1) +loggerjava.exceptionhandler.register_def(test2) if __name__ == "__main__": try: test1(1) except Exception as E: loggerjava.error(loggerjava.exceptionhandler.handler(E)) + try: + a = test2 + a.printa() + except Exception as E: + loggerjava.error(loggerjava.exceptionhandler.handler(E)) ``` #### Output: ```commandline [20:39:00] [main/ERROR]: NameError: name 'b' is not defined - at (:7) - at test1 (:4) + at (test.py:30) + at test1.test1 (test.py:21) + +[20:39:00] [main/ERROR]: AttributeError: 'test2' object has no attribute 'b' + at (test.py:35) + at test2.printa (test.py:25) ``` ### Versions diff --git a/loggerjava/__init__.py b/loggerjava/__init__.py index d791343..b34a5cd 100644 --- a/loggerjava/__init__.py +++ b/loggerjava/__init__.py @@ -1,12 +1,12 @@ import time import loggerjava -import loggerjava.exceptionhandler +from loggerjava.exceptionhandler import * if __name__ == '__main__': pass -ver = "v0.8.0.dev1" +ver = "v0.8.0" name = "log" absolutepath = False showdetailedtime = False @@ -75,7 +75,7 @@ def log(txt, type="i", pos="main", **overrides): f.close() if debugmodein: return _formats.format(timelog, pos, level, txt) - del detailtime, inconsole, debugmodein, timelog, overridename, data + del detailtime, inconsole, debugmodein, timelog def debug(txt, pos="main", **overrides): diff --git a/loggerjava/exceptionhandler.py b/loggerjava/exceptionhandler.py index 13192e9..70b6b28 100644 --- a/loggerjava/exceptionhandler.py +++ b/loggerjava/exceptionhandler.py @@ -3,124 +3,91 @@ import inspect import os +# 模块级别的变量,用于存储注册的类和函数信息 +_database = [] -def format_traceback_frame(frame): - filename = frame[0] - lineno = frame[1] - name = frame[2] - text = frame[3] - - # 移除文件路径,只保留文件名 - filename = os.path.basename(filename) - - # 移除函数名前的 'at ',并添加 ' in ' 来更接近 Java 风格 - name = name.replace('at ', '').replace(' in ', '') - - # 格式化输出 - return f" at {name} ({filename}:{lineno})\n" +def register_def(item): + """ + register the classes/defs to the exceptionhander module + :param item: the class/def you created + :return: none + """ + if inspect.isclass(item): + class_name = item.__name__ + method_names = [method for method in dir(item) if callable(getattr(item, method)) and method[0] != "_"] + _database.append({ + "name": class_name, + "defs": method_names + }) + elif inspect.isfunction(item): + func_name = item.__name__ + _database.append({ + "name": func_name, + "defs": [] # 函数没有内部方法,所以defs为空列表 + }) + else: + raise ValueError("Only classes and functions can be registered.") + + +def query_def_ownership(def_name): + """ + check the ownership of def_name + :param def_name: the name of def + :return: the ownership of the def + """ + for entry in _database: + if entry["name"] == def_name or def_name in entry["defs"]: + return entry["name"] + return None # 如果没有找到,返回None def handler(exc): """ the handler of the exceptions :param exc: the catched Exception see README.md for the usage of it - :return: + :return: none """ - # 初始化输出字符串 - output = "" - - # 捕获异常类型和消息 exc_type = type(exc).__name__ exc_message = str(exc) + formatted_exc = f"{exc_type}: {exc_message}\n" + + tb = exc.__traceback__ + frames = traceback.extract_tb(tb) + + for frame in frames: + filename, lineno, name, text = frame + filename = os.path.basename(filename) - # 添加异常类型和消息到输出字符串 - output += f"{exc_type}: {exc_message}\n" + cls = query_def_ownership(name) + #module_name = "" + #print(cls) + if cls is None: + formatted_frame = f" at {name} ({filename}:{lineno})\n" + else: + #formatted_frame = f" at {module_name}.{cls}.{name} ({filename}:{lineno})\n" + formatted_frame = f" at {cls}.{name} ({filename}:{lineno})\n" - # 提取堆栈跟踪信息 - tb = traceback.extract_tb(exc.__traceback__) + formatted_exc += formatted_frame - # 遍历堆栈帧并添加到输出字符串 - for frame in tb: - output += format_traceback_frame(frame) + return formatted_exc - return output -def handler2(Exception): - # 获取异常的类型、值和traceback对象 - exc_type, exc_value, exc_traceback = sys.exc_info() - # 格式化异常信息为字符串列表 - tb_list = traceback.format_exception(exc_type, exc_value, exc_traceback) - # 将列表中的字符串连接起来形成完整的调用栈信息 - tb_str = ''.join(tb_list) - # 打印调用栈信息 - print(f"捕获到异常: {Exception}\n调用栈信息:\n{tb_str}") - print(exc_type.__name__) - print(exc_value) - print(exc_traceback) - #print(tb_list) - print(tb_str) - exception_type_full_str = f"{type(Exception).__module__}.{type(Exception).__name__}" - line = exception_type_full_str+": "+str(Exception)+"\n at" - print(line) +class a(): + def __init__(self): + self.a = 1 + def p(self): + print(self.b) +register_def(a) if __name__ == "__main__": pass - #hmm wat? - """ + try: - print(a) - except Exception as e: - print(handler(e)) - """ -""" - exception_type_name = type(e).__name__ - # 将异常类型的名称转化为字符串(实际上已经是字符串了) - exception_type_str = str(exception_type_name) - print(f"捕获到异常类型: {exception_type_str}") - - exception_type_full_str = f"{type(e).__module__}.{type(e).__name__}" - print(f"完整的异常类型字符串: {exception_type_full_str}") - - tb = traceback.extract_tb(e.__traceback__) - # 通常,最后一个元素是异常发生的位置 - last_frame = tb[-1] - # 获取函数名和模块名 - func_name = last_frame[2] - module_name = last_frame[0] - - print("捕获到异常:") - print(f"异常类型: {type(e).__name__}") - print(f"异常信息: {e}") - print("调用栈信息:") - # 打印完整的堆栈跟踪信息 - for frame in tb: - filename, line_number, function_name, text = frame - print(f"{module_name}.{function_name} (文件 {filename}, 行 {line_number})") - print(f" {text.strip()}") - - tb = e.__traceback__ - # 提取堆栈跟踪信息 - stack_info = traceback.extract_tb(tb) - - # 格式化堆栈跟踪信息以更接近Java的格式 - formatted_tb = [] - for frame in stack_info: - filename, line_number, function_name, text = frame - # 假设模块名就是文件名去掉.py后缀(这通常不是完全准确的,但在这里作为示例) - module_name = filename.rsplit('.', 1)[0].replace('/', '.') if '.' in filename else '__main__' - formatted_tb.append(f"{module_name}.{function_name} (文件 {filename}, 行 {line_number})") - formatted_tb.append(f" {text.strip()}") - - # 打印异常类型和消息 - print("捕获到异常:") - print(f"异常类型: {type(e).__name__}") - print(f"异常信息: {e}") - - # 打印格式化后的堆栈跟踪信息 - print("调用栈信息:") - for line in formatted_tb: - print(line) -""" \ No newline at end of file + sa = a() + sa.p() + except Exception as E: + print(handler4(E)) + #hmm wat? diff --git a/loggerjava/test_loggerjava.py b/loggerjava/test_loggerjava.py index 2c22b73..a3c71a7 100644 --- a/loggerjava/test_loggerjava.py +++ b/loggerjava/test_loggerjava.py @@ -3,6 +3,8 @@ # import pytest import time +import loggerjava.exceptionhandler + """ class MyTestCase(unittest.TestCase): def test_something(self): @@ -45,6 +47,16 @@ def testin(): assert logger.log("testoverride", type="d", showdetailedtime=True) == "[" + time.asctime() + "] [main/debug]: testoverride\n" assert logger.warn("testoverride", showdetailedtime=True) == "[" + time.asctime() + "] [main/WARN]: testoverride\n" + try: + def test1(a): + print(b) + test1(1) + except Exception as e: + a = loggerjava.exceptionhandler.handler(e) + assert a == "NameError: name 'b' is not defined\n at testin (test_loggerjava.py:53)\n at test1 (test_loggerjava.py:52)\n" + assert logger.warn(loggerjava.exceptionhandler.handler(e)) == "[" + str(time.localtime().tm_hour).rjust(2, "0") + ":" + \ + str(time.localtime().tm_min).rjust(2, "0") + ":" + str(time.localtime().tm_sec).rjust(2, + "0") + "] [main/WARN]: %s\n"%a if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index 8d64058..e378372 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "loggerjava" -version = "v0.8.0.dev1" +version = "v0.8.0" authors = [ { name="HTony03", email="HTony03@foxmail.com" }, ]