Volver a la wiki

log_action: helper de auditoría (SystemLog) que nunca rompe la request

Descripción

Helper genérico para registrar entradas de auditoría (SystemLog) desde cualquier endpoint o servicio, con garantía de nunca romper la request (best-effort).

Ubicación: core.utils.audit.log_action()
Disponible en: from core.utils import log_action
Requisitos previos: SystemLog (modelo) ya debe existir.

Firma

def log_action(
    request,
    category: str,
    action: str,
    details: str = "",
    level: str = "INFO"
) -> None:

Parámetros

ParámetroTipoDescripciónEjemplo
requestHttpRequestContexto HTTP para resolver user + org. Obligatorio.Django request object
categorystrCategoría de auditoría (constante en SystemLog.CATEGORY_CHOICES)."ITSM", "OBSERVATORY", "AUTH"
actionstrIdentificador corto machine-friendly de la acción."channel.create", "alert.delete", "sla.update"
detailsstrPayload libre (JSON, texto plano o URL-encoded). Opcional, por defecto "".f"id={c.id} name={c.name}", json.dumps({"old": old_val, "new": new_val})
levelstrSeveridad del log ("INFO", "WARN", "ERROR"). Por defecto "INFO"."WARN" para acciones arriesgadas

Retorno

Comportamiento

Resolución de contexto

  1. Usuario: request.user si autenticado; None si anónimo o token sin identidad
  2. Organización: Resuelto via get_current_org(request) (respeta RLS)
  3. IP/User-Agent: No se capturan en SystemLog (se podrían añadir vía request.META si se requiere)

Best-effort (tolerancia a fallos)

try:
    # 1. Import SystemLog + get_current_org
    # 2. Resolve user & org
    # 3. Create entry
    SystemLog.objects.create(...)
except Exception:
    logger.exception("log_action failed (category=%s action=%s)", category, action)
    # NCA: nunca re-raise, request continúa

Implicación: Si la BD está lenta, la migración falló, o hay constraint violation, el endpoint sigue adelante. El fallo se registra en logging.getLogger("core") para debugging posterior.

Casos especiales

Uso típico

En un endpoint de mutación

from django.shortcuts import get_object_or_404
from ninja import Router
from core.utils import log_action, require_perm

router = Router()

@router.delete("/channels/{channel_id}")
def delete_channel(request, channel_id: int):
    require_perm(request, "itsm", "edit")
    org = require_org(request)
    c = get_object_or_404(NotificationChannel, id=channel_id, organization=org)
    
    # Audit ANTES de borrar (por si quieres capturar datos del objeto)
    log_action(
        request,
        category="ITSM",
        action="channel.delete",
        details=f"id={channel_id} name={c.name}"
    )
    
    c.delete()
    return {"deleted": True}

Con JSON detallado

import json

@router.post("/alerts/{alert_id}/threshold")
def update_threshold(request, alert_id: int, data: ThresholdIn):
    old_val = alert.threshold_value
    alert.threshold_value = data.threshold_value
    alert.save()
    
    log_action(
        request,
        category="OBSERVATORY",
        action="alert.threshold",
        details=json.dumps({
            "alert_id": alert_id,
            "old_value": old_val,
            "new_value": data.threshold_value
        })
    )
    return {"ok": True}

Campos generados automáticamente

Cada entrada SystemLog incluye:

CampoFuenteEjemplo
timestamptimezone.now()2026-06-07 10:55:52+00:00
userrequest.user si autenticadoUser(id=42, username="operator")
organizationget_current_org(request)Organization(id=5, slug="acme")
levelParámetro (default "INFO")"INFO"
categoryParámetro"ITSM"
actionParámetro"channel.create"
detailsParámetro"id=123 name=Webhook"

Integración con RLS

Índices recomendados

Para queries rápidas de auditoría:

CREATE INDEX idx_systemlog_org_category_action_ts ON core_systemlog(
    organization_id,
    category,
    action,
    timestamp DESC
);

CREATE INDEX idx_systemlog_org_user_ts ON core_systemlog(
    organization_id,
    user_id,
    timestamp DESC
);

Logging de fallos

Cualquier fallo en log_action() se emite a logging.getLogger("core") con nivel ERROR:

logger.exception("log_action failed (category=%s action=%s)", category, action)

Monitoreo recomendado: Alertar si tasa de “log_action failed” > 0.1% de requests de mutación.

Performance

Versión

Véase también

Subir