179 lines
5.8 KiB
Go
179 lines
5.8 KiB
Go
package ledger
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
|
)
|
|
|
|
type journalEntryType string
|
|
|
|
const (
|
|
journalEntryTypeCredit journalEntryType = "credit"
|
|
journalEntryTypeDebit journalEntryType = "debit"
|
|
journalEntryTypeTransfer journalEntryType = "transfer"
|
|
journalEntryTypeFX journalEntryType = "fx"
|
|
)
|
|
|
|
type journalEntryStatus string
|
|
|
|
const (
|
|
journalEntryStatusAttempted journalEntryStatus = "attempted"
|
|
journalEntryStatusSuccess journalEntryStatus = "success"
|
|
journalEntryStatusError journalEntryStatus = "error"
|
|
)
|
|
|
|
type journalEntryErrorType string
|
|
|
|
const (
|
|
journalEntryErrorNotImplemented journalEntryErrorType = "not_implemented"
|
|
journalEntryErrorFailed journalEntryErrorType = "failed"
|
|
journalEntryErrorIdempotencyCheck journalEntryErrorType = "idempotency_check_failed"
|
|
journalEntryErrorAccountResolve journalEntryErrorType = "account_resolve_failed"
|
|
journalEntryErrorAccountInvalid journalEntryErrorType = "account_invalid"
|
|
journalEntryErrorContraResolve journalEntryErrorType = "contra_resolve_failed"
|
|
journalEntryErrorContraMissingID journalEntryErrorType = "contra_missing_id"
|
|
journalEntryErrorSystemAccountResolve journalEntryErrorType = "system_account_resolve_failed"
|
|
journalEntryErrorSystemAccountInvalid journalEntryErrorType = "system_account_invalid"
|
|
journalEntryErrorSystemAccountMissing journalEntryErrorType = "system_account_missing_id"
|
|
journalEntryErrorUnbalancedAfterContra journalEntryErrorType = "unbalanced_after_contra"
|
|
journalEntryErrorTransactionFailed journalEntryErrorType = "transaction_failed"
|
|
)
|
|
|
|
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 journalEntryType, status journalEntryStatus, durationSeconds float64) {
|
|
initMetrics()
|
|
journalEntriesTotal.WithLabelValues(string(entryType), string(status)).Inc()
|
|
journalEntryLatency.WithLabelValues(string(entryType)).Observe(durationSeconds)
|
|
}
|
|
|
|
func recordJournalEntryError(entryType journalEntryType, errorType journalEntryErrorType) {
|
|
initMetrics()
|
|
journalEntryErrors.WithLabelValues(string(entryType), string(errorType)).Inc()
|
|
journalEntriesTotal.WithLabelValues(string(entryType), string(journalEntryStatusError)).Inc()
|
|
}
|
|
|
|
func recordBalanceQuery(status string, durationSeconds float64) {
|
|
initMetrics()
|
|
balanceQueriesTotal.WithLabelValues(status).Inc()
|
|
balanceQueryLatency.WithLabelValues(status).Observe(durationSeconds)
|
|
}
|
|
|
|
func recordTransactionAmount(currency string, entryType journalEntryType, amount float64) {
|
|
initMetrics()
|
|
transactionAmounts.WithLabelValues(currency, string(entryType)).Observe(amount)
|
|
}
|
|
|
|
func recordAccountOperation(operation, status string) {
|
|
initMetrics()
|
|
accountOperationsTotal.WithLabelValues(operation, status).Inc()
|
|
}
|
|
|
|
func recordDuplicateRequest(entryType journalEntryType) {
|
|
initMetrics()
|
|
duplicateRequestsTotal.WithLabelValues(string(entryType)).Inc()
|
|
}
|