$ whoami go-utils
go-utils
Go utility library for AWS microservices — structured logging with trace correlation, typed errors, a resilient HTTP client, RS256 JWT, Postgres/Redis/S3 adapters and SQS/SNS/EventBridge messaging. Observability-first, config-from-env, interface-driven.
$ cat ~/principles.md #
Observability-first
Every package emits OpenTelemetry spans, and the logger injects trace_id/span_id from the context into every line — logs and traces correlate out of the box.
Config from env
Every adapter has ConfigFromEnv(prefix). Same shape everywhere — DB_*, REDIS_*, SQS_* — so wiring a service is boilerplate-free and 12-factor by default.
Interface-driven
Each package exposes an interface with an unexported implementation. Depend on the interface, mock it in tests, swap the backend without touching callers.
$ cat ~/install.md #
// v2+ carries the /v2 suffix (Go semantic import versioning)
$ go get github.com/juanMaAV92/go-utils/v2
// import a package
import "github.com/juanMaAV92/go-utils/v2/logger" # Public module — no auth needed. Requires Go 1.25+. AWS clients use the standard credential chain (env, shared config, IAM role); no hardcoded credentials.
$ go list ./... 18 pkgs #
▸ logger Structured JSON#
Flat JSON to stdout on top of slog. When a span is active, trace_id and span_id are injected automatically — no manual plumbing.
// Create once at startup
log := logger.New("payments-api", env.GetEnvironment())
// context-first — trace_id/span_id are pulled from the active span
log.Info(ctx, "process_payment", "payment captured",
"amount", 50000, "currency", "COP") Output:
{"time":"2026-03-22T10:15:30.12Z","level":"INFO","service":"payments-api","step":"process_payment","message":"payment captured","trace_id":"4bf9...","span_id":"00f0...","amount":50000,"currency":"COP"} ▸ errors Typed + Echo#
A single ErrorResponse type with HTTP code, error code and messages. Predefined constructors for every status, plus a drop-in Echo handler.
// Typed, predefined errors
return errors.ErrNotFound()
return errors.ErrBadRequest().WithMessage("email is required")
// Fully custom
return errors.New(http.StatusConflict, "CONFLICT", []string{"already exists"})
// Wire the Echo handler once — maps *ErrorResponse to the right status + JSON
e.HTTPErrorHandler = echoerr.HTTPErrorHandler ▸ httpclient Resilient client#
Resty-based client with retries, timeouts and W3C trace propagation. Request/response bodies are never logged — only metadata — so credentials and tokens don't leak.
c := httpclient.New(log,
httpclient.WithBaseURL("https://api.example.com"),
httpclient.WithRetryCount(3),
httpclient.WithServiceName("billing"),
)
// W3C trace context is injected automatically; bodies are never logged
resp, err := c.Post(ctx, "/invoices", invoice)
var out Invoice
_ = resp.JSON(&out) ▸ security/jwt RS256#
Generic RS256 signing and validation over any claims struct. Validation enforces RS256 only, requires exp, and checks the issuer — closing the classic algorithm-substitution and never-expiring-token gaps.
svc, _ := jwt.New(privatePEM, publicPEM, "auth-service")
// Sign
claims := MyClaims{RegisteredClaims: svc.RegisteredClaims(time.Hour), UserID: "u_1"}
token, _ := svc.GenerateToken(&claims)
// Validate — RS256 only, exp required, issuer checked
got, err := jwt.ValidateToken[MyClaims](svc, token) ▸ data stores postgres · redis · s3#
Interface-driven persistence adapters, each with ConfigFromEnv and OTel tracing.
database/postgresql— GORM wrapper:Create,Find/FindManywith pagination,UpdateWhere,WithTransaction; pg error codes mapped to sentinels (cause preserved forerrors.Is)cache/redis— typedSet/Get/GetOrSet, sets, pub/sub, atomicGETDEL, TTL/NX/XX optionsstorage/s3—Get/Put/Head/Deleteplus presigned upload/download URLs
▸ messaging sqs · sns · scheduler#
Event-driven building blocks with trace context flowing through message attributes.
sqs— batch producer + worker-pool consumer that transparently unwraps the SNS envelope; backoff on poll errors and a graceful drain on shutdown (no duplicate delivery)sns— producer that propagates W3C trace context via message attributesscheduler— one-time EventBridge schedules with a webhook-via-Lambda helper and aDisabledflag that survives updates
▸ middleware/identity RBAC#
Echo middleware that reads a gateway-injected identity (user, roles, permissions) from request headers into the context.
HasPermission/HasAnyPermission/RequireCapabilitywithall:allsuperadmin- Wildcard patterns (
orders:*) and role checks ToRequestOptionsforwards the identity downstream — scoped forwarding no longer leaks superadmin past the pattern
▸ core helpers env · validator · telemetry · …#
The small, dependency-light pieces every service reuses.
env— typed env parsing (GetEnvAsInt/Duration/Bool/Slice,MustHave)validator— struct validation with field-aware messages, backed by go-playgroundtelemetry— one-call OTLP setup; parent-based sampling that honors upstream decisionspointers·timeutil— generics and date helperstestutil/echo·testutil/http— request builders and JSON assertions for handler tests
$ cat ~/ecosystem.md #
aws-sdk-go-v2, gorm, go-redis, resty, go-playground/validator, golang-jwt, opentelemetry-go Echo; everything else (logging, messaging, stores, jwt) is framework-agnostic