dbt: monitoring ou observabilité externe

J’abordes ici une pratique très professionnelle pour intégrer dbt à un système de monitoring ou observabilité externe, tout en assurant fiabilité, scalabilité, et non-blocage.


🎯 Objectif

Tu veux suivre l’activité dbt (succès, échecs, durées, modèles exécutés…) dans un système externe :

  • Datadog
  • Prometheus / Grafana
  • Sentry
  • ELK stack
  • ou même ton propre backend ou pipeline Kafka

Mais tu veux le faire fiablement, même si ce système externe tombe, sans bloquer dbt run.


✅ Solution :

Combiner un hook on-run-end avec une file de messages (message queue)
→ Pour capturer les événements dbt asynchrone et sans perte.


🧱 Architecture visuelle

               dbt run
                  |
          ┌───────▼────────┐
          │ on-run-end hook│
          └───────┬────────┘
                  ▼
      ┌────────────────────┐
      │ Message Queue (MQ) │  ⟶ Kafka / RabbitMQ / SQS / PubSub / Redis
      └────────────────────┘
                  ▼
       ┌────────────────────┐
       │ Monitoring Consumer│  ⟶ Insertion dans Datadog, logs, alertes...
       └────────────────────┘

⚙️ Étapes détaillées

1. Utiliser un hook dbt : on-run-end

Dans dbt_project.yml :

on-run-end:
  - "{{ log_run_summary() }}"

Mais ici, on veut faire plus que logger : on veut envoyer un message structuré à une file (queue).


2. Créer une macro log_run_summary

Exemple simple :

-- macros/log_run_summary.sql

{% macro log_run_summary() %}
  {% set summary = {
      "event": "dbt_run_end",
      "project": target.name,
      "env": target.schema,
      "user": target.user,
      "run_started_at": run_started_at,
      "run_completed_at": modules.datetime.now().isoformat(),
      "status": invocation_status,
      "elapsed": run_elapsed_time
  } %}

  -- Simulation : log json localement
  {% do log(tojson(summary), info=True) %}

  -- Envoi vers la file de messages (si activé)
  {% if var('enable_event_queue', false) %}
    {% set json = tojson(summary) %}
    {% do run_query("call push_to_queue('" ~ json ~ "')") %}
  {% endif %}
{% endmacro %}

3. Tu relies cela à une UDF SQL ou fonction externe push_to_queue

  • Ça peut être un HTTP UDF dans BigQuery
  • Ou un wrapper sur un pubsub/sqs/kafka dans Databricks/Snowflake
  • Ou un service REST qui accepte des POST depuis un curl déclenché par dbt

4. Pourquoi une file de messages ?

Sans MQAvec MQ
En cas d’erreur réseau → événement perduBufferisé, il sera traité quand dispo
Bloque potentiellement dbt runNe bloque pas → asynchrone
Pas de rétention / redeliveryMQ gère la durabilité et la reprise
Dépendance forte à l’externeMQ isole dbt des outils downstream

🧪 Exemple d’event JSON structuré

{
  "event": "dbt_run_end",
  "project": "mon_projet",
  "status": "success",
  "elapsed": 132.54,
  "models_run": 42,
  "env": "prod",
  "timestamp": "2025-06-16T09:00:12Z"
}

🧼 Avantages de cette approche

BénéficeDétail
🔄 RésilientLes événements ne sont pas perdus même si le système externe plante
📤 AsynchroneLe dbt run n’attend pas l’upload — il pousse dans une file
🧘 Non-bloquantPas d’impact sur la durée ou stabilité du dbt run
🔎 Observabilité claireTu peux tracer par modèle, par projet, par environnement
📁 Standard industrielMQ est une brique clé dans toute architecture data fiable

Leave a Reply

Your email address will not be published. Required fields are marked *