加入日志管理

This commit is contained in:
陈辅元
2026-04-16 10:53:10 +08:00
parent 284e02f41c
commit 695356a496
19 changed files with 582 additions and 181 deletions
+14 -10
View File
@@ -136,28 +136,28 @@ def _classify_dialog_rules(
)
if _SQL_OR_QUERY_HINT_RE.search(t):
logger.debug("[dialog] intent=text2sql (query/business hint)")
logger.info("[dialog] intent=text2sql (query/business hint) preview=%r", user_text[:120])
return DialogClassifyResult(DialogIntent.TEXT2SQL, None)
core = _strip_trailing_punct(t)
if core.casefold() in _CHITCHAT_KEYS:
logger.debug("[dialog] intent=conversation (chitchat phrase)")
logger.info("[dialog] intent=conversation (chitchat phrase) core=%r", core)
return DialogClassifyResult(
DialogIntent.CONVERSATION, reply_suggestion=DEFAULT_CONVERSATION_REPLY
)
if _META_QUESTION_RE.search(t):
logger.debug("[dialog] intent=conversation (meta question)")
logger.info("[dialog] intent=conversation (meta question) preview=%r", user_text[:120])
return DialogClassifyResult(
DialogIntent.CONVERSATION,
reply_suggestion=DEFAULT_CONVERSATION_REPLY,
)
if last_turn_was_data_query:
logger.debug("[dialog] intent=text2sql (follow-up after data query)")
logger.info("[dialog] intent=text2sql (follow-up after data query) preview=%r", user_text[:120])
return DialogClassifyResult(DialogIntent.TEXT2SQL, None)
logger.debug("[dialog] intent=text2sql (default)")
logger.info("[dialog] intent=text2sql (default rules) preview=%r", user_text[:120])
return DialogClassifyResult(DialogIntent.TEXT2SQL, None)
@@ -208,11 +208,15 @@ def _classify_dialog_llm(
"若上一版 SQL 或结果不符合预期,请具体说明:希望增加/修改哪些条件、"
"时间范围或统计维度,以便重新生成。"
)
logger.info("[dialog] intent=conversation (LLM)")
logger.info(
"[dialog] intent=conversation (LLM) reply_chars=%s reply_preview=%r",
len(reply),
reply[:300] + ("…" if len(reply) > 300 else ""),
)
return DialogClassifyResult(DialogIntent.CONVERSATION, reply_suggestion=reply)
if intent_s == "text2sql":
logger.info("[dialog] intent=text2sql (LLM)")
logger.info("[dialog] intent=text2sql (LLM) user_preview=%r", user_text[:200])
return DialogClassifyResult(DialogIntent.TEXT2SQL, None)
raise ValueError(f"unexpected intent field: {intent_s!r}")
@@ -254,18 +258,18 @@ def classify_dialog(
)
if _SQL_OR_QUERY_HINT_RE.search(t):
logger.debug("[dialog] intent=text2sql (query/business hint, hybrid fast)")
logger.info("[dialog] intent=text2sql (hybrid fast: query hint) preview=%r", user_text[:120])
return DialogClassifyResult(DialogIntent.TEXT2SQL, None)
core = _strip_trailing_punct(t)
if core.casefold() in _CHITCHAT_KEYS:
logger.debug("[dialog] intent=conversation (chitchat phrase, hybrid fast)")
logger.info("[dialog] intent=conversation (hybrid fast: chitchat) core=%r", core)
return DialogClassifyResult(
DialogIntent.CONVERSATION, reply_suggestion=DEFAULT_CONVERSATION_REPLY
)
if _META_QUESTION_RE.search(t):
logger.debug("[dialog] intent=conversation (meta question, hybrid fast)")
logger.info("[dialog] intent=conversation (hybrid fast: meta) preview=%r", user_text[:120])
return DialogClassifyResult(
DialogIntent.CONVERSATION,
reply_suggestion=DEFAULT_CONVERSATION_REPLY,
+80
View File
@@ -0,0 +1,80 @@
"""
Text2SQL API 仓库级日志:控制台 + 单一磁盘文件(每次进程启动清空 logs/*.log 后重写)。
由 ``api_server`` 在导入早期调用;与 ``uvicorn.run(..., log_config=False)`` 配合,
使 uvicorn / FastAPI 的日志经 root 统一落到文件。
"""
from __future__ import annotations
import logging
from pathlib import Path
def configure_text2sql_api_logging(repo_root: Path) -> Path:
"""
配置 root logger:控制台(INFO,简短格式)+ ``logs/text2sql_api.log``(INFO,含文件名/行号/函数)。
每次调用会删除 ``logs`` 目录下所有 ``*.log``,再新建 ``text2sql_api.log``(覆盖写),
保证一次运行仅保留一个日志文件。
Returns:
主日志文件绝对路径。
"""
log_dir = (repo_root / "logs").resolve()
log_dir.mkdir(parents=True, exist_ok=True)
for p in log_dir.glob("*.log"):
try:
p.unlink()
except OSError:
pass
log_path = log_dir / "text2sql_api.log"
root = logging.getLogger()
root.setLevel(logging.INFO)
for h in list(root.handlers):
root.removeHandler(h)
try:
h.close()
except Exception:
pass
fmt_console = logging.Formatter(
"%(asctime)s [%(levelname)s] %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
fmt_file = logging.Formatter(
"%(asctime)s %(levelname)-7s [%(name)s] %(filename)s:%(lineno)d %(funcName)s() | %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
fh = logging.FileHandler(log_path, mode="w", encoding="utf-8")
fh.setLevel(logging.INFO)
fh.setFormatter(fmt_file)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
ch.setFormatter(fmt_console)
root.addHandler(fh)
root.addHandler(ch)
# 依赖库降噪(避免 httpx 每条请求刷屏;Chroma 遥测与新版 posthog 不兼容时会打 ERROR)
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
for _name in (
"chromadb.telemetry",
"chromadb.telemetry.product.posthog",
"posthog",
):
logging.getLogger(_name).disabled = True
# Uvicorn 默认自带 handler;与 log_config=False 合用时改为只往 root 冒泡
for name in ("uvicorn", "uvicorn.error", "uvicorn.access"):
lg = logging.getLogger(name)
lg.handlers.clear()
lg.propagate = True
logging.getLogger(__name__).info("日志文件: %s", log_path)
return log_path