Files
planet/backend/app/services/business_logs.py
rayd1o 5bf5c73ca0
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / delivery (push) Has been cancelled
release / images (push) Has been cancelled
release: bump version to 0.66.0
2026-05-26 03:41:47 +08:00

118 lines
3.2 KiB
Python

from __future__ import annotations
import asyncio
from collections.abc import Mapping
from typing import Any
from app.core.logging import PlanetLoggerAdapter, sanitize_log_value
from app.core.request_context import get_request_id
from app.services.persistent_logs import record_system_log
LEVEL_METHODS = {
"debug": "debug_event",
"info": "info_event",
"warning": "warning_event",
"error": "error_event",
}
def normalize_business_level(level: str | None) -> str:
normalized = str(level or "info").strip().lower()
if normalized in {"warn", "warning"}:
return "warning"
if normalized in {"err", "error", "critical", "fatal"}:
return "error"
if normalized == "debug":
return "debug"
return "info"
def build_business_context(
context: Mapping[str, Any] | None = None,
**fields: Any,
) -> dict[str, Any]:
payload = dict(context or {})
for key, value in fields.items():
if value is not None:
payload[key] = value
return sanitize_log_value(payload)
async def emit_business_log(
logger: PlanetLoggerAdapter,
*,
event: str,
message: str,
category: str,
level: str = "info",
source: str = "backend",
service: str | None = None,
module: str | None = None,
request_id: str | None = None,
user_id: int | None = None,
context: Mapping[str, Any] | None = None,
) -> None:
normalized_level = normalize_business_level(level)
safe_context = build_business_context(context)
log_method = getattr(logger, LEVEL_METHODS[normalized_level])
log_method(message, event=event, context=safe_context)
await record_system_log(
source=source,
level=normalized_level,
message=message,
service=service,
module=module,
event=event,
request_id=request_id or get_request_id(),
user_id=user_id,
category=category,
context=safe_context,
)
def emit_business_log_background(
logger: PlanetLoggerAdapter,
*,
event: str,
message: str,
category: str,
level: str = "info",
source: str = "backend",
service: str | None = None,
module: str | None = None,
request_id: str | None = None,
user_id: int | None = None,
context: Mapping[str, Any] | None = None,
) -> None:
normalized_level = normalize_business_level(level)
safe_context = build_business_context(context)
log_method = getattr(logger, LEVEL_METHODS[normalized_level])
log_method(message, event=event, context=safe_context)
try:
loop = asyncio.get_running_loop()
except RuntimeError:
return
loop.create_task(
record_system_log(
source=source,
level=normalized_level,
message=message,
service=service,
module=module,
event=event,
request_id=request_id or get_request_id(),
user_id=user_id,
category=category,
context=safe_context,
)
)
def exception_context(exc: BaseException, context: Mapping[str, Any] | None = None) -> dict[str, Any]:
return build_business_context(
context,
error_type=type(exc).__name__,
error=str(exc),
)