2026-03-18 17:18:23 +08:00
|
|
|
|
"""
|
2026-03-26 12:13:36 +08:00
|
|
|
|
loguru 统一日志配置 + InterceptHandler 拦截第三方库的标准库 logging。
|
2026-03-22 16:45:57 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
约定:
|
|
|
|
|
|
- **业务代码**(`app` 包内):一律使用 ``get_logger(__name__)``,返回 **loguru** ``logger.bind(module=...)``,
|
|
|
|
|
|
直接走 loguru sink;占位符用 **``{}``**(勿用 ``%s``,否则不会插值)。
|
|
|
|
|
|
**禁止**用 ``import logging`` 取业务 logger(适配器层与第三方 SDK 除外)。
|
|
|
|
|
|
- **第三方**(uvicorn、celery、httpx、langchain 等):仍用标准库 ``logging``,经 ``InterceptHandler`` 汇入 loguru。
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
默认将 ``celery*``、``httpx``/``httpcore`` 调到 WARNING,避免刷屏;任务边界见 ``app.tasks.celery_app`` 中 ``event=celery_task_*``。
|
2026-03-22 16:45:57 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
级别:
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
- INFO:面向运维的稳定摘要(生产/预发推荐长期保持)。
|
|
|
|
|
|
- DEBUG:可含 prompt/响应预览或哈希;会显著增噪与体积,仅短时排障;可与 ``AGENT_LOG_MAX_CHARS`` / ``AGENT_LOG_PROMPT_MODE`` 配合。
|
2026-03-26 12:13:36 +08:00
|
|
|
|
|
|
|
|
|
|
由 ``Settings.log_level`` 控制 sink(``LOG_LEVEL``);``LOG_LEVEL=DEBUG`` 时业务 ``logger.debug`` 可见。
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
不打开全局 DEBUG 也可设 ``LOG_AGENT_VERBOSE=1`` 查看 Agent 单行耗时与规模(见 ``app.core.agent_logging``)。
|
2026-03-26 12:13:36 +08:00
|
|
|
|
|
|
|
|
|
|
**实践说明**:开发/终端用「人类可读」单行格式;若上生产聚合(ELK、Loki、CloudWatch),建议**另加** JSON sink(``serialize=True`` 或自定义 ``format``)与现有 stderr 并存,便于检索与关联,而不是在控制台格式里硬塞结构化字段。
|
|
|
|
|
|
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
**字段约定(可读性)**:
|
|
|
|
|
|
|
|
|
|
|
|
- 机读键用英文 ``snake_case``:优先 ``event=...``,其余 ``key=value`` 空格分隔;与人相关的说明用 ``msg=中文短句``(可含空格),放在行尾或紧邻 ``event`` 后。
|
|
|
|
|
|
- **HTTP**:``request_id`` 由中间件 ``contextualize``;业务处可 ``logger.bind(**correlation_bind_kwargs(user_id=..., memoir_correlation_id=...))``(见 ``app.core.log_events``)。
|
|
|
|
|
|
- **Celery**:``task_prerun`` 会通过 ``app.core.celery_log_context`` 注入 ``user_id`` / ``correlation_id`` / ``task_id`` 等到 loguru ``extra``(不覆盖已有 ``bind``);``task_postrun`` 清除,避免串任务。
|
|
|
|
|
|
- **耗时**:业务里程碑的结束行带 ``duration_ms``(``perf_counter`` × 1000);LLM 细粒度见 ``app.core.agent_logging`` 的 ``agent_span`` / ``LOG_AGENT_VERBOSE``。
|
|
|
|
|
|
- **级别**:INFO=里程碑与任务起止;DEBUG=体积与路径;WARNING=可恢复失败与降级。
|
|
|
|
|
|
|
|
|
|
|
|
Agent / LLM 诊断见 ``app.core.agent_logging``;``LOG_AGENT_VERBOSE``、``AGENT_LOG_MAX_CHARS``、``AGENT_LOG_PROMPT_MODE``、``AGENT_LOG_PROMPT_DEDUP`` 见 ``api/.env.example`` 与 ``Settings``。
|
2026-03-18 17:18:23 +08:00
|
|
|
|
"""
|
|
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
2026-03-18 17:18:23 +08:00
|
|
|
|
import logging
|
2026-03-26 12:13:36 +08:00
|
|
|
|
import os
|
2026-03-18 17:18:23 +08:00
|
|
|
|
import sys
|
2026-03-26 12:13:36 +08:00
|
|
|
|
from typing import TYPE_CHECKING, Any
|
2026-03-18 17:18:23 +08:00
|
|
|
|
|
|
|
|
|
|
from loguru import logger
|
|
|
|
|
|
|
2026-03-22 16:45:57 +08:00
|
|
|
|
from app.core.config import settings
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
from app.core.log_events import (
|
|
|
|
|
|
celery_prerun_extras,
|
|
|
|
|
|
correlation_bind_kwargs,
|
|
|
|
|
|
format_log_event,
|
|
|
|
|
|
)
|
2026-03-22 16:45:57 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
|
|
from loguru import Logger
|
|
|
|
|
|
|
2026-03-22 16:45:57 +08:00
|
|
|
|
|
|
|
|
|
|
def _sink_min_level() -> str:
|
|
|
|
|
|
raw = (settings.log_level or "INFO").strip().upper()
|
|
|
|
|
|
if raw in ("TRACE", "DEBUG", "INFO", "SUCCESS", "WARNING", "ERROR", "CRITICAL"):
|
|
|
|
|
|
return raw
|
|
|
|
|
|
return "INFO"
|
|
|
|
|
|
|
2026-03-18 17:18:23 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
def _parse_stdlib_level(name: str) -> int | None:
|
|
|
|
|
|
s = name.strip().upper()
|
|
|
|
|
|
if not s:
|
|
|
|
|
|
return None
|
|
|
|
|
|
if s == "TRACE":
|
|
|
|
|
|
return logging.DEBUG
|
|
|
|
|
|
return logging._nameToLevel.get(s) # type: ignore[attr-defined]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _stdlib_logging_package_dir() -> str:
|
|
|
|
|
|
"""标准库 ``logging`` 包目录(``logging.__file__`` 的父目录),用于路径判断。"""
|
|
|
|
|
|
return os.path.dirname(os.path.abspath(logging.__file__))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _path_is_stdlib_logging_source(path: str) -> bool:
|
|
|
|
|
|
"""是否落在 CPython 自带的 ``logging`` 包源码下(避免用 ``/logging/`` 子串误伤业务目录名)。"""
|
|
|
|
|
|
if not path:
|
|
|
|
|
|
return False
|
|
|
|
|
|
try:
|
|
|
|
|
|
root = os.path.normcase(_stdlib_logging_package_dir())
|
|
|
|
|
|
norm = os.path.normcase(os.path.abspath(path))
|
|
|
|
|
|
except OSError:
|
|
|
|
|
|
return False
|
|
|
|
|
|
sep = os.sep
|
|
|
|
|
|
return norm == root or norm.startswith(root + sep)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# CPython 未暴露「真实调用方」与「logging 内部 dispatch」的区分 API。部分链路里
|
|
|
|
|
|
# pathname 已是业务文件(如 celery/.../trace.py),但 funcName 仍被记成 logging
|
|
|
|
|
|
# 内部入口(callHandlers / Handler.emit 等)。此处枚举与 ``Lib/logging`` 中常见
|
|
|
|
|
|
# 帧名对齐;若未来版本改名,可据栈样本增补。
|
|
|
|
|
|
_LOG_DISPATCH_FUNC_NAMES: frozenset[str] = frozenset(
|
|
|
|
|
|
{"callHandlers", "emit", "handle", "makeRecord", "callWithContext"}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _stdlib_emit_display(log_record: logging.LogRecord) -> tuple[str, int]:
|
|
|
|
|
|
"""从 LogRecord 解析更可读的 function / line(供 InterceptHandler 写入 loguru)。"""
|
|
|
|
|
|
fn = log_record.funcName or "?"
|
|
|
|
|
|
ln = log_record.lineno
|
|
|
|
|
|
path = log_record.pathname or ""
|
|
|
|
|
|
|
|
|
|
|
|
if _path_is_stdlib_logging_source(path):
|
|
|
|
|
|
return "-", 0
|
|
|
|
|
|
|
|
|
|
|
|
if fn in _LOG_DISPATCH_FUNC_NAMES:
|
|
|
|
|
|
base = os.path.basename(path)
|
|
|
|
|
|
stem = base[:-3] if base.endswith(".py") else base
|
|
|
|
|
|
return stem or "?", ln
|
|
|
|
|
|
|
|
|
|
|
|
return fn, ln
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _stderr_format(record: Any) -> str:
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
"""控制台 sink:request_id / correlation_id / user_id 有值时才显示对应列。"""
|
2026-03-26 12:13:36 +08:00
|
|
|
|
rid = str(record["extra"].get("request_id") or "").strip()
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
rid_part = "<dim>rid={extra[request_id]}</dim> | " if rid and rid != "-" else ""
|
|
|
|
|
|
cid = str(record["extra"].get("correlation_id") or "").strip()
|
|
|
|
|
|
cid_part = "<dim>corr={extra[correlation_id]}</dim> | " if cid else ""
|
|
|
|
|
|
uid = str(record["extra"].get("user_id") or "").strip()
|
|
|
|
|
|
uid_part = "<dim>uid={extra[user_id]}</dim> | " if uid else ""
|
2026-03-26 12:13:36 +08:00
|
|
|
|
return (
|
|
|
|
|
|
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
|
|
|
|
|
|
"<level>{level.name: <8}</level> | "
|
|
|
|
|
|
"<cyan>{extra[module]}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
f"{rid_part}{cid_part}{uid_part}"
|
2026-03-26 12:13:36 +08:00
|
|
|
|
"<level>{message}</level>\n{exception}"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
def _merge_celery_worker_extra(record: Any) -> None:
|
|
|
|
|
|
"""把 ContextVar 中的 Celery 上下文字段并入本条 loguru 记录(不覆盖已有非空 extra)。"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
from app.core.celery_log_context import get_celery_log_extras
|
|
|
|
|
|
|
|
|
|
|
|
ctx = get_celery_log_extras()
|
|
|
|
|
|
if not ctx:
|
|
|
|
|
|
return
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
return
|
|
|
|
|
|
ex = record["extra"]
|
|
|
|
|
|
for k, v in ctx.items():
|
|
|
|
|
|
if not v:
|
|
|
|
|
|
continue
|
|
|
|
|
|
cur = ex.get(k)
|
|
|
|
|
|
if cur is None or str(cur).strip() in ("", "-"):
|
|
|
|
|
|
ex[k] = v
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
def _apply_third_party_log_levels() -> None:
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
"""压低 Celery/httpx 框架日志噪声。
|
|
|
|
|
|
|
|
|
|
|
|
根 logger 为 NOTSET 时,子 logger 若也为 NOTSET,有效级别会变成 0(NOTSET),INFO 会全部通过,
|
|
|
|
|
|
因此这里**必须**写死默认级别,不能依赖 NOTSET「继承」。
|
|
|
|
|
|
|
|
|
|
|
|
默认(未设 CELERY_LOG_LEVEL / HTTPX_LOG_LEVEL):
|
|
|
|
|
|
- ``LOG_LEVEL`` 为 TRACE/DEBUG:Celery→INFO,httpx/httpcore→WARNING
|
|
|
|
|
|
- 否则:Celery 与 httpx/httpcore→WARNING(保留业务 loguru 与 ``event=celery_task_*`` 摘要)
|
|
|
|
|
|
|
|
|
|
|
|
需要框架原始行时,设置 ``CELERY_LOG_LEVEL=INFO``、``HTTPX_LOG_LEVEL=INFO`` 等。
|
|
|
|
|
|
"""
|
2026-03-26 12:13:36 +08:00
|
|
|
|
sink = _sink_min_level()
|
|
|
|
|
|
verbose = sink in ("TRACE", "DEBUG")
|
|
|
|
|
|
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
# 无效环境变量时的回退:与「未设置变量」分支一致,禁止 NOTSET
|
|
|
|
|
|
default_celery = logging.INFO if verbose else logging.WARNING
|
|
|
|
|
|
default_httpx = logging.WARNING
|
|
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
raw_c = (settings.celery_log_level or "").strip()
|
|
|
|
|
|
if raw_c:
|
|
|
|
|
|
parsed = _parse_stdlib_level(raw_c)
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
cel_level = parsed if parsed is not None else default_celery
|
2026-03-26 12:13:36 +08:00
|
|
|
|
else:
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
cel_level = default_celery
|
2026-03-26 12:13:36 +08:00
|
|
|
|
|
|
|
|
|
|
for name in ("celery", "celery.worker"):
|
|
|
|
|
|
logging.getLogger(name).setLevel(cel_level)
|
|
|
|
|
|
|
|
|
|
|
|
raw_h = (settings.httpx_log_level or "").strip()
|
|
|
|
|
|
if raw_h:
|
|
|
|
|
|
parsed = _parse_stdlib_level(raw_h)
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
httpx_level = parsed if parsed is not None else default_httpx
|
2026-03-26 12:13:36 +08:00
|
|
|
|
else:
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
httpx_level = default_httpx
|
2026-03-26 12:13:36 +08:00
|
|
|
|
|
|
|
|
|
|
for name in ("httpx", "httpcore"):
|
|
|
|
|
|
logging.getLogger(name).setLevel(httpx_level)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-18 17:18:23 +08:00
|
|
|
|
class InterceptHandler(logging.Handler):
|
2026-03-26 12:13:36 +08:00
|
|
|
|
"""Route standard-library logging messages into loguru.
|
|
|
|
|
|
|
|
|
|
|
|
使用 stdlib LogRecord 的「真实文件/行」覆盖 loguru 的 function/line;
|
|
|
|
|
|
module 使用 record.name(如 celery.app.trace)。若只能解析到 logging 内部,则显示 ``-:0``。
|
|
|
|
|
|
"""
|
2026-03-18 17:18:23 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
def emit(self, log_record: logging.LogRecord) -> None:
|
2026-03-18 17:18:23 +08:00
|
|
|
|
try:
|
2026-03-26 12:13:36 +08:00
|
|
|
|
level = logger.level(log_record.levelname).name
|
2026-03-18 17:18:23 +08:00
|
|
|
|
except ValueError:
|
2026-03-26 12:13:36 +08:00
|
|
|
|
level = log_record.levelno
|
2026-03-18 17:18:23 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
modname = log_record.name or "logging"
|
|
|
|
|
|
fn, ln = _stdlib_emit_display(log_record)
|
2026-03-18 17:18:23 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
def patch_record(record: object) -> None:
|
|
|
|
|
|
r = record # loguru Record, dict-like
|
|
|
|
|
|
r["function"] = fn # type: ignore[index]
|
|
|
|
|
|
r["line"] = ln # type: ignore[index]
|
|
|
|
|
|
r["extra"]["module"] = modname # type: ignore[index]
|
|
|
|
|
|
|
|
|
|
|
|
msg = log_record.getMessage()
|
|
|
|
|
|
patched = logger.patch(patch_record)
|
|
|
|
|
|
if log_record.exc_info:
|
|
|
|
|
|
patched.opt(exception=log_record.exc_info).log(level, msg)
|
|
|
|
|
|
else:
|
|
|
|
|
|
patched.log(level, msg)
|
2026-03-18 17:18:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def setup_logging() -> None:
|
2026-03-26 12:13:36 +08:00
|
|
|
|
"""Call once at process entry(API:`main`;Worker:`celery_app` 首行)。
|
2026-03-20 15:15:35 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
Celery 需 ``worker_hijack_root_logger=False``,否则会覆盖根 logger。
|
2026-03-20 15:15:35 +08:00
|
|
|
|
"""
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
global logger
|
2026-03-18 17:18:23 +08:00
|
|
|
|
logger.remove()
|
|
|
|
|
|
|
|
|
|
|
|
logger.add(
|
|
|
|
|
|
sys.stderr,
|
2026-03-22 16:45:57 +08:00
|
|
|
|
level=_sink_min_level(),
|
2026-03-26 12:13:36 +08:00
|
|
|
|
format=_stderr_format,
|
2026-03-18 17:18:23 +08:00
|
|
|
|
backtrace=True,
|
|
|
|
|
|
diagnose=False,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
json_path = (settings.log_json_file or "").strip()
|
|
|
|
|
|
if json_path:
|
|
|
|
|
|
logger.add(
|
|
|
|
|
|
json_path,
|
|
|
|
|
|
level=_sink_min_level(),
|
|
|
|
|
|
serialize=True,
|
|
|
|
|
|
rotation="20 MB",
|
|
|
|
|
|
retention="7 days",
|
|
|
|
|
|
encoding="utf-8",
|
|
|
|
|
|
enqueue=True,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
logger.configure(extra={"request_id": "-", "module": "-"})
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
logger = logger.patch(_merge_celery_worker_extra)
|
2026-03-26 12:13:36 +08:00
|
|
|
|
|
|
|
|
|
|
# 仅 root 挂 InterceptHandler,避免子 logger 与 root 各处理一次导致重复行
|
2026-03-18 17:18:23 +08:00
|
|
|
|
root = logging.getLogger()
|
|
|
|
|
|
root.handlers = [InterceptHandler()]
|
2026-03-26 12:13:36 +08:00
|
|
|
|
root.setLevel(logging.NOTSET)
|
|
|
|
|
|
|
|
|
|
|
|
_apply_third_party_log_levels()
|
2026-03-18 17:18:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
def get_logger(name: str) -> Logger:
|
|
|
|
|
|
"""返回带 ``module`` 上下文的 loguru Logger;业务模块应 ``get_logger(__name__)``。"""
|
|
|
|
|
|
return logger.bind(module=name)
|
2026-03-18 17:18:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
# 供 middleware 等使用 ``contextualize`` 的同一 loguru 实例(与 get_logger 同源)
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
__all__ = [
|
|
|
|
|
|
"logger",
|
|
|
|
|
|
"setup_logging",
|
|
|
|
|
|
"get_logger",
|
|
|
|
|
|
"InterceptHandler",
|
|
|
|
|
|
"format_log_event",
|
|
|
|
|
|
"correlation_bind_kwargs",
|
|
|
|
|
|
"celery_prerun_extras",
|
|
|
|
|
|
]
|