Migrate all repos into monorepo context folders
Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)
Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Iterable
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class QueryLogEvent:
|
||||
"""Structured query log event.
|
||||
|
||||
Attributes:
|
||||
query_name: Short name for the operation (e.g. "get_open_tasks").
|
||||
sql: SQL statement with parameters redacted/normalized.
|
||||
params: Parameters (redacted where needed).
|
||||
"""
|
||||
|
||||
query_name: str
|
||||
sql: str
|
||||
params: tuple[Any, ...] | None
|
||||
|
||||
|
||||
_SECRET_KEYS = re.compile(r"(pass(word)?|secret|token|key)", re.IGNORECASE)
|
||||
|
||||
|
||||
def _redact_value(value: Any) -> Any:
|
||||
"""Redact a single value for logging.
|
||||
|
||||
Args:
|
||||
value: Value to redact.
|
||||
|
||||
Returns:
|
||||
Redacted value.
|
||||
"""
|
||||
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, (int, float, bool)):
|
||||
return value
|
||||
s = str(value)
|
||||
if len(s) <= 4:
|
||||
return "***"
|
||||
return s[:2] + "***" + s[-2:]
|
||||
|
||||
|
||||
def redact_params(params: Iterable[Any] | None) -> tuple[Any, ...] | None:
|
||||
"""Redact query parameters for safe logging.
|
||||
|
||||
Args:
|
||||
params: DB-API parameter sequence.
|
||||
|
||||
Returns:
|
||||
Redacted parameter tuple.
|
||||
"""
|
||||
|
||||
if params is None:
|
||||
return None
|
||||
return tuple(_redact_value(p) for p in params)
|
||||
|
||||
|
||||
def normalize_sql(sql: str) -> str:
|
||||
"""Normalize SQL for logging.
|
||||
|
||||
This removes excessive whitespace to keep log lines readable.
|
||||
|
||||
Args:
|
||||
sql: SQL statement.
|
||||
|
||||
Returns:
|
||||
Normalized SQL.
|
||||
"""
|
||||
|
||||
return " ".join(sql.split())
|
||||
|
||||
|
||||
def log_query(
|
||||
*,
|
||||
logger: logging.Logger,
|
||||
query_name: str,
|
||||
sql: str,
|
||||
params: Iterable[Any] | None = None,
|
||||
) -> None:
|
||||
"""Emit a safe query log line.
|
||||
|
||||
Args:
|
||||
logger: Logger to use.
|
||||
query_name: Short name for the operation.
|
||||
sql: SQL statement.
|
||||
params: DB-API parameters.
|
||||
"""
|
||||
|
||||
event = QueryLogEvent(
|
||||
query_name=query_name,
|
||||
sql=normalize_sql(sql),
|
||||
params=redact_params(params),
|
||||
)
|
||||
logger.debug("DB query: %s", event)
|
||||
Reference in New Issue
Block a user