extended logging + wallet referencing improved #186

Merged
tech merged 1 commits from tron-185 into main 2025-12-26 00:31:34 +00:00
2 changed files with 73 additions and 17 deletions

View File

@@ -14,7 +14,6 @@ import (
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/mservice"
"github.com/tech/sendico/pkg/mutil/mzap"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap"
@@ -100,27 +99,49 @@ func (w *Wallets) Create(ctx context.Context, wallet *model.ManagedWallet) (*mod
if strings.TrimSpace(wallet.IdempotencyKey) == "" {
return nil, merrors.InvalidArgument("walletsStore: empty idempotencyKey")
}
fields := []zap.Field{
zap.String("wallet_ref", wallet.WalletRef),
zap.String("idempotency_key", wallet.IdempotencyKey),
}
if wallet.OrganizationRef != "" {
fields = append(fields, zap.String("organization_ref", wallet.OrganizationRef))
}
if wallet.OwnerRef != "" {
fields = append(fields, zap.String("owner_ref", wallet.OwnerRef))
}
if wallet.Network != "" {
fields = append(fields, zap.String("network", wallet.Network))
}
if wallet.TokenSymbol != "" {
fields = append(fields, zap.String("token_symbol", wallet.TokenSymbol))
}
if err := w.walletRepo.Insert(ctx, wallet, repository.Filter("idempotencyKey", wallet.IdempotencyKey)); err != nil {
if errors.Is(err, merrors.ErrDataConflict) {
w.logger.Debug("wallet already exists", zap.String("wallet_ref", wallet.WalletRef), zap.String("idempotency_key", wallet.IdempotencyKey))
w.logger.Debug("wallet already exists", fields...)
return wallet, nil
}
w.logger.Warn("wallet create failed", append(fields, zap.Error(err))...)
return nil, err
}
w.logger.Debug("wallet created", zap.String("wallet_ref", wallet.WalletRef))
w.logger.Debug("wallet created", fields...)
return wallet, nil
}
func (w *Wallets) Get(ctx context.Context, walletID string) (*model.ManagedWallet, error) {
walletID = strings.TrimSpace(walletID)
walletRef, err := primitive.ObjectIDFromHex(walletID)
if err != nil {
w.logger.Warn("Invalid wallet refernce", zap.Error(err), zap.String("wallet_id", walletID))
return nil, err
if walletID == "" {
return nil, merrors.InvalidArgument("walletsStore: empty walletRef")
}
fields := []zap.Field{
zap.String("wallet_id", walletID),
}
wallet := &model.ManagedWallet{}
if err := w.walletRepo.Get(ctx, walletRef, wallet); err != nil {
w.logger.Warn("Managed wallet not found", zap.Error(err), mzap.ObjRef("wallet_ref", walletRef))
if err := w.balanceRepo.FindOneByFilter(ctx, repository.Filter("walletRef", walletID), wallet); err != nil {
if errors.Is(err, merrors.ErrNoData) {
w.logger.Debug("wallet not found", fields...)
} else {
w.logger.Warn("wallet lookup failed", append(fields, zap.Error(err))...)
}
return nil, err
}
return wallet, nil
@@ -128,29 +149,38 @@ func (w *Wallets) Get(ctx context.Context, walletID string) (*model.ManagedWalle
func (w *Wallets) List(ctx context.Context, filter model.ManagedWalletFilter) (*model.ManagedWalletList, error) {
query := repository.Query()
fields := make([]zap.Field, 0, 6)
if org := strings.TrimSpace(filter.OrganizationRef); org != "" {
query = query.Filter(repository.Field("organizationRef"), org)
fields = append(fields, zap.String("organization_ref", org))
}
if owner := strings.TrimSpace(filter.OwnerRef); owner != "" {
query = query.Filter(repository.Field("ownerRef"), owner)
fields = append(fields, zap.String("owner_ref", owner))
}
if network := strings.TrimSpace(filter.Network); network != "" {
query = query.Filter(repository.Field("network"), strings.ToLower(network))
normalized := strings.ToLower(network)
query = query.Filter(repository.Field("network"), normalized)
fields = append(fields, zap.String("network", normalized))
}
if token := strings.TrimSpace(filter.TokenSymbol); token != "" {
query = query.Filter(repository.Field("tokenSymbol"), strings.ToUpper(token))
normalized := strings.ToUpper(token)
query = query.Filter(repository.Field("tokenSymbol"), normalized)
fields = append(fields, zap.String("token_symbol", normalized))
}
if cursor := strings.TrimSpace(filter.Cursor); cursor != "" {
if oid, err := primitive.ObjectIDFromHex(cursor); err == nil {
query = query.Comparison(repository.IDField(), builder.Gt, oid)
fields = append(fields, zap.String("cursor", cursor))
} else {
w.logger.Warn("Ignoring invalid wallet cursor", zap.String("cursor", cursor), zap.Error(err))
w.logger.Warn("ignoring invalid wallet cursor", zap.String("cursor", cursor), zap.Error(err))
}
}
limit := sanitizeWalletLimit(filter.Limit)
fields = append(fields, zap.Int64("limit", limit))
fetchLimit := limit + 1
query = query.Sort(repository.IDField(), true).Limit(&fetchLimit)
@@ -164,8 +194,10 @@ func (w *Wallets) List(ctx context.Context, filter model.ManagedWalletFilter) (*
return nil
}
if err := w.walletRepo.FindManyByFilter(ctx, query, decoder); err != nil && !errors.Is(err, merrors.ErrNoData) {
return nil, err
listErr := w.walletRepo.FindManyByFilter(ctx, query, decoder)
if listErr != nil && !errors.Is(listErr, merrors.ErrNoData) {
w.logger.Warn("wallet list failed", append(fields, zap.Error(listErr))...)
return nil, listErr
}
nextCursor := ""
@@ -175,10 +207,21 @@ func (w *Wallets) List(ctx context.Context, filter model.ManagedWalletFilter) (*
wallets = wallets[:len(wallets)-1]
}
return &model.ManagedWalletList{
result := &model.ManagedWalletList{
Items: wallets,
NextCursor: nextCursor,
}, nil
}
fields = append(fields,
zap.Int("count", len(result.Items)),
zap.String("next_cursor", result.NextCursor),
)
if errors.Is(listErr, merrors.ErrNoData) {
w.logger.Debug("wallet list empty", fields...)
} else {
w.logger.Debug("wallet list fetched", fields...)
}
return result, nil
}
func (w *Wallets) SaveBalance(ctx context.Context, balance *model.WalletBalance) error {
@@ -192,6 +235,7 @@ func (w *Wallets) SaveBalance(ctx context.Context, balance *model.WalletBalance)
if balance.CalculatedAt.IsZero() {
balance.CalculatedAt = time.Now().UTC()
}
fields := []zap.Field{zap.String("wallet_ref", balance.WalletRef)}
existing := &model.WalletBalance{}
err := w.balanceRepo.FindOneByFilter(ctx, repository.Filter("walletRef", balance.WalletRef), existing)
@@ -202,15 +246,20 @@ func (w *Wallets) SaveBalance(ctx context.Context, balance *model.WalletBalance)
existing.PendingOutbound = balance.PendingOutbound
existing.CalculatedAt = balance.CalculatedAt
if err := w.balanceRepo.Update(ctx, existing); err != nil {
w.logger.Warn("wallet balance update failed", append(fields, zap.Error(err))...)
return err
}
w.logger.Debug("wallet balance updated", fields...)
return nil
case errors.Is(err, merrors.ErrNoData):
if err := w.balanceRepo.Insert(ctx, balance, repository.Filter("walletRef", balance.WalletRef)); err != nil {
w.logger.Warn("wallet balance create failed", append(fields, zap.Error(err))...)
return err
}
w.logger.Debug("wallet balance created", fields...)
return nil
default:
w.logger.Warn("wallet balance lookup failed", append(fields, zap.Error(err))...)
return err
}
}
@@ -220,10 +269,17 @@ func (w *Wallets) GetBalance(ctx context.Context, walletID string) (*model.Walle
if walletID == "" {
return nil, merrors.InvalidArgument("walletsStore: empty walletRef")
}
fields := []zap.Field{zap.String("wallet_ref", walletID)}
balance := &model.WalletBalance{}
if err := w.balanceRepo.FindOneByFilter(ctx, repository.Filter("walletRef", walletID), balance); err != nil {
if errors.Is(err, merrors.ErrNoData) {
w.logger.Debug("wallet balance not found", fields...)
} else {
w.logger.Warn("wallet balance lookup failed", append(fields, zap.Error(err))...)
}
return nil, err
}
w.logger.Debug("wallet balance fetched", fields...)
return balance, nil
}

View File

@@ -66,7 +66,7 @@ oracle:
card_gateways:
monetix:
funding_address: "TGBDXEg9rxSqGFJDcb889zqTjDwx1bmLRF"
fee_wallet_ref: "694c124fd76f9f811ac57134"
fee_wallet_ref: "694c124ed76f9f811ac57133"
fee_ledger_accounts:
monetix: "ledger:fees:monetix"