API Call Logging
Capture every outgoing or third-party API request with header and body redaction, smart truncation, and automatic correlation to the surrounding business transaction.
API call logging records outbound requests to services like payment gateways, shipping APIs, and identity providers. Each log entry captures the service, endpoint, method, headers, bodies, response, duration, and status.
Go Audit never originates HTTP calls itself. You call your
third-party API as usual, then hand the request/response to
auditor.API().Record(...).
Setup
Enable it on the auditor config:
auditor, err := audit.New(sqlDB, audit.Config{
Dialect: audit.PostgreSQL,
APIAudit: audit.APIAuditConfig{
Enabled: true,
RedactHeaders: []string{"Authorization", "X-API-Key"},
RedactBodyFields: []string{"password", "card_number", "cvv"},
MaxBodySize: 64 * 1024, // default is 4096 bytes
},
})Then run auditor.AutoMigrate(ctx) — it creates the audit_api_logs
table alongside audit_logs.
Recording an API Call
start := time.Now()
resp, err := httpClient.Do(req)
duration := time.Since(start)
reqHeaders := flatten(req.Header)
respHeaders := flatten(resp.Header)
_ = auditor.API().Record(ctx, audit.APIEntry{
Service: "bca",
Endpoint: "/v1/transfer",
Method: http.MethodPost,
StatusCode: resp.StatusCode,
RequestHeaders: reqHeaders,
ResponseHeaders: respHeaders,
RequestBody: reqBody,
ResponseBody: respBody,
DurationMs: int(duration.Milliseconds()),
})RequestHeaders and ResponseHeaders are both map[string]string
and share the same RedactHeaders list. RequestBody and
ResponseBody are any — structs, pointers, and maps all work
because the auditor normalizes them through encoding/json before
redaction.
Auto Redaction
Any header whose key matches RedactHeaders (case-insensitive) is
replaced with "***REDACTED***". Any body field whose key matches
RedactBodyFields (case-insensitive, at any depth in a JSON tree) is
replaced the same way.
{
"request_headers": {
"Authorization": "***REDACTED***",
"Content-Type": "application/json"
},
"response_headers": {
"Set-Cookie": "***REDACTED***",
"Content-Type": "application/json"
},
"request_body": {
"card_number": "***REDACTED***",
"amount": 100000
}
}The redaction is symmetric — it applies to request and response
headers (via RedactHeaders) and request and response bodies
(via RedactBodyFields).
Body Truncation
Bodies larger than MaxBodySize (default 4096 bytes) are replaced
with a truncation marker so you can distinguish truncated payloads
from short ones:
{
"_truncated": true,
"original_size": 128512,
"preview": "{\"items\":[{\"id\":1,\"name\":\"…"
}The preview is the first MaxBodySize bytes, rewound to the nearest
valid UTF-8 rune boundary.
Linking to Data Changes
Pass a transaction ID through the context and Go Audit stamps it on both data audit rows and API call rows:
txID := audit.NewTransactionID()
ctx = audit.WithTransactionID(ctx, txID)
// every data + API log on this ctx shares txIDQuery the full story with
QueryByTransaction.