===================================== Logging et Observabilité ===================================== Le module de logging injecte automatiquement le contexte tenant dans chaque enregistrement de log. Le module d'observabilité enrichit les spans OpenTelemetry. Logging Structuré ================= Module : ``src.share_kernel.infrastructure.logging`` .. module:: src.share_kernel.infrastructure.logging :synopsis: Filtre de logging avec contexte tenant .. class:: TenantContextFilter(logging.Filter) Filtre de logging qui injecte les attributs tenant et utilisateur dans chaque ``LogRecord``. Attributs injectés : - ``tenant_id`` : UUID du tenant courant - ``tenant_slug`` : Slug du tenant courant - ``user_id`` : UUID de l'utilisateur courant - ``correlation_id`` : ID de corrélation pour le traçage distribué .. method:: filter(record: logging.LogRecord) -> bool Ajoute les attributs de contexte au record. Retourne toujours ``True``. **Configuration dans settings.py :** .. code-block:: python LOGGING = { 'version': 1, 'filters': { 'tenant_context': { '()': 'src.share_kernel.infrastructure.logging.TenantContextFilter', }, }, 'formatters': { 'tenant': { 'format': '%(asctime)s [%(levelname)s] ' '[tenant=%(tenant_slug)s user=%(user_id)s ' 'cid=%(correlation_id)s] %(name)s: %(message)s', }, }, 'handlers': { 'console': { 'class': 'logging.StreamHandler', 'formatter': 'tenant', 'filters': ['tenant_context'], }, }, 'root': { 'handlers': ['console'], 'level': 'INFO', }, } **Sortie exemple :** .. code-block:: text 2026-03-23 10:15:30 [INFO] [tenant=acme-corp user=550e8400... cid=a1b2c3...] src.module.tenant.views: Tenant created .. data:: TENANT_LOG_FORMAT :type: str Format de log recommandé pour la sortie structurée. Observabilité (OpenTelemetry) ============================== Module : ``src.share_kernel.infrastructure.observability`` .. module:: src.share_kernel.infrastructure.observability :synopsis: Enrichissement des spans OpenTelemetry et métriques Toutes les fonctions sont des no-ops si OpenTelemetry n'est pas installé. .. function:: set_span_tenant_attributes() -> None Ajoute les attributs tenant au span OpenTelemetry courant : - ``tenant.id`` - ``tenant.slug`` - ``correlation.id`` .. function:: set_span_abac_attributes(decision: str, policy_id: str | None = None) -> None Ajoute les attributs d'évaluation ABAC au span courant : - ``abac.decision`` - ``abac.policy_id`` .. function:: traced_task(func) Décorateur pour ajouter le traçage OpenTelemetry à une tâche Celery. .. code-block:: python from src.share_kernel.infrastructure.observability import traced_task @traced_task def process_order(order_id): # Un span "celery.process_order" est créé automatiquement ... .. class:: SpanAttributeMiddleware Middleware Django qui enrichit les spans OpenTelemetry avec le contexte tenant. À placer **après** ``TenantMiddleware`` dans ``MIDDLEWARE``. .. code-block:: python MIDDLEWARE = [ ... 'src.module.tenant.middleware.TenantMiddleware', 'src.share_kernel.infrastructure.observability.SpanAttributeMiddleware', ... ] Métriques simples ================= .. function:: increment_metric(name: str, labels: dict | None = None) -> None Incrémente un compteur simple. Les données sont loggées de manière structurée. .. code-block:: python from src.share_kernel.infrastructure.observability import increment_metric increment_metric("abac.evaluation", {"decision": "allow", "tenant": "acme"}) .. function:: observe_duration(name: str, duration: float, labels: dict | None = None) -> None Enregistre une observation de durée. .. class:: MeasureDuration Context manager pour mesurer et enregistrer la durée d'un bloc. .. code-block:: python from src.share_kernel.infrastructure.observability import MeasureDuration with MeasureDuration("abac.evaluation_time", {"engine": "json"}): result = evaluate_policies(request)