包含多个会话的累积代码变更: - backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔 - admin-web: ETL 状态页、任务管理、调度配置、登录优化 - miniprogram: 看板页面、聊天集成、UI 组件、导航更新 - etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强 - tenant-admin: 项目初始化 - db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8) - packages/shared: 枚举和工具函数更新 - tools: 数据库工具、报表生成、健康检查 - docs: PRD/架构/部署/合约文档更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
137 lines
4.9 KiB
Python
137 lines
4.9 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
Dev Trace Log 配置模块
|
||
|
||
从环境变量读取 trace 相关配置,支持运行时动态修改(内存状态)。
|
||
重启后回退到 .env 配置值。使用单例模式,全局唯一实例。
|
||
|
||
环境变量缺失时使用合理默认值:
|
||
- DEV_TRACE_ENABLED: false(默认关闭,显式开启才采集)
|
||
- DEV_TRACE_LOG_DIR: export/dev-trace-logs
|
||
- DEV_TRACE_LOG_RETENTION_DAYS: 7
|
||
- DEV_TRACE_LOG_SQL: true
|
||
- DEV_TRACE_LOG_PARAMS: true
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import os
|
||
import threading
|
||
from typing import Any
|
||
|
||
|
||
def _parse_bool(value: str, default: bool) -> bool:
|
||
"""解析布尔型环境变量,支持 true/1/yes(不区分大小写)。"""
|
||
if not value:
|
||
return default
|
||
return value.strip().lower() in ("true", "1", "yes")
|
||
|
||
|
||
class TraceConfig:
|
||
"""全链路日志配置(单例)。
|
||
|
||
属性从环境变量初始化,运行时可通过 update_settings() 动态修改。
|
||
重启后自动回退到 .env 值(因为 __init__ 重新读取环境变量)。
|
||
"""
|
||
|
||
_instance: TraceConfig | None = None
|
||
_lock: threading.Lock = threading.Lock()
|
||
|
||
def __new__(cls) -> TraceConfig:
|
||
# 双重检查锁定,线程安全的单例
|
||
if cls._instance is None:
|
||
with cls._lock:
|
||
if cls._instance is None:
|
||
instance = super().__new__(cls)
|
||
instance._init_from_env()
|
||
cls._instance = instance
|
||
return cls._instance
|
||
|
||
def _init_from_env(self) -> None:
|
||
"""从环境变量读取配置,作为基线值和当前运行时值。"""
|
||
# 基线值(.env 原始值,reset_to_env 时回退到这里)
|
||
self._env_enabled: bool = _parse_bool(
|
||
os.environ.get("DEV_TRACE_ENABLED", ""), default=False
|
||
)
|
||
raw_log_dir: str = os.environ.get(
|
||
"DEV_TRACE_LOG_DIR", "export/dev-trace-logs"
|
||
)
|
||
# CHANGE 2026-03-22 | trace日志路径修复
|
||
# 相对路径基于项目根目录解析,避免受后端 cwd(apps/backend/)影响
|
||
if not os.path.isabs(raw_log_dir):
|
||
project_root = os.environ.get("NEOZQYY_ROOT", "")
|
||
if project_root:
|
||
raw_log_dir = os.path.join(project_root, raw_log_dir)
|
||
self._env_log_dir: str = raw_log_dir
|
||
self._env_retention_days: int = int(
|
||
os.environ.get("DEV_TRACE_LOG_RETENTION_DAYS", "7")
|
||
)
|
||
self._env_log_sql: bool = _parse_bool(
|
||
os.environ.get("DEV_TRACE_LOG_SQL", ""), default=True
|
||
)
|
||
self._env_log_params: bool = _parse_bool(
|
||
os.environ.get("DEV_TRACE_LOG_PARAMS", ""), default=True
|
||
)
|
||
|
||
# 运行时值(初始等于基线值,API 可动态修改)
|
||
self.enabled: bool = self._env_enabled
|
||
self.log_dir: str = self._env_log_dir
|
||
self.retention_days: int = self._env_retention_days
|
||
self.log_sql: bool = self._env_log_sql
|
||
self.log_params: bool = self._env_log_params
|
||
|
||
# ------------------------------------------------------------------
|
||
# 运行时开关方法
|
||
# ------------------------------------------------------------------
|
||
|
||
def update_settings(
|
||
self,
|
||
*,
|
||
enabled: bool | None = None,
|
||
retention_days: int | None = None,
|
||
log_sql: bool | None = None,
|
||
log_params: bool | None = None,
|
||
) -> None:
|
||
"""更新内存中的运行时设置(不写 .env,重启后回退)。"""
|
||
if enabled is not None:
|
||
self.enabled = enabled
|
||
if retention_days is not None:
|
||
self.retention_days = retention_days
|
||
if log_sql is not None:
|
||
self.log_sql = log_sql
|
||
if log_params is not None:
|
||
self.log_params = log_params
|
||
|
||
def get_settings(self) -> dict[str, Any]:
|
||
"""返回当前运行时设置字典。"""
|
||
return {
|
||
"enabled": self.enabled,
|
||
"log_dir": self.log_dir,
|
||
"retention_days": self.retention_days,
|
||
"log_sql": self.log_sql,
|
||
"log_params": self.log_params,
|
||
}
|
||
|
||
def reset_to_env(self) -> None:
|
||
"""重置运行时值为 .env 基线值。"""
|
||
self.enabled = self._env_enabled
|
||
self.log_dir = self._env_log_dir
|
||
self.retention_days = self._env_retention_days
|
||
self.log_sql = self._env_log_sql
|
||
self.log_params = self._env_log_params
|
||
|
||
# ------------------------------------------------------------------
|
||
# 测试辅助:重置单例(仅测试使用)
|
||
# ------------------------------------------------------------------
|
||
|
||
@classmethod
|
||
def _reset_singleton(cls) -> None:
|
||
"""销毁单例实例,下次访问时重新从环境变量初始化。仅供测试使用。"""
|
||
with cls._lock:
|
||
cls._instance = None
|
||
|
||
|
||
def get_trace_config() -> TraceConfig:
|
||
"""获取全局 TraceConfig 单例。"""
|
||
return TraceConfig()
|