package db import ( "tercul/internal/observability" "time" "gorm.io/gorm" ) const ( callBackBeforeName = "prometheus:before" callBackAfterName = "prometheus:after" startTime = "start_time" ) type PrometheusPlugin struct { Metrics *observability.Metrics } func (p *PrometheusPlugin) Name() string { return "PrometheusPlugin" } func (p *PrometheusPlugin) Initialize(db *gorm.DB) error { // Before callbacks db.Callback().Create().Before("gorm:create").Register(callBackBeforeName, p.before) db.Callback().Query().Before("gorm:query").Register(callBackBeforeName, p.before) db.Callback().Update().Before("gorm:update").Register(callBackBeforeName, p.before) db.Callback().Delete().Before("gorm:delete").Register(callBackBeforeName, p.before) db.Callback().Row().Before("gorm:row").Register(callBackBeforeName, p.before) db.Callback().Raw().Before("gorm:raw").Register(callBackBeforeName, p.before) // After callbacks db.Callback().Create().After("gorm:create").Register(callBackAfterName, p.after) db.Callback().Query().After("gorm:query").Register(callBackAfterName, p.after) db.Callback().Update().After("gorm:update").Register(callBackAfterName, p.after) db.Callback().Delete().After("gorm:delete").Register(callBackAfterName, p.after) db.Callback().Row().After("gorm:row").Register(callBackAfterName, p.after) db.Callback().Raw().After("gorm:raw").Register(callBackAfterName, p.after) return nil } func (p *PrometheusPlugin) before(db *gorm.DB) { db.Set(startTime, time.Now()) } func (p *PrometheusPlugin) after(db *gorm.DB) { _ts, ok := db.Get(startTime) if !ok { return } ts, ok := _ts.(time.Time) if !ok { return } operation := db.Statement.SQL.String() if len(operation) > 50 { // Truncate long queries operation = operation[:50] } status := "success" if db.Error != nil { status = "error" } duration := time.Since(ts).Seconds() p.Metrics.DBQueryDuration.WithLabelValues(operation, status).Observe(duration) p.Metrics.DBQueriesTotal.WithLabelValues(operation, status).Inc() } func NewPrometheusPlugin(metrics *observability.Metrics) *PrometheusPlugin { return &PrometheusPlugin{Metrics: metrics} }