dbt: Pre-hook + post-hook vs LogHandler personnalisé

🎯 Objectif

Suivre qui a exécuté quoi, quand, avec quels résultats et combien de temps cela a pris.

Cela permet de :

  • faire de l’audit trail (traçabilité réglementaire)
  • surveiller la performance des modèles
  • suivre les modifications exécutées par utilisateur ou pipeline

✅ Solution proposée : pre-hook + post-hook + LogHandler personnalisé


🧱 Étape 1 – Définir un LogHandler custom (dans un fichier .py si tu développes un plugin)

👉 dbt permet aux adapters personnalisés ou aux environnements dbt-core avancés de rediriger les logs avec leur propre LogHandler.

⚠️ Ceci n’est pas possible directement dans un projet dbt classique en YAML pur, mais c’est très courant dans les entreprises qui utilisent dbt comme brique intégrée dans un framework Python.

Exemple d’un LogHandler (dans un projet plugin) :

import logging
import datetime

class CustomAuditLogHandler(logging.Handler):
    def emit(self, record):
        log_entry = self.format(record)
        with open("/logs/dbt_audit.log", "a") as f:
            f.write(f"{datetime.datetime.now()} - {log_entry}\n")

🧱 Étape 2 – Utiliser des pre-hook et post-hook dans le dbt_project.yml ou le modèle

models:
  my_project:
    mart:
      +pre-hook:
        - "{{ log_start('mart_clients') }}"
      +post-hook:
        - "{{ log_end('mart_clients') }}"

Et tu crées une macro dans macros/logging.sql :

{% macro log_start(model_name) %}
    insert into audit_logs(model, event, timestamp, user)
    values ('{{ model_name }}', 'start', current_timestamp, '{{ target.user }}')
{% endmacro %}

{% macro log_end(model_name) %}
    insert into audit_logs(model, event, timestamp, user)
    values ('{{ model_name }}', 'end', current_timestamp, '{{ target.user }}')
{% endmacro %}

💡 Que permet cette méthode ?

  • pre-hook → enregistre le début de l’exécution
  • post-hook → enregistre la fin
  • tu peux enrichir avec :
    • execution_time
    • target.environment
    • status (via run_results.json)
    • row_count, etc.

🔐 Bonus : on peut auditer par utilisateur ou par contexte

insert into audit_logs(model, event, timestamp, user, environment)
values (
  '{{ this.name }}',
  'start',
  current_timestamp,
  '{{ target.user }}',
  '{{ target.name }}'
)

✅ Résumé

ÉlémentRôle
pre-hookJournalise le début d’un modèle
post-hookJournalise la fin
LogHandler personnaliséPermet de formater ou rediriger les logs (fichier, S3, table, Kafka…)
Audit table (optionnel)Pour stocker les logs dans une table relationnelle
Utilisable avecdbt-core + macros, ou plugin Python personnalisé

“using a custom LogHandler with pre_hook and post_hook implementation”
est ambiguë et même trompeuse si on la comprend littéralement dans le contexte d’un projet dbt standard.


✅ Voici la vérité technique claire :

pre-hook / post-hook :

  • sont exécutés dans le SQL (via macros)
  • te permettent de logguer dans une table (audit trail dans BigQuery, Snowflake…)
  • sont 100% utilisables dans dbt-core / dbt Cloud

Custom LogHandler (en Python) :

  • s’utilise uniquement si tu développes un outil Python autour ou au-dessus de dbt
  • te permet de rediriger les logs Python de dbt vers un fichier, un endpoint, ou autre
  • ne peut pas être combiné directement avec des pre-hook SQL, car ils n’exécutent pas de code Python

❌ Ce qui est faux (ou mal formulé) dans la phrase

La phrase dit :

“using a custom LogHandler with pre_hook and post_hook implementation”

Or :

  • pre-hook et post-hook sont du SQL exécuté dans le warehouse
  • LogHandler est un objet Python attaché au logger dbt (dans le code source Python, pas dans le projet YAML)

👉 Il n’y a pas d’interaction directe entre les deux dans un projet dbt normal.


✅ Donc, deux scénarios bien distincts

1. Projet dbt classique (core ou cloud)

➡️ Tu utilises pre-hook / post-hook + macros pour insérer des logs dans une table d’audit SQL

+post-hook: ["{{ log_audit_end('fact_ventes') }}"]
-- dans macros/log_audit.sql
{% macro log_audit_end(model_name) %}
insert into logs_audit (model, event, user, timestamp)
values ('{{ model_name }}', 'end', '{{ target.user }}', current_timestamp)
{% endmacro %}

2. Outil Python qui pilote dbt (ex: Airflow, CLI wrapper, SDK)

➡️ Tu branches un LogHandler Python personnalisé pour logger en dehors de dbt

from dbt.logger import GLOBAL_LOGGER as logger
logger.addHandler(CustomAuditLogHandler())

Tu peux ensuite observer tous les logs de dbt comme :

2024-06-17 12:30:12 | Running model mart.ventes ...

✅ Conclusion

La phrase peut prêter à confusion.
Il serait plus juste de la reformuler ainsi :

🟩 Version corrigée :

For comprehensive audit tracking in dbt, combining SQL-based pre_hook and post_hook macros with a custom Python LogHandler (in adapter or orchestration layers) provides the most flexible and complete approach.
While hooks allow tracking inside the data warehouse, a LogHandler offers control over external logging and orchestration context.


Leave a Reply

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