Naijacloud
Docs

Go

One call at the start of main(). The package uses only the standard library, needs Go 1.22 or newer, and takes a context first on every call so errors and logs stay tied to their request.

5 min read

Install

Install
bash
go get github.com/naijacloud/argus-go

Set up

At the start of main():

main.go
go
import argus "github.com/naijacloud/argus-go" argus.Init(argus.Options{DSN: "https://<public key>@argus-in.naijacloud.com/<project id>"})

Then, still in main(), send what's queued before the program exits, and report a crash:

main.go
go
defer argus.Close(2 * time.Second) // send what's queued before exiting defer argus.Recover() // report a panic, then panic as before

Leave DSN empty to read ARGUS_DSN, then SENTRY_DSN. A Naijacloud service gets the DSN from its Send errors to Argus switch, so there argus.Init(argus.Options{}) is enough. Without a DSN the SDK does nothing.

Send a test event

main.go
go
argus.Init(argus.Options{Debug: true}) argus.CaptureMessage(context.Background(), "Argus test event", argus.LevelInfo) argus.Close(5 * time.Second)

Run it with ARGUS_DSN set, and the event shows under Argus → Errors. With Debug on, the SDK prints any problem sending it, such as a refused key.

What it captures

  • Panics, with defer argus.Recover() in main and at the top of each goroutine. It reports the panic, flushes, and panics again, so your program fails the way it would have.
  • Errors you capture, with the whole errors.Unwrap chain (including errors.Join) and source lines around each frame.
  • Requests and outgoing calls, once you add the middleware and the round tripper below.

Database clients and gRPC are not traced yet.

net/http

Middleware
go
mux := http.NewServeMux() mux.HandleFunc("GET /orders/{id}", getOrder) http.ListenAndServe(":8080", argus.Middleware(mux))

Middleware traces each request as a span named after its route (GET /orders/{id}), continues a traceparent header from the caller, gives the request its own scope, and reports panics before re-panicking. With a router other than ServeMux, set the route yourself: argus.SpanFromContext(ctx).SetAttribute("http.route", "/orders/:id"). Gin, Echo, Fiber and chi work through argus.Middleware where they accept net/http middleware.

For outgoing calls, wrap your client's transport. Calls made inside a span become child spans and carry traceparent:

Outgoing calls
go
client := &http.Client{Transport: argus.RoundTripper(nil)} // nil: http.DefaultTransport

Report errors yourself

Errors
go
if err := chargeCard(ctx, order); err != nil { argus.CaptureException(ctx, err, argus.Details{ Tags: map[string]string{"provider": "paystack"}, Extra: map[string]any{"orderId": order.ID}, }) } argus.CaptureMessage(ctx, "webhook signature mismatch", argus.LevelWarning) argus.SetUser(ctx, argus.User{ID: user.ID}) argus.SetTag(ctx, "region", "af-west")

argus.WithScope(ctx) gives a job or goroutine its own tags, user and breadcrumbs; the middleware does it for each request. To carry on after a panic, recover it yourself and call argus.CapturePanic(ctx, v).

Logs

Logs
go
argus.Log.Info(ctx, "order placed", "orderId", "ord_81", "total", 18500) argus.Log.Error(ctx, "paystack timed out", "attempt", 3)

Arguments are slog-style key and value pairs. Logs are sent every 5 seconds, and a log written inside a span carries its trace id. Already on log/slog? Send its records to Argus and keep your local output:

log/slog
go
slog.SetDefault(slog.New(argus.NewSlogHandler(&argus.SlogOptions{ Next: slog.NewJSONHandler(os.Stdout, nil), // still printed CaptureErrors: true, // Error records also become events })))

Metrics

Metrics
go
argus.Metrics.Count(ctx, "orders.placed", 1, "method", "card") argus.Metrics.Gauge(ctx, "queue.depth", float64(len(jobs))) argus.Metrics.Histogram(ctx, "checkout.duration", ms, argus.Unit("ms"))

Metrics are added up in your process and sent every 10 seconds. Keep attribute values few: each distinct set is its own series.

Traces

Traces
go
err := argus.Trace(ctx, "send invoices", func(ctx context.Context) error { return sendInvoices(ctx) }) ctx, span := argus.StartSpan(ctx, "charge card", "provider", "paystack") defer span.End()

Spans join the active span in ctx, or start a trace. argus.ContinueTrace(ctx, traceparent) continues a trace from a queue message. Sample traces with TracesSampleRate, from 0 to 1.

Cron check-ins

Create a cron monitor in Argus first, then report runs by its slug:

Cron check-ins
go
err := argus.Cron.CheckIn(ctx, "nightly-invoices", sendInvoices) // or by hand: argus.Cron.Start(ctx, "nightly-invoices") argus.Cron.Success(ctx, "nightly-invoices") // or Fail(ctx, slug, output), Exit(ctx, slug, code, output)

CheckIn runs the job (a func(ctx context.Context) error), reports the start, then success or failure, and returns the job's error. A program that exits right after its job must call argus.Close first, or the last check-in may not leave.

Feature flags

Feature flags
go
if argus.Flags.IsOn(ctx, "new-checkout", user.ID) { // … } theme := argus.Flags.Variant(ctx, "theme", user.ID, "light")

Answers are cached for 30 seconds per user. If Argus doesn't answer within FlagTimeout (2 seconds), or the flag doesn't exist, you get false for IsOn (or argus.FlagDefault(true) if you pass it) and your fallback for Variant.

Release and environment

Init reads ARGUS_RELEASE and ARGUS_ENVIRONMENT, then SENTRY_RELEASE and SENTRY_ENVIRONMENT; the environment is production when none is set. Or set them:

Options
go
argus.Init(argus.Options{Release: version, Environment: "staging"})

Privacy

On by default:

  • Values of keys such as password, token, secret, authorization, cookie, bvn, pin and card become [Filtered], at any depth.
  • Card numbers, bearer and basic credentials, JWTs and password=… pairs are filtered inside strings.
  • Query strings and user:password@ are removed from URLs.
  • Cookies and request bodies are never sent.
  • The user's IP address is not sent unless you set SendDefaultPii: true.

BeforeSend changes an event, or drops it when it returns nil.

Already on Sentry

Keep sentry-go. In your sentry.Init call, change the Dsn line:

sentry.Init
go
Dsn: "https://<public key>@argus-in.naijacloud.com/<project id>",