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.
Install
go get github.com/naijacloud/argus-goSet up
At the start of main():
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:
defer argus.Close(2 * time.Second) // send what's queued before exiting
defer argus.Recover() // report a panic, then panic as beforeLeave 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
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()inmainand 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.Unwrapchain (includingerrors.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
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:
client := &http.Client{Transport: argus.RoundTripper(nil)} // nil: http.DefaultTransportReport errors yourself
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
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:
slog.SetDefault(slog.New(argus.NewSlogHandler(&argus.SlogOptions{
Next: slog.NewJSONHandler(os.Stdout, nil), // still printed
CaptureErrors: true, // Error records also become events
})))Metrics
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
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:
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
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:
argus.Init(argus.Options{Release: version, Environment: "staging"})Privacy
On by default:
- Values of keys such as
password,token,secret,authorization,cookie,bvn,pinandcardbecome[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:
Dsn: "https://<public key>@argus-in.naijacloud.com/<project id>",