Files
alert-contract-expiring-hr/scripts/util/logging_setup.py
taojianmin 293b7d1591
All checks were successful
技能自动化发布 / release (push) Successful in 7s
chore: auto release commit (2026-09-15 00:32:44)
2026-09-15 00:32:44 +08:00

108 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""logging 配置:降级到 stderr,避免污染 stdout(stdout 留给结构化输出如 JSON)。
优先用 jiangchang_skill_core 提供的 logging;本地无该包时降级到 stderr。
v1.1.18:本地降级路径追加 RotatingFileHandler(按 LOG_FILE env 决定是否落文件)。
"""
from __future__ import annotations
import logging
import logging.handlers
import os
import sys
from pathlib import Path
from util.constants import (
LOG_LOGGER_NAME,
SKILL_SLUG,
SKILL_VERSION,
)
_configured = False
def setup_skill_logging() -> logging.Logger:
"""初始化 skill logger(幂等)。
本地降级行为(无 jiangchang_skill_core 时):
- 若 LOG_FILE 已设:追加 RotatingFileHandler(LOG_MAX_BYTES × LOG_BACKUP_COUNT)
- 始终追加 StreamHandler(sys.stderr)
- logger level 取自 LOG_LEVEL(默认 INFO)
"""
global _configured
logger = logging.getLogger(LOG_LOGGER_NAME)
if _configured:
return logger
# 优先用宿主提供的 skill logger 配置
try:
from jiangchang_skill_core.logging_config import setup_skill_logging as _host_setup
_host_setup(SKILL_SLUG, LOG_LOGGER_NAME)
_configured = True
return logging.getLogger(LOG_LOGGER_NAME)
except ImportError:
pass
# logger 级别
level_name = os.environ.get("LOG_LEVEL", "INFO").upper()
logger.setLevel(getattr(logging, level_name, logging.INFO))
formatter = logging.Formatter(
fmt=f"%(asctime)s [{SKILL_SLUG}] %(levelname)s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
# 本地降级:可选 RotatingFileHandler
log_file_str = os.environ.get("LOG_FILE")
if log_file_str:
log_path = Path(log_file_str)
if not log_path.is_absolute():
from util.runtime_paths import get_logs_dir
log_path = get_logs_dir() / log_file_str
log_path.parent.mkdir(parents=True, exist_ok=True)
max_bytes = int(os.environ.get("LOG_MAX_BYTES", str(5 * 1024 * 1024)))
backup_count = int(os.environ.get("LOG_BACKUP_COUNT", "5"))
file_handler = logging.handlers.RotatingFileHandler(
log_path,
maxBytes=max_bytes,
backupCount=backup_count,
encoding="utf-8",
)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# 始终保留 stderr handler
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.propagate = False
_configured = True
logger.info("logging initialized (local fallback) v%s", SKILL_VERSION)
return logger
def get_skill_logger() -> logging.Logger:
"""获取 skill logger(不会重复 setup)。"""
if not _configured:
return setup_skill_logging()
return logging.getLogger(LOG_LOGGER_NAME)
def reset_for_tests() -> None:
"""测试用:重置 _configured flag,让 setup_skill_logging 重新初始化。
必须在每个修改日志配置的测试 fixture 里调用,否则 env 改动不会生效。
"""
global _configured
logger = logging.getLogger(LOG_LOGGER_NAME)
for h in list(logger.handlers):
try:
h.close()
except Exception:
pass
logger.removeHandler(h)
_configured = False