Skip to main content
Version: v3_uptime_v0.x.x

Uptime

Release Discord Test

Uptime middleware for Fiber that records in-process heartbeat history and serves a lightweight status page.

Compatible with Fiber v3.

Preview

Uptime dashboard preview

Install

go get -u github.com/gofiber/fiber/v3
go get -u github.com/gofiber/contrib/v3/uptime
go get -u github.com/gofiber/storage/redis/v3

Signature

uptime.New(config ...uptime.Config) fiber.Handler
uptime.RemoveService(ctx context.Context, store *fiberredis.Storage, keyPrefix, serviceID string) error

Basic usage

package main

import (
"github.com/gofiber/contrib/v3/uptime"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/log"
fiberredis "github.com/gofiber/storage/redis/v3"
)

func main() {
app := fiber.New()
store := fiberredis.New()
app.Hooks().OnPostShutdown(func(_ error) error {
return store.Close()
})

app.Use(uptime.New(uptime.Config{
App: app,
Store: store,
ServiceID: "api",
ServiceName: "API",
}))

app.Get("/", func(c fiber.Ctx) error {
return c.SendString("ok")
})

log.Fatal(app.Listen(":3000"))
}

Open:

  • http://localhost:3000/uptime
  • http://localhost:3000/uptime/api/status

Endpoint probes

By default, uptime records a heartbeat for the current process identified by ServiceID. You can also configure HTTP endpoints. Each endpoint is shown as a separate service on the dashboard and in the JSON API.

app.Use(uptime.New(uptime.Config{
App: app,
Store: store,
Endpoints: []uptime.EndpointConfig{
{
ID: "api-health",
Name: "API Health",
URL: "https://api.example.com/health",
Method: "GET",
Interval: 10 * time.Second,
Timeout: 3 * time.Second,
ExpectedStatusCodes: []int{200, 204},
},
},
}))

When ExpectedStatusCodes is empty, any 2xx or 3xx response is considered up. Failed probes do not write heartbeat slots, so the endpoint naturally moves to yellow, red, or down as slots are missed.

Every instance runs its own probes, so N replicas sharing a StorageKeyPrefix send N times the probe traffic to each target. A slot counts as up when any replica saw the endpoint up.

The first probe runs when New is called, before app.Listen has opened the port. Endpoints pointing at the app's own routes therefore miss their first slot or two on startup.

Redis

Redis state is stored through github.com/gofiber/storage/redis/v3. Create the Fiber Redis storage in your app and pass it to the uptime config. By default, that storage package connects to 127.0.0.1:6379 and database 0.

store := fiberredis.New(fiberredis.Config{
Addrs: []string{"127.0.0.1:6379"},
Password: "",
Database: 0,
})
app.Hooks().OnPostShutdown(func(_ error) error {
return store.Close()
})

app.Use(uptime.New(uptime.Config{
App: app,
Store: store,
ServiceID: "api",
StorageKeyPrefix: "fiber:uptime",
}))

The middleware uses Conn() from the Fiber Redis storage to run the uptime queries it needs. Use a dedicated Redis database or a distinct StorageKeyPrefix when multiple environments share the same Redis server. The caller owns the Redis storage lifecycle. Close the Redis storage after the Fiber app has shut down, for example from OnPostShutdown, so uptime can stop its background recorders first.

When multiple uptime instances share the same Redis database and StorageKeyPrefix, use the same Timezone and heartbeat or probe interval for the same ServiceID or endpoint ID. If those settings need to differ, use distinct service IDs, endpoint IDs, or storage prefixes.

Key expiry

Service, sample and daily keys carry a TTL of RetentionDays + 1 days that is re-armed on every write. Background maintenance normally removes them long before that, so the TTL only matters once no process is left to run the cleanup: a decommissioned service, a changed key prefix, an app that never comes back. Without it those keys would stay in Redis forever.

The services registry set is shared by all instances under a prefix and is never expired. A service that has never recorded a successful heartbeat also keeps its (small) service hash without a TTL. Use RemoveService to clear either.

Removing a service

The dashboard lists every service found under StorageKeyPrefix, not just the ones in the current config. Services are never dropped automatically while their retention window keeps being refreshed, so renaming ServiceID or an endpoint ID, or removing an endpoint, leaves the old identifier behind as a row that reports down forever. Delete it explicitly:

err := uptime.RemoveService(context.Background(), store, "fiber:uptime", "old-endpoint-id")

Pass the same StorageKeyPrefix the middleware uses, or "" for the default. This removes the service, its history and its raw samples.

Remove the service from your config and restart before calling it. Calling it while the service is still being recorded takes it off the dashboard for good, but in-flight heartbeats will recreate partial keys; those carry the TTL above and expire on their own.

Snapshots and custom UI

The dashboard and JSON API build a fresh Snapshot from the backing store on each request. Use Fiber's cache middleware around the uptime route if you want HTTP-level caching. The same snapshot payload is available at UI.Path + "/api/status" for custom dashboards.

Config

PropertyTypeDescriptionDefault
App*fiber.AppFiber app used to register the shutdown hook that closes the uptime runtime.Required
Nextfunc(fiber.Ctx) boolSkip the uptime handler when true.nil
ServiceIDstringStable service identifier for the current process. Required only when Endpoints is empty.""
ServiceNamestringDisplay name.ServiceID
ServiceDescriptionstringDisplay description.""
Endpoints[]uptime.EndpointConfigOptional HTTP endpoints to probe as tracked services.nil
SampleIntervaltime.DurationHeartbeat interval.3 * time.Second
RetentionDaysintNumber of days to retain daily history. Also sets the key expiry backstop.90
DaysToShowintNumber of days shown in snapshots and dashboard.30
Timezone*time.LocationTimezone for day and slot boundaries.time.Local
NodeIDint64Optional node value used for generated instance IDs.0
InstanceIDint64Explicit process instance ID.Generated
IDGeneratoruptime.IDGeneratorCustom instance ID generator.nil
Store*fiberredis.StorageFiber Redis storage instance from github.com/gofiber/storage/redis/v3.Required
StorageKeyPrefixstringPrefix for all uptime Redis keys."fiber:uptime"
UIuptime.UIConfigDashboard copy and thresholds. Threshold values are configurable in (0, 1]; zero uses the defaults.Light English UI, green at 99.9%, yellow at 99%

EndpointConfig

PropertyTypeDescriptionDefault
IDstringStable endpoint identifier.Required
NamestringDisplay name.ID
DescriptionstringDisplay description.""
URLstringAbsolute http or https URL to probe.Required
MethodstringHTTP method used for the probe.GET
Headersmap[string]stringOptional request headers sent with each probe.nil
ExpectedStatusCodes[]intStatus codes that mark the endpoint up. Empty means any 2xx or 3xx.nil
Intervaltime.DurationEndpoint heartbeat interval.Config.SampleInterval
Timeouttime.DurationMaximum duration for one probe.5 * time.Second

Handler behavior

The Fiber handler serves:

  • /uptime
  • /uptime/
  • /uptime/api/status

GET and HEAD are supported. Other methods return 405 Method Not Allowed. Requests outside UI.Path, including unknown uptime subpaths, are passed to the next handler.

The handler matches request paths against UI.Path (default /uptime). When mounted under a Fiber group or Use prefix, the match is relative to that mount point.

The middleware does not read request bodies, capture response bodies, or wrap business handlers. Process heartbeats and endpoint probes are run by background tickers owned by the uptime runtime.

Performance notes

Store writes and endpoint probes happen on background tickers, not on every business request. Status requests read the backing store to build the response. Use Fiber's cache middleware if the dashboard or JSON API should be cached.

Concurrency safety

Uptime middleware instances are safe for concurrent use after construction. The snapshot payload is built from fresh store reads. Redis commands are issued through the Fiber Redis storage connection and are safe for concurrent use by the background recorder and Fiber handlers.

Config.App is required so New can register a Fiber shutdown hook that stops the uptime runtime. The caller owns the Redis storage lifecycle and should close it after the app has shut down, for example from OnPostShutdown or a signal handler that closes Redis after app.Shutdown returns.

Security notes

Mount the dashboard on an internal or protected route when uptime history should not be public. The middleware does not log request bodies, response bodies, authorization headers, cookies, or query strings. Endpoint probe response bodies are closed without being read. Avoid putting secrets in endpoint URLs because URLs may still appear in upstream infrastructure logs outside this middleware.