apitally
API monitoring and analytics middleware with metrics, logging, and alerts. Works with Chi, Echo, Fiber, and Gin
About apitally
Apitally SDK for Go
Apitally is a simple API monitoring and analytics tool that makes it easy to understand API usage, monitor performance, and troubleshoot issues. Get started in minutes by just adding a few lines of code. No infrastructure changes required, no dashboards to build.
The SDK is an OpenTelemetry distribution and works alongside an existing OpenTelemetry setup.
Learn more about Apitally on our 🌎 website or check out the 📚 documentation.
[!IMPORTANT] Upgrading from 0.x? Version 1.0 is a full rewrite with a new setup API. See the migration guide for how to upgrade.
Key features
- API analytics: Traffic, error and performance metrics for your API, each endpoint, and per API consumer. Drill down from metrics to individual API requests.
- Request logs and traces: Every request as a searchable log entry, with optional capture of headers and request/response bodies. Requests are exported as OpenTelemetry spans, including spans from any other instrumentations you have.
- Application logs: Logs written via
log/slogcan be captured and correlated with the requests they belong to. - Error tracking: Validation errors and server errors, including panics with stack traces.
- Server metrics: CPU and memory usage of your app's processes.
- API monitoring & alerts: Get notified if something isn't right using custom alerts, synthetic uptime checks and heartbeat monitoring. Alert notifications can be delivered via email, Slack and Microsoft Teams.
Supported frameworks
The SDK supports Go >= 1.25.
| Framework | Supported versions | Setup guide |
|---|---|---|
| Gin | v1.9.1+ | Link |
| Fiber | v2.51.0+, v3.0.0+ | Link |
| Echo | v4.11.4+, v5.0.4+ | Link |
| Chi | v5.1.0+ | Link |
Apitally also supports many other web frameworks in JavaScript, Python and .NET via our other SDKs.
Getting started
If you don't have an Apitally account yet, first sign up here. Then create an app in the Apitally dashboard. You'll see detailed setup instructions with code snippets you can copy and paste. These also include your write token.
Gin
Install the SDK module for Gin:
go get github.com/apitally/apitally-go/gin-v1
Call apitally.Init right after gin.Default(), before registering middleware and routes:
import (
"github.com/gin-gonic/gin"
apitally "github.com/apitally/apitally-go/gin-v1"
)
func main() {
r := gin.Default()
cfg := apitally.NewConfig()
cfg.WriteToken = "your-write-token"
cfg.Env = "dev"
apitally.Init(r, cfg)
// register middleware and routes below this point
}
For further instructions, see our setup guide for Gin.
Fiber
Install the SDK module for Fiber:
go get github.com/apitally/apitally-go/fiber-v3
Call apitally.Init right after registering Fiber's recover middleware, before registering other middleware and routes:
import (
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/recover"
apitally "github.com/apitally/apitally-go/fiber-v3"
)
func main() {
app := fiber.New()
app.Use(recover.New())
cfg := apitally.NewConfig()
cfg.WriteToken = "your-write-token"
cfg.Env = "dev"
apitally.Init(app, cfg)
// register middleware and routes below this point
}
For further instructions, see our setup guide for Fiber.
Echo
Install the SDK module for Echo:
go get github.com/apitally/apitally-go/echo-v5
Call apitally.Init right after registering Echo's Recover middleware, before registering other middleware and routes:
import (
"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
apitally "github.com/apitally/apitally-go/echo-v5"
)
func main() {
e := echo.New()
e.Use(middleware.Recover())
cfg := apitally.NewConfig()
cfg.WriteToken = "your-write-token"
cfg.Env = "dev"
apitally.Init(e, cfg)
// register middleware and routes below this point
}
For further instructions, see our setup guide for Echo.
Chi
Install the SDK module for Chi:
go get github.com/apitally/apitally-go/chi-v5
Call apitally.Init right after registering Chi's Recoverer middleware, before registering other middleware and routes:
import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
apitally "github.com/apitally/apitally-go/chi-v5"
)
func main() {
r := chi.NewRouter()
r.Use(middleware.Recoverer)
cfg := apitally.NewConfig()
cfg.WriteToken = "your-write-token"
cfg.Env = "dev"
apitally.Init(r, cfg)
// register middleware and routes below this point
}
For further instructions, see our setup guide for Chi.
Graceful shutdown
Call apitally.Shutdown after your HTTP server has stopped, so Apitally can send any remaining telemetry before your app exits:
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
srv := &http.Server{Addr: ":8080", Handler: r}
go srv.ListenAndServe()
<-ctx.Done()
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
srv.Shutdown(shutdownCtx) // with Fiber: app.ShutdownWithContext(shutdownCtx)
apitally.Shutdown(shutdownCtx)
Configuration
Set configuration options as fields on the Config you pass to apitally.Init. Always create it with apitally.NewConfig(), which sets the defaults. See the SDK reference for all available options.
Environment variables
To keep configuration out of your code, set these environment variables instead of the matching fields:
APITALLY_WRITE_TOKEN: the write token (WriteToken)APITALLY_ENV: the environment name (Env), defaults todevAPITALLY_DISABLED: set totrueto disable Apitally (Disabled)
Request and response data
Apitally captures response headers by default. To also capture request headers and request and response bodies, set these fields:
cfg.CaptureRequestHeaders = true
cfg.CaptureRequestBody = true
cfg.CaptureResponseBody = true
Apitally automatically masks common sensitive values, such as password fields and the Authorization header. To mask additional values, set MaskQueryParams, MaskHeaders, and MaskBodyFields to regular expressions. See our documentation on masking for details.
Exclusions and sampling
Apitally automatically excludes common health checks and static assets, such as /healthz and /robots.txt, from logs and traces. To exclude additional paths, set ExcludePaths to regular expressions.
To capture logs and traces for only a fraction of the remaining requests, set SampleRate, for example to 0.1 for 10%. To decide for each request individually, set SampleOnRequest or SampleOnResponse to a callback.
Metrics always include all requests. See our documentation on sampling for details.
Adding context to requests
The following functions add context to the current request. Call them while handling a request, for example in a handler, middleware, or authentication code. Their first argument is the request context, which is c in Gin and Fiber, c.Request().Context() in Echo, and r.Context() in Chi.
Consumers
To associate the request with the API consumer making it, call SetConsumer. Only Identifier is required.
apitally.SetConsumer(ctx, apitally.Consumer{
Identifier: user.Identifier,
Name: user.Name,
Group: user.Group,
Attributes: map[string]string{"plan": user.Plan},
})
Custom attributes
To attach custom data to the request's trace, call SetRequestAttributes. The SampleOnResponse, MaskRequestBody, and MaskResponseBody callbacks can also read these attributes.
import "go.opentelemetry.io/otel/attribute"
apitally.SetRequestAttributes(ctx, attribute.String("tenant.id", tenantID))
See our documentation on attributes for details.
Handled errors
To capture an error that your code handles itself, call CaptureError. Panics and errors passed to the framework are captured automatically.
if err := processOrder(ctx); err != nil {
apitally.CaptureError(ctx, err)
}
Capturing application logs
To capture logs written with log/slog, wrap your handler with apitally.NewSlogHandler. It passes every record to your handler unchanged.
handler := slog.NewJSONHandler(os.Stdout, nil)
slog.SetDefault(slog.New(apitally.NewSlogHandler(handler)))
Don't wrap slog.Default().Handler(), because setting the result as the default logger causes a deadlock.
Apitally only captures records logged with the request context, for example with slog.InfoContext:
slog.InfoContext(ctx, "Order created", "order_id", order.ID)
To mask or drop individual log records, set MaskLogRecord to a callback. See our documentation on masking for details.
Existing OpenTelemetry setup
If your app already uses OpenTelemetry, register your tracer provider with otel.SetTracerProvider and any HTTP instrumentation middleware, such as otelgin, before calling apitally.Init. Apitally adds its span processor to your tracer provider and keeps your existing exporters. It also adds its data to your instrumentation's request spans instead of creating its own.
Your tracer provider's sampler also applies to Apitally. Requests it drops have no request logs or traces in Apitally, but still count in metrics.
Trusted proxies
If your app runs behind a reverse proxy or load balancer, configure trusted proxies in your framework:
- Gin:
SetTrustedProxiesmethod - Fiber:
TrustProxyandProxyHeadersettings - Echo:
IPExtractorsetting - Chi:
RealIPmiddleware
Apitally records the client IP your framework reports and uses it for GeoIP.
Getting help
If you need help please create a new discussion on GitHub or email us at [email protected]. We'll get back to you as soon as possible.
License
This library is licensed under the terms of the MIT license.
Frequently Asked Questions
What is apitally?
apitally is a Web Frameworks library for the Go programming language. API monitoring and analytics middleware with metrics, logging, and alerts. Works with Chi, Echo, Fiber, and Gin
How do I install apitally?
Install apitally with the Go module system using `go get apitally/apitally-go`. Check the repository for the current installation instructions.
What category does apitally belong to?
apitally is listed under Web Frameworks, specifically Middlewares.