feat(audit): skip audit log for excluded health/root paths
健康检查与根路径(/health/live、/health/ready、/api/v1/health、 /、/health/storage)没有用户、没业务动作,每秒被 K8s/LB 探针刷一次只会灌进无意义噪音。命中排除集即跳过审计行; 诊断日志(method/path/status/ms 走 stderr)照常打,对容器 运维排错仍有用。 * settings.audit_excluded_paths: list[str] 默认覆盖 5 条 基础设施路径,env AUDIT_EXCLUDED_PATHS 用逗号分隔 (pydantic NoDecode + field_validator 兼容 str/list) * main.py 模块级 _AUDIT_EXCLUDED = frozenset(...), access_log 的 success/exception 两条审计行各加守卫 诊断无条件打 * 测试用 _AccessLogReplica 复刻 access_log 契约(不 import 真实 main.py),新增 4 个 case:排除根路径、排除 /health/live、 不排除路径照写审计、自定义排除集 顺带 schedule 模块:ExecutionResult 与 context 已迁到 schedule.domain.*(execution.py / orchestrator.py / scheduler.py / worker.py),调用点跟进;schedule 自身 18 个测试在改前改后均通过。
This commit is contained in:
@@ -4,10 +4,10 @@ import asyncio
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path, PurePosixPath
|
||||
|
||||
from loguru import logger
|
||||
from schedule.domain.execution import ExecutionResult
|
||||
|
||||
MAX_LOG_BYTES = 4 * 1024 * 1024
|
||||
|
||||
@@ -26,18 +26,6 @@ def _resolve_python(version: str) -> str:
|
||||
raise ValueError(f"unsupported python_version: {version}")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ExecutionResult:
|
||||
status: str
|
||||
exit_code: int | None
|
||||
logs: bytes
|
||||
result: bytes
|
||||
result_file_name: str
|
||||
result_content_type: str
|
||||
error_code: str | None = None
|
||||
error_message: str | None = None
|
||||
|
||||
|
||||
def _limited_log(value: str) -> bytes:
|
||||
encoded = value.encode("utf-8", errors="replace")
|
||||
if len(encoded) <= MAX_LOG_BYTES:
|
||||
|
||||
@@ -30,7 +30,7 @@ from loguru import logger
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||
|
||||
from schedule.context import (
|
||||
from schedule.domain.context import (
|
||||
FAILED_NODE_STATES,
|
||||
TERMINAL_NODE_STATES,
|
||||
TERMINAL_RUN_STATES,
|
||||
|
||||
@@ -28,7 +28,7 @@ from loguru import logger
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||
|
||||
from schedule.context import naive_utc
|
||||
from schedule.domain.context import naive_utc
|
||||
|
||||
# APScheduler's persistent SQLAlchemy job store pickles each job. A bound
|
||||
# ``CronScheduler`` method captures this instance (including SQLAlchemy engine
|
||||
|
||||
@@ -41,8 +41,9 @@ from common.scheduler.trigger import SYSTEM_CRON_USER_ID
|
||||
from loguru import logger
|
||||
from sqlalchemy import select
|
||||
|
||||
from schedule.context import TERMINAL_NODE_STATES
|
||||
from schedule.execution import ExecutionResult, execute_artifact
|
||||
from schedule.domain.context import TERMINAL_NODE_STATES
|
||||
from schedule.domain.execution import ExecutionResult
|
||||
from schedule.execution import execute_artifact
|
||||
|
||||
NODE_EXECUTE_EVENT = schedule_event_type("job.node.execute")
|
||||
NODE_FINISHED_EVENT = schedule_event_type("job.node.finished")
|
||||
|
||||
Reference in New Issue
Block a user