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

class src.share_kernel.infrastructure.logging.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é

filter(record: logging.LogRecord) bool

Ajoute les attributs de contexte au record. Retourne toujours True.

Configuration dans settings.py :

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 :

2026-03-23 10:15:30 [INFO] [tenant=acme-corp user=550e8400... cid=a1b2c3...] src.module.tenant.views: Tenant created
src.share_kernel.infrastructure.logging.TENANT_LOG_FORMAT: str

Format de log recommandé pour la sortie structurée.

Observabilité (OpenTelemetry)

Module : src.share_kernel.infrastructure.observability

Toutes les fonctions sont des no-ops si OpenTelemetry n’est pas installé.

src.share_kernel.infrastructure.observability.set_span_tenant_attributes() None

Ajoute les attributs tenant au span OpenTelemetry courant :

  • tenant.id

  • tenant.slug

  • correlation.id

src.share_kernel.infrastructure.observability.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

src.share_kernel.infrastructure.observability.traced_task(func)

Décorateur pour ajouter le traçage OpenTelemetry à une tâche Celery.

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 src.share_kernel.infrastructure.observability.SpanAttributeMiddleware

Middleware Django qui enrichit les spans OpenTelemetry avec le contexte tenant. À placer après TenantMiddleware dans MIDDLEWARE.

MIDDLEWARE = [
    ...
    'src.module.tenant.middleware.TenantMiddleware',
    'src.share_kernel.infrastructure.observability.SpanAttributeMiddleware',
    ...
]

Métriques simples

src.share_kernel.infrastructure.observability.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.

from src.share_kernel.infrastructure.observability import increment_metric

increment_metric("abac.evaluation", {"decision": "allow", "tenant": "acme"})
src.share_kernel.infrastructure.observability.observe_duration(name: str, duration: float, labels: dict | None = None) None

Enregistre une observation de durée.

class src.share_kernel.infrastructure.observability.MeasureDuration

Context manager pour mesurer et enregistrer la durée d’un bloc.

from src.share_kernel.infrastructure.observability import MeasureDuration

with MeasureDuration("abac.evaluation_time", {"engine": "json"}):
    result = evaluate_policies(request)