package ledger import ( "sync" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) var ( metricsOnce sync.Once // Journal entry operations journalEntriesTotal *prometheus.CounterVec journalEntryLatency *prometheus.HistogramVec journalEntryErrors *prometheus.CounterVec // Balance operations balanceQueriesTotal *prometheus.CounterVec balanceQueryLatency *prometheus.HistogramVec // Transaction amounts transactionAmounts *prometheus.HistogramVec // Account operations accountOperationsTotal *prometheus.CounterVec // Idempotency duplicateRequestsTotal *prometheus.CounterVec ) func initMetrics() { metricsOnce.Do(func() { // Journal entries posted by type journalEntriesTotal = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "ledger_journal_entries_total", Help: "Total number of journal entries posted to the ledger", }, []string{"entry_type", "status"}, // entry_type: credit, debit, transfer, fx, fee, adjust, reverse ) // Journal entry processing latency journalEntryLatency = promauto.NewHistogramVec( prometheus.HistogramOpts{ Name: "ledger_journal_entry_duration_seconds", Help: "Duration of journal entry posting operations", Buckets: []float64{.001, .005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}, }, []string{"entry_type"}, ) // Journal entry errors by type journalEntryErrors = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "ledger_journal_entry_errors_total", Help: "Total number of journal entry posting errors", }, []string{"entry_type", "error_type"}, // error_type: validation, insufficient_funds, db_error, etc. ) // Balance queries balanceQueriesTotal = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "ledger_balance_queries_total", Help: "Total number of balance queries", }, []string{"status"}, // success, error ) // Balance query latency balanceQueryLatency = promauto.NewHistogramVec( prometheus.HistogramOpts{ Name: "ledger_balance_query_duration_seconds", Help: "Duration of balance query operations", Buckets: prometheus.DefBuckets, }, []string{"status"}, ) // Transaction amounts (in normalized form) transactionAmounts = promauto.NewHistogramVec( prometheus.HistogramOpts{ Name: "ledger_transaction_amount", Help: "Distribution of transaction amounts", Buckets: []float64{1, 10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000}, }, []string{"currency", "entry_type"}, ) // Account operations accountOperationsTotal = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "ledger_account_operations_total", Help: "Total number of account-level operations", }, []string{"operation", "status"}, // operation: create, freeze, unfreeze ) // Duplicate/idempotent requests duplicateRequestsTotal = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "ledger_duplicate_requests_total", Help: "Total number of duplicate requests detected via idempotency keys", }, []string{"entry_type"}, ) }) } // Metric recording helpers func recordJournalEntry(entryType, status string, durationSeconds float64) { initMetrics() journalEntriesTotal.WithLabelValues(entryType, status).Inc() journalEntryLatency.WithLabelValues(entryType).Observe(durationSeconds) } func recordJournalEntryError(entryType, errorType string) { initMetrics() journalEntryErrors.WithLabelValues(entryType, errorType).Inc() journalEntriesTotal.WithLabelValues(entryType, "error").Inc() } func recordBalanceQuery(status string, durationSeconds float64) { initMetrics() balanceQueriesTotal.WithLabelValues(status).Inc() balanceQueryLatency.WithLabelValues(status).Observe(durationSeconds) } func recordTransactionAmount(currency, entryType string, amount float64) { initMetrics() transactionAmounts.WithLabelValues(currency, entryType).Observe(amount) } func recordAccountOperation(operation, status string) { initMetrics() accountOperationsTotal.WithLabelValues(operation, status).Inc() } func recordDuplicateRequest(entryType string) { initMetrics() duplicateRequestsTotal.WithLabelValues(entryType).Inc() }