51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
"""NL2SQL 管理员诊断数据构造。"""
|
|||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from collections import deque
|
||
|
|
from threading import Lock
|
||
|
|
|
||
|
|
def build_diagnostic_snapshot(
|
||
|
|
*,
|
||
|
|
query_id: str,
|
||
|
|
status: str,
|
||
|
|
access_tables: set[str] | list[str],
|
||
|
|
security_rule: str | None = None,
|
||
|
|
model_elapsed_ms: float | None = None,
|
||
|
|
sql: str | None = None,
|
||
|
|
) -> dict:
|
||
|
|
"""构造不含原始 SQL 和敏感结果的诊断快照。"""
|
||
|
|
return {
|
||
|
|
"query_id": query_id,
|
||
|
|
"status": status,
|
||
|
|
"access_tables": sorted(set(access_tables)),
|
||
|
|
"security_rule": security_rule,
|
||
|
|
"model_elapsed_ms": model_elapsed_ms,
|
||
|
|
"has_sql": bool(sql),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
class DiagnosticRegistry:
|
||
|
|
"""保存最近的脱敏诊断摘要,进程重启后自动清空。"""
|
||
|
|
|
||
|
|
def __init__(self, *, max_items: int = 100):
|
||
|
|
self._items = deque(maxlen=max_items)
|
||
|
|
self._lock = Lock()
|
||
|
|
|
||
|
|
def record(self, **kwargs) -> None:
|
||
|
|
"""记录诊断摘要并丢弃未定义的敏感字段。"""
|
||
|
|
allowed = {
|
||
|
|
"query_id", "status", "access_tables", "security_rule",
|
||
|
|
"model_elapsed_ms", "sql",
|
||
|
|
}
|
||
|
|
snapshot = build_diagnostic_snapshot(**{key: value for key, value in kwargs.items() if key in allowed})
|
||
|
|
with self._lock:
|
||
|
|
self._items.appendleft(snapshot)
|
||
|
|
|
||
|
|
def list_recent(self) -> list[dict]:
|
||
|
|
"""返回最近诊断摘要的副本。"""
|
||
|
|
with self._lock:
|
||
|
|
return [dict(item) for item in self._items]
|
||
|
|
|
||
|
|
|
||
|
|
diagnostic_registry = DiagnosticRegistry()
|