feat(observabillity): #115 integrate otel for metrics and traces
All checks were successful
Build Docker Image / Build-Docker-Image (push) Successful in 5m51s
Build and Push Docker Image / Build-And-Push-Docker-Image (push) Successful in 5m46s

This commit was merged in pull request #152.
This commit is contained in:
2025-06-07 12:18:41 +02:00
parent b336b65532
commit 3e7251ef9d
32 changed files with 480 additions and 314 deletions

View File

@@ -11,18 +11,6 @@ import (
"github.com/google/uuid"
"github.com/jmoiron/sqlx"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
var (
transactionRecurringMetric = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "spendsparrow_transaction_recurring_total",
Help: "The total of transactionRecurring operations",
},
[]string{"operation"},
)
)
type TransactionRecurring interface {
@@ -54,9 +42,8 @@ func NewTransactionRecurring(db *sqlx.DB, random Random, clock Clock, transactio
func (s TransactionRecurringImpl) Add(
user *types.User,
transactionRecurringInput types.TransactionRecurringInput) (*types.TransactionRecurring, error) {
transactionRecurringMetric.WithLabelValues("add").Inc()
transactionRecurringInput types.TransactionRecurringInput,
) (*types.TransactionRecurring, error) {
if user == nil {
return nil, ErrUnauthorized
}
@@ -97,14 +84,14 @@ func (s TransactionRecurringImpl) Add(
func (s TransactionRecurringImpl) Update(
user *types.User,
input types.TransactionRecurringInput) (*types.TransactionRecurring, error) {
transactionRecurringMetric.WithLabelValues("update").Inc()
input types.TransactionRecurringInput,
) (*types.TransactionRecurring, error) {
if user == nil {
return nil, ErrUnauthorized
}
uuid, err := uuid.Parse(input.Id)
if err != nil {
log.Error("transactionRecurring update: %v", err)
log.L.Error("transactionRecurring update", "err", err)
return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest)
}
@@ -161,7 +148,6 @@ func (s TransactionRecurringImpl) Update(
}
func (s TransactionRecurringImpl) GetAll(user *types.User) ([]*types.TransactionRecurring, error) {
transactionRecurringMetric.WithLabelValues("get_all_by_account").Inc()
if user == nil {
return nil, ErrUnauthorized
}
@@ -182,14 +168,13 @@ func (s TransactionRecurringImpl) GetAll(user *types.User) ([]*types.Transaction
}
func (s TransactionRecurringImpl) GetAllByAccount(user *types.User, accountId string) ([]*types.TransactionRecurring, error) {
transactionRecurringMetric.WithLabelValues("get_all_by_account").Inc()
if user == nil {
return nil, ErrUnauthorized
}
accountUuid, err := uuid.Parse(accountId)
if err != nil {
log.Error("transactionRecurring GetAllByAccount: %v", err)
log.L.Error("transactionRecurring GetAllByAccount", "err", err)
return nil, fmt.Errorf("could not parse accountId: %w", ErrBadRequest)
}
@@ -234,15 +219,17 @@ func (s TransactionRecurringImpl) GetAllByAccount(user *types.User, accountId st
return transactionRecurrings, nil
}
func (s TransactionRecurringImpl) GetAllByTreasureChest(user *types.User, treasureChestId string) ([]*types.TransactionRecurring, error) {
transactionRecurringMetric.WithLabelValues("get_all_by_treasurechest").Inc()
func (s TransactionRecurringImpl) GetAllByTreasureChest(
user *types.User,
treasureChestId string,
) ([]*types.TransactionRecurring, error) {
if user == nil {
return nil, ErrUnauthorized
}
treasureChestUuid, err := uuid.Parse(treasureChestId)
if err != nil {
log.Error("transactionRecurring GetAllByTreasureChest: %v", err)
log.L.Error("transactionRecurring GetAllByTreasureChest", "err", err)
return nil, fmt.Errorf("could not parse treasureChestId: %w", ErrBadRequest)
}
@@ -288,13 +275,12 @@ func (s TransactionRecurringImpl) GetAllByTreasureChest(user *types.User, treasu
}
func (s TransactionRecurringImpl) Delete(user *types.User, id string) error {
transactionRecurringMetric.WithLabelValues("delete").Inc()
if user == nil {
return ErrUnauthorized
}
uuid, err := uuid.Parse(id)
if err != nil {
log.Error("transactionRecurring delete: %v", err)
log.L.Error("transactionRecurring delete", "err", err)
return fmt.Errorf("could not parse Id: %w", ErrBadRequest)
}
@@ -389,7 +375,8 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
tx *sqlx.Tx,
oldTransactionRecurring *types.TransactionRecurring,
userId uuid.UUID,
input types.TransactionRecurringInput) (*types.TransactionRecurring, error) {
input types.TransactionRecurringInput,
) (*types.TransactionRecurring, error) {
var (
id uuid.UUID
accountUuid *uuid.UUID
@@ -425,7 +412,7 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
if input.AccountId != "" {
temp, err := uuid.Parse(input.AccountId)
if err != nil {
log.Error("transactionRecurring validate: %v", err)
log.L.Error("transactionRecurring validate", "err", err)
return nil, fmt.Errorf("could not parse accountId: %w", ErrBadRequest)
}
accountUuid = &temp
@@ -435,7 +422,7 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
return nil, err
}
if rowCount == 0 {
log.Error("transactionRecurring validate: %v", err)
log.L.Error("transactionRecurring validate", "err", err)
return nil, fmt.Errorf("account not found: %w", ErrBadRequest)
}
@@ -445,7 +432,7 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
if input.TreasureChestId != "" {
temp, err := uuid.Parse(input.TreasureChestId)
if err != nil {
log.Error("transactionRecurring validate: %v", err)
log.L.Error("transactionRecurring validate", "err", err)
return nil, fmt.Errorf("could not parse treasureChestId: %w", ErrBadRequest)
}
treasureChestUuid = &temp
@@ -465,17 +452,17 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
}
if !hasAccount && !hasTreasureChest {
log.Error("transactionRecurring validate: %v", err)
log.L.Error("transactionRecurring validate", "err", err)
return nil, fmt.Errorf("either account or treasure chest is required: %w", ErrBadRequest)
}
if hasAccount && hasTreasureChest {
log.Error("transactionRecurring validate: %v", err)
log.L.Error("transactionRecurring validate", "err", err)
return nil, fmt.Errorf("either account or treasure chest is required, not both: %w", ErrBadRequest)
}
valueFloat, err := strconv.ParseFloat(input.Value, 64)
if err != nil {
log.Error("transactionRecurring validate: %v", err)
log.L.Error("transactionRecurring validate", "err", err)
return nil, fmt.Errorf("could not parse value: %w", ErrBadRequest)
}
valueInt := int64(valueFloat * DECIMALS_MULTIPLIER)
@@ -494,18 +481,18 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
}
intervalMonths, err = strconv.ParseInt(input.IntervalMonths, 10, 0)
if err != nil {
log.Error("transactionRecurring validate: %v", err)
log.L.Error("transactionRecurring validate", "err", err)
return nil, fmt.Errorf("could not parse intervalMonths: %w", ErrBadRequest)
}
if intervalMonths < 1 {
log.Error("transactionRecurring validate: %v", err)
log.L.Error("transactionRecurring validate", "err", err)
return nil, fmt.Errorf("intervalMonths needs to be greater than 0: %w", ErrBadRequest)
}
var nextExecution *time.Time = nil
if input.NextExecution != "" {
t, err := time.Parse("2006-01-02", input.NextExecution)
if err != nil {
log.Error("transaction validate: %v", err)
log.L.Error("transaction validate", "err", err)
return nil, fmt.Errorf("could not parse timestamp: %w", ErrBadRequest)
}