Examples
API Call Logging Example
Track a BCA payment call alongside the order data change.
This example shows a payment flow where a BCA API call and an order
update are linked via a shared transaction_id.
Complete Code
package main
import (
"bytes"
"context"
"encoding/json"
"io"
"log"
"net/http"
"time"
"github.com/gopackx/go-audit"
auditgorm "github.com/gopackx/go-audit/adapters/gorm"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Order struct {
ID uint `gorm:"primaryKey"`
Amount int
Status string
PaymentRef string
}
func main() {
gormDB, err := gorm.Open(postgres.Open("..."), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
sqlDB, err := gormDB.DB()
if err != nil {
log.Fatal(err)
}
auditor, err := audit.New(sqlDB, audit.Config{
Dialect: audit.PostgreSQL,
UserFunc: func(ctx context.Context) (string, string) {
return "user-42", "user"
},
DataAudit: audit.DataAuditConfig{Enabled: true},
APIAudit: audit.APIAuditConfig{
Enabled: true,
RedactHeaders: []string{"Authorization"},
RedactBodyFields: []string{"card_number", "cvv"},
MaxBodySize: 64 * 1024,
},
})
if err != nil {
log.Fatal(err)
}
_ = gormDB.Use(auditgorm.Plugin(auditor))
_ = auditor.AutoMigrate(context.Background())
_ = gormDB.AutoMigrate(&Order{})
order := Order{Amount: 100000, Status: "pending"}
gormDB.Create(&order)
txID := audit.NewTransactionID()
ctx := audit.WithTransactionID(context.Background(), txID)
tx := gormDB.WithContext(ctx)
// Outbound API call to BCA
reqBody, _ := json.Marshal(map[string]any{"amount": order.Amount})
req, _ := http.NewRequestWithContext(ctx,
http.MethodPost,
"https://api.bca.co.id/v1/transfer",
bytes.NewReader(reqBody),
)
req.Header.Set("Authorization", "Bearer secret")
req.Header.Set("Content-Type", "application/json")
headers := map[string]string{}
for k, v := range req.Header {
if len(v) > 0 {
headers[k] = v[0]
}
}
start := time.Now()
resp, err := http.DefaultClient.Do(req)
duration := time.Since(start)
var respPayload map[string]any
if resp != nil {
body, _ := io.ReadAll(resp.Body)
_ = json.Unmarshal(body, &respPayload)
}
_ = auditor.API().Record(ctx, audit.APIEntry{
Service: "bca",
Endpoint: "/v1/transfer",
Method: http.MethodPost,
StatusCode: statusCode(resp),
RequestHeaders: headers,
RequestBody: map[string]any{"amount": order.Amount},
ResponseBody: respPayload,
DurationMs: int(duration.Milliseconds()),
ErrorMessage: errString(err),
})
// Update the order to reflect the payment outcome
ref, _ := respPayload["reference"].(string)
tx.Model(&order).Updates(map[string]any{
"payment_ref": ref,
"status": "paid",
})
// Fetch the full transaction trail
trail, _ := auditor.QueryByTransaction(ctx, txID)
_ = trail // contains both DataLogs and APILogs
}statusCode and errString are trivial helpers — return 0 / "" when
the input is nil.
What You Get
audit_logshas one row for the order update with the newpayment_refandstatus.audit_api_logshas one row for the BCA call with theAuthorizationheader replaced by"***REDACTED***"and the full response body (or a truncation marker if it exceededMaxBodySize).- Both rows share the same
transaction_id.
Next
See the full example for a multi-step flow with several API calls.