diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore index 412bf43..c53189d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,9 @@ wheels/ # Virtual environments .venv + +# Config +.env + +# Log +logs/* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7e13f46..5a568f2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,13 +13,6 @@ repos: - id: check-merge-conflict # 检查合并冲突标记 - id: debug-statements # 检查调试语句 - # Python代码格式化:black - - repo: https://github.com/psf/black - rev: 25.1.0 # 稳定版本 - hooks: - - id: black - args: ['--line-length=120'] # 行长度适配AI项目长函数参数 - # 整理import顺序:isort - repo: https://github.com/PyCQA/isort rev: 5.13.2 # 稳定版本 @@ -32,10 +25,7 @@ repos: rev: v0.14.14 hooks: - id: ruff - args: - - --line-length=120 - - --select=E,W,F,I,N,UP,YTT,B,SIM,COM,C4,DTZ,T10,EM,EXE,FA,ISC,ICN,G,INP,PIE,Q003,RET,RSE,SLF,SIM,T20,TID,TRY - - --ignore=E203,W503,COM812 # 忽略和black冲突的规则 + args: [--fix, --exit-non-zero-on-fix, --no-cache] # 检测硬编码密钥:detect-secrets (暂时禁用,基线文件问题) # - repo: https://github.com/Yelp/detect-secrets diff --git a/pyproject.toml b/pyproject.toml index 5ab2581..f3ca85f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,7 @@ [dependency-groups] dev = [ - "pre-commit>=4.5.1" + "pre-commit>=4.5.1", + "pytest>=9.0.2" ] [project] @@ -10,5 +11,6 @@ description = "Add your description here" readme = "README.md" requires-python = ">=3.11" dependencies = [ - "detect-secrets>=1.5.0" + "detect-secrets>=1.5.0", + "loguru>=0.7.3" ] diff --git a/src/comp_synth/__init__.py b/src/comp_synth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/comp_synth/config.py b/src/comp_synth/config.py new file mode 100644 index 0000000..cced74b --- /dev/null +++ b/src/comp_synth/config.py @@ -0,0 +1,2 @@ +# -------------------------- Log ---------------------- +LOG_DIR = "D:\CompSynth\logs" diff --git a/src/comp_synth/logging/__init__.py b/src/comp_synth/logging/__init__.py new file mode 100644 index 0000000..fe70e80 --- /dev/null +++ b/src/comp_synth/logging/__init__.py @@ -0,0 +1,3 @@ +from comp_synth.logging.logger_config import logger + +__all__ = [logger] diff --git a/src/comp_synth/logging/logger_config.py b/src/comp_synth/logging/logger_config.py new file mode 100644 index 0000000..c59b2d4 --- /dev/null +++ b/src/comp_synth/logging/logger_config.py @@ -0,0 +1,43 @@ +from pathlib import Path + +from loguru import logger + +from comp_synth import config + +LOG_DIR = Path(config.LOG_DIR) +LOG_DIR.mkdir(parents=True, exist_ok=True) + +# 定义日志格式 +# 控制台彩色格式(含上下文绑定字段:request_id/user_id) +CONSOLE_FMT = ( + "{time:YYYY-MM-DD HH:mm:ss} | " + "{level: <8} | " + "{module}:{line} | " + "{message}" +) +# 文件纯文本格式(含进程/线程ID,便于多进程调试) +FILE_FMT = "{time:YYYY-MM-DD HH:mm:ss.SSS} | " "{level: <8} | " "{module}:{line} | " "{message}" +# 错误日志格式(含异常堆栈) +ERROR_FMT = "{time:YYYY-MM-DD HH:mm:ss.SSS} | " "{level: <8} | " "{module}:{line} | " "{message}" + +logger.remove() + +logger.add( + sink=LOG_DIR / "app_{time:YYYYMMDD}.log", + level="DEBUG", + format=FILE_FMT, + encoding="utf-8", + enqueue=True, + backtrace=False, + diagnose=False, +) + +logger.add( + sink=LOG_DIR / "error_{time:YYYYMMDD}.log", + level="ERROR", + format=ERROR_FMT, + encoding="utf-8", + enqueue=True, + backtrace=True, + diagnose=False, +) diff --git a/tests/test_logging.py b/tests/test_logging.py new file mode 100644 index 0000000..4a50205 --- /dev/null +++ b/tests/test_logging.py @@ -0,0 +1,116 @@ +from comp_synth.logging import logger + +# from loguru import logger +# +# logger.remove() +# +# # 1. 控制台输出(INFO及以上,彩色格式) +# logger.add( +# sys.stdout, +# level="INFO", # 最低日志级别 +# format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {module}:{line} - {message}" +# ) +# +# # 2. 文件输出(DEBUG及以上,纯文本格式,自动创建文件)默认使用追加模式 +# logger.add( +# sink="../logs/app.log", # 日志文件路径,目录不存在会自动创建 +# level="DEBUG", +# format="{time:YYYY HH:mm:ss} | {level: <8} | {module}:{line} - {message}", +# encoding="utf-8" # 指定编码,避免中文乱码(必配) +# ) +# +# logger.add( +# sink="../logs/app.log", # 不幂等 +# level="DEBUG", +# format="{time:YYYY HH:mm:ss} | {level: <8} | {module}:{line} - {message}", +# encoding="utf-8" +# ) +# +# # 过滤1:仅输出来自 user 模块的日志(通配符*匹配子模块) +# logger.add( +# sys.stdout, +# format="{time:YYYY HH:mm:ss} | {level: <8} | {module}:{line} - {message}", +# filter="user.*" # 仅匹配 logger 名称为 user、user.utils、user.service 等的日志 +# ) +# +# # 过滤2:仅输出 ERROR 和 CRITICAL 级别日志(字典格式) +# logger.add( +# "../logs/error.log", +# format="{time:YYYY HH:mm:ss} | {level: <8} | {module}:{line} - {message}", +# filter=lambda record: record["level"].name in ["ERROR", "CRITICAL"] +# ) +# +# # 生产环境标配:50MB轮转+保留30天+zip压缩+中文防乱码 +# logger.add( +# sink="../logs/app_{time:YYYYMMDD}.log", # 文件名带日期,便于查找 +# level="DEBUG", +# format="{time:YYYY HH:mm:ss} | {level: <8} | {module}:{line} - {message}", +# encoding="utf-8", +# rotation="50 MB", # 单个文件50MB,自动轮转 +# retention="30 days", # 仅保留最近30天的日志文件 +# compression="zip", # 过期日志自动压缩为zip格式 +# enqueue=True, # 多进程安全写入(避免多进程下日志乱序/丢失) +# backtrace=True, # 捕获异常时,显示完整的堆栈回溯(包括第三方库) +# diagnose=True # 捕获异常时,显示变量值等诊断信息(开发/测试环境开启) +# ) +# +# logger.debug("调试信息:仅写入文件,控制台不显示") +# logger.info("信息:控制台+文件均显示") +# logger.info("根模块日志:不会被输出") # 过滤1不匹配,无输出 +# logger.error("根模块错误:会写入error.log") # 过滤2匹配,正常输出 +# +# try: +# # 模拟异常 +# 1 / 0 +# except ZeroDivisionError: +# # exc_info=True:自动记录完整的异常堆栈 +# logger.error("除零错误发生,业务执行失败", exc_info=True) +# +# +# # 装饰器方式:捕获函数内所有异常 +# @logger.catch # 关键:添加该装饰器 +# def divide(a, b): +# return a / b +# +# +# +# logger.remove() +# # 格式中添加绑定的字段占位符:{request_id}、{user_id} +# console_fmt = "{time:HH:mm:ss} | {level: <8} | request_id={request_id} | user_id={user_id} | {message}" +# logger.add(sys.stdout, format=console_fmt, level="INFO") +# +# # 1. 基础绑定:绑定固定字段 +# logger = logger.bind(request_id="req-123456", user_id=1001) +# logger.info("用户发起登录请求") +# logger.info("用户密码验证通过") +# logger.warning("用户登录次数超过阈值") +# +# # 2. 动态绑定:针对不同请求生成唯一request_id(Web场景标配) +# def handle_request(user_id): +# # 为每个请求生成唯一request_id +# req_id = str(uuid.uuid4())[:8] +# # 动态绑定上下文 +# req_logger = logger.bind(request_id=req_id, user_id=user_id) +# req_logger.info("请求开始:/api/user/info") +# req_logger.info("查询用户信息完成") +# return {"code": 200, "msg": "success"} +# +# # 模拟两个不同请求 +# handle_request(1002) +# handle_request(1003) + + +def test_logger(): + logger.debug("agent调用工具失败") + logger.info("agent调用add工具中") + + +@logger.catch(reraise=True) +def divide(a, b): + return a / b + +def test_logger_reraise(): + try: + divide(1, 0) + except Exception: + print("process catch error") diff --git a/uv.lock b/uv.lock index 0d8e582..1de418f 100644 --- a/uv.lock +++ b/uv.lock @@ -93,24 +93,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + [[package]] name = "compsynth" version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "detect-secrets" }, + { name = "loguru" }, ] [package.dev-dependencies] dev = [ { name = "pre-commit" }, + { name = "pytest" }, ] [package.metadata] -requires-dist = [{ name = "detect-secrets", specifier = ">=1.5.0" }] +requires-dist = [ + { name = "detect-secrets", specifier = ">=1.5.0" }, + { name = "loguru", specifier = ">=0.7.3" }, +] [package.metadata.requires-dev] -dev = [{ name = "pre-commit", specifier = ">=4.5.1" }] +dev = [ + { name = "pre-commit", specifier = ">=4.5.1" }, + { name = "pytest", specifier = ">=9.0.2" }, +] [[package]] name = "detect-secrets" @@ -161,6 +178,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "loguru" +version = "0.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" }, +] + [[package]] name = "nodeenv" version = "1.10.0" @@ -170,6 +209,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + [[package]] name = "platformdirs" version = "4.5.1" @@ -179,6 +227,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, ] +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + [[package]] name = "pre-commit" version = "4.5.1" @@ -195,6 +252,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" }, ] +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" @@ -287,3 +369,12 @@ sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544 wheels = [ { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, ] + +[[package]] +name = "win32-setctime" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" }, +]