statuspage

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package statuspage builds the opt-in public status page: component probing, 90-day uptime bars, operator-authored incidents and the whitelisted public view. Nothing beyond View is ever published.

Index

Constants

View Source
const (
	PagePath    = "/public/status"
	SummaryPath = "/public/status.json"
	FeedPath    = "/public/status.rss"
	AtomPath    = "/public/status.atom"
	HistoryPath = "/public/status/history"
	BadgePath   = "/public/status/badge.svg"
	IncidentDir = "/public/status/incidents/"
)

FeedPath and SummaryPath are the public asset paths, relative to the page.

View Source
const (
	DefaultSampleInterval = time.Minute
	DefaultCacheTTL       = 30 * time.Second
	DefaultCheckTimeout   = 8 * time.Second
)

Defaults for Config, overridable via environment in cmd/levelrail.

View Source
const (
	Operational = "operational"
	Degraded    = "degraded"
	Outage      = "outage"
	Maintenance = "maintenance"
	Unknown     = "unknown"
	NoData      = "nodata"
)

Component and overall statuses.

View Source
const (
	KindApp    = "app"
	KindDomain = "domain"
	KindCheck  = "check"
	// KindMonitor follows an uptime monitor by id (ADR 054).
	KindMonitor = "monitor"
)

Component kinds.

View Source
const (
	IncidentKind    = "incident"
	MaintenanceKind = "maintenance"

	StatusInvestigating = "investigating"
	StatusIdentified    = "identified"
	StatusMonitoring    = "monitoring"
	StatusResolved      = "resolved"
	StatusScheduled     = "scheduled"
	StatusInProgress    = "in_progress"
	StatusCompleted     = "completed"

	ImpactNone     = "none"
	ImpactMinor    = "minor"
	ImpactMajor    = "major"
	ImpactCritical = "critical"
)

Incident kinds, statuses and impacts.

View Source
const UptimeDays = 90

UptimeDays is the number of daily bars on the page.

Variables

This section is empty.

Functions

func OverallStatus

func OverallStatus(statuses []string) string

OverallStatus folds component statuses into one headline status.

func RenderAtom

func RenderAtom(v View, baseURL string) ([]byte, error)

RenderAtom renders incidents and maintenance as an Atom 1.0 feed. baseURL is the page's own origin, e.g. "https://status.example.com".

func RenderBadge

func RenderBadge(label, state string) []byte

RenderBadge renders a flat two-part SVG badge. Both texts are escaped and only fixed colours are used, so no input reaches the markup raw.

func RenderHTML

func RenderHTML(v View) ([]byte, error)

RenderHTML renders the public page.

func RenderHistory

func RenderHistory(v View, tab string, page, size int) ([]byte, error)

RenderHistory renders one page of the incident and maintenance archive. tab is "all", "incidents" or "maintenance"; page counts from 1.

func RenderIncident

func RenderIncident(v View, id string) (body []byte, ok bool, err error)

RenderIncident renders the permalink page for one incident or maintenance entry. ok is false when the ID is unknown.

func RenderMarkdownLite

func RenderMarkdownLite(src string) template.HTML

RenderMarkdownLite converts operator text to safe HTML. All input is escaped first; only paragraphs, line breaks, "- " lists, **bold**, `code` and http(s) links are then re-introduced.

func RenderRSS

func RenderRSS(v View, baseURL string) ([]byte, error)

RenderRSS renders incidents and maintenance as an RSS 2.0 feed with plain-text descriptions. baseURL is the page's own origin, e.g. "https://status.example.com".

func StatusText

func StatusText(s string) string

StatusText is the human headline for an overall status.

Types

type AppSource

type AppSource interface {
	AppStatus(ctx context.Context, name string) (string, error)
}

AppSource reports an app's current status as one of the status constants.

type ComponentView

type ComponentView struct {
	ID          string    `json:"id"`
	Name        string    `json:"name"`
	Description string    `json:"description,omitempty"`
	Group       string    `json:"group,omitempty"`
	Status      string    `json:"status"`
	Uptime90    *float64  `json:"uptime_90d"`
	Days        []DayView `json:"days"`
}

ComponentView is one component as the public sees it.

type Config

type Config struct {
	SampleInterval time.Duration
	CacheTTL       time.Duration
	CheckTimeout   time.Duration
	Parallelism    int
}

Config tunes sampling and caching; zero values take the defaults.

type DayView

type DayView struct {
	Date   string   `json:"date"`
	Status string   `json:"status"`
	Uptime *float64 `json:"uptime,omitempty"`
	// Level scales the bar colour 1..4 by the day's weighted downtime share.
	Level int `json:"level,omitempty"`
}

DayView is one uptime bar.

type DomainSource

type DomainSource interface {
	CheckDomainStatus(ctx context.Context, domain string) (string, error)
}

DomainSource is the existing DNS domain check.

type IncidentView

type IncidentView struct {
	ID         string       `json:"id"`
	Title      string       `json:"title"`
	Status     string       `json:"status"`
	Impact     string       `json:"impact"`
	StartsAt   time.Time    `json:"starts_at"`
	EndsAt     *time.Time   `json:"ends_at,omitempty"`
	ResolvedAt *time.Time   `json:"resolved_at,omitempty"`
	Components []string     `json:"components,omitempty"`
	Updates    []UpdateView `json:"updates"`
	// Ongoing marks maintenance with no end time yet.
	Ongoing bool `json:"ongoing,omitempty"`
}

IncidentView is an incident or maintenance announcement.

func NewIncidentView

func NewIncidentView(i store.StatusIncident, componentNames map[string]string, updates []store.StatusIncidentUpdate) IncidentView

NewIncidentView is the one public serializer for an incident. Webhooks use it so they carry exactly the fields the public page does. Pass public updates only.

type MonitorSource

type MonitorSource interface {
	MonitorState(ctx context.Context, id string) string
}

MonitorSource reports a monitor's confirmed state: up, suspect, down, recovering, or "" when unknown.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service samples component health and builds the public View.

func New

func New(st Store, apps AppSource, domains DomainSource, cfg Config, logger *slog.Logger) *Service

New builds a Service. apps and domains may be nil, in which case components of that kind report unknown.

func (*Service) Enabled

func (s *Service) Enabled(ctx context.Context) (bool, error)

Enabled reports whether the public page is switched on. The flag is held for the view TTL and dropped by Invalidate, so a settings save is seen at once.

func (*Service) History

func (s *Service) History(ctx context.Context) (View, error)

History returns the view with the full archive window of incidents and maintenance, cached like View.

func (*Service) Invalidate

func (s *Service) Invalidate()

Invalidate drops the cached view so the next read reflects a management change.

func (*Service) PreviewView

func (s *Service) PreviewView(ctx context.Context) (View, error)

PreviewView builds an uncached view regardless of the enabled flag, for the management UI.

func (*Service) Run

func (s *Service) Run(ctx context.Context) error

Run samples every component on the configured interval until ctx ends.

func (*Service) Sample

func (s *Service) Sample(ctx context.Context) error

Sample probes every component once and records the result. It does nothing while the page is disabled.

func (*Service) SetMonitors

func (s *Service) SetMonitors(m MonitorSource)

SetMonitors lets monitor components follow the uptime monitor engine.

func (*Service) SetWindows

func (s *Service) SetWindows(w WindowSource)

SetWindows adds scheduled maintenance windows to the public view.

func (*Service) View

func (s *Service) View(ctx context.Context) (View, error)

View returns the public view, cached for the configured TTL.

type Store

type Store interface {
	GetStatusPageSettings(ctx context.Context) (store.StatusPageSettings, error)
	ListStatusComponents(ctx context.Context) ([]store.StatusComponent, error)
	ListStatusGroups(ctx context.Context) ([]store.StatusGroup, error)
	AddStatusSamples(ctx context.Context, componentID, day string, ok, degraded, down int) error
	ListStatusDaily(ctx context.Context, sinceDay string) ([]store.StatusDaily, error)
	PruneStatusDaily(ctx context.Context, beforeDay string) error
	ListPublicStatusIncidents(ctx context.Context, limit int) ([]store.StatusIncident, error)
	ListPublicStatusIncidentUpdates(ctx context.Context) ([]store.StatusIncidentUpdate, error)
}

Store is what Service reads and writes. *store.DB satisfies it.

type Tuning

type Tuning struct {
	DegradedWeight float64 // APP_STATUS_DEGRADED_WEIGHT: downtime weight of a degraded sample, 0..1
	DayOutageShare float64 // APP_STATUS_DAY_OUTAGE_SHARE: weighted downtime share that paints a day fully red
	AboutMax       int     // APP_STATUS_ABOUT_MAX: about text length cap
	DescriptionMax int     // APP_STATUS_DESCRIPTION_MAX: component description length cap
	GroupNameMax   int     // APP_STATUS_GROUP_NAME_MAX
	GroupsMax      int     // APP_STATUS_GROUPS_MAX
	LogoURLMax     int     // APP_STATUS_LOGO_URL_MAX
	HistoryPage    int     // APP_STATUS_HISTORY_PAGE_SIZE: entries per history page
	HistoryDays    int     // APP_STATUS_HISTORY_DAYS: archive depth
}

Tuning holds every operator-adjustable limit and weight of the page. Each field reads one APP_STATUS_* variable; the defaults are documented in docs/status-page.md.

func TuningFromEnv

func TuningFromEnv() Tuning

TuningFromEnv reads the knobs, falling back to the defaults for unset or invalid values.

type UpdateView

type UpdateView struct {
	Status string    `json:"status"`
	Body   string    `json:"body"`
	At     time.Time `json:"at"`
}

UpdateView is one timeline entry.

type View

type View struct {
	Title       string          `json:"title"`
	Description string          `json:"description,omitempty"`
	Status      string          `json:"status"`
	StatusText  string          `json:"status_text"`
	GeneratedAt time.Time       `json:"generated_at"`
	Accent      string          `json:"accent,omitempty"`
	LogoURL     string          `json:"logo_url,omitempty"`
	About       string          `json:"about,omitempty"`
	Website     string          `json:"website,omitempty"`
	NoIndex     bool            `json:"noindex,omitempty"`
	PoweredBy   bool            `json:"powered_by"`
	Components  []ComponentView `json:"components"`
	Incidents   []IncidentView  `json:"incidents"`
	Maintenance []IncidentView  `json:"maintenance"`
}

View is the entire public payload. Every field is deliberate: a privacy test fails when one is added without updating its whitelist.

type WindowSource

type WindowSource interface {
	ListMaintenanceWindows(ctx context.Context, since time.Time) ([]store.MaintenanceWindow, error)
}

WindowSource lists one-off maintenance windows. *store.DB satisfies it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL