haelu

package module
v0.0.0-...-20c561a Latest Latest
Warning

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

Go to latest
Published: Feb 12, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

README

haelu

A simple, opinionated health monitoring package

Documentation

Index

Constants

View Source
const (
	// DefaultProbeInterval is the interval a Monitor will invoke a Probe on
	// when no interval is set. A Monitor may have its own default, which can
	// be set via WithDefaultProbeInterval.
	DefaultProbeInterval time.Duration = 2 * time.Minute
)

Variables

View Source
var (
	// ErrMonitorStarted is returned by Monitor.Start to indicate that the Monitor
	// has already been started.
	ErrMonitorStarted = errors.New("the monitor has been started")

	// ErrMonitorShutdown is returned by Monitor.Shutdown to indicate that the
	// Monitor has not yet been started or has already been Shutdown.
	ErrMonitorShutdown = errors.New("the monitor has been shutdown")
)

Functions

func AddStatus

func AddStatus(err error, status Status) error

AddStatus associates a health Status with the given error. The returned error will wrap err and implement SelfStatuser.

If err already has a status associated with it, it will be replaced with the given status.

func DefaultHealthResponseCoder

func DefaultHealthResponseCoder(s Status) int

DefaultHealthResponseCoder is the default HealthResponseCoder used when no strategy is supplied.

This function returns a 200 for StatusGood, 429 for StatusWarn (consul's convention), and a 500 for any other status.

Types

type Definition

type Definition struct {
	// Name is the unique identifier for this subsystem within the Monitor.
	Name Name

	// Status is the initial status for this subsystem. By default, a subsystem's
	// initial state is StatusGood. Use this field to set a different Status that
	// will have effect until the first time an update occurs.
	Status Status

	// NonCritical indicates how this subsystem affects the overall Monitor status. By
	// default, this field is false, which means that a subsystem is critical.
	//
	// A critical subsystem directly affects a Monitor's overall status. If any critical
	// subsystems are StatusWarn, the overall status will be StatusWarn. If any critical
	// subsystems are StatusBad, the overall status will be StatusBad.
	//
	// A noncritcal subsystem will never cause a Monitor to be StatusBad. If any noncritical
	// subsystem is NOT StatusGood, the overall status will be StatusWarn.
	NonCritical bool

	// Probe is an optional closure that interrogates this subsystem's state. A probe will be
	// called only if both (1) the Monitor has been started, and (2) the subsystem is not paused.
	//
	// If no Probe is specified, the only way to update a subsystem's state is via its Updater.
	Probe Probe

	// ProbeInterval is the time interval on which any Probe is invoked. If no Probe is set,
	// this field is ignored.
	ProbeInterval time.Duration

	// Metadata are optional name/value pairs to associate with this subsystem. A caller may
	// specify any values in this map to act as metadata for the subsystem.
	Metadata Metadata
}

Definition holds the information necessary to create a logical subsystem within a Monitor.

type Handler

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

Handler is an HTTP handler that exposes health status. A Handler uses a Monitor's State to render HTTP responses.

func NewHandler

func NewHandler(opts ...HandlerOption) (*Handler, error)

NewHandler constructs a new health Handler using the supplied set of options.

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(response http.ResponseWriter, request *http.Request)

ServeHTTP returns an HTTP response that represents the most recent health update.

type HandlerOption

type HandlerOption interface {
	// contains filtered or unexported methods
}

HandlerOption is a configurable option for customizing a health Handler.

func WithHealthResponseCoder

func WithHealthResponseCoder(f HealthResponseCoder) HandlerOption

WithHealthResponseCoder sets a custom strategy for determining the HTTP response code for a given health Status.

If this option isn't used or is set to nil, DefaultHealthResponseCoder is used.

func WithMonitor

func WithMonitor(m *Monitor) HandlerOption

WithMonitor sets the health Monitor the Handler uses when presenting status.

type HealthResponseCoder

type HealthResponseCoder func(Status) int

HealthResponseCoder is a strategy for turning a health Status into an HTTP response code.

type Metadata

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

Metadata represents an immutable set of name/value pairs. Metadata may be associated with subsystems to expose client-specific metadata.

The zero value of this type is a usable, empty set.

func Map

func Map[T any](src map[string]T) Metadata

Map returns an immutable Metadata with the same name/value pairs as the src map. The returned Attributes is a shallow copy of the src.

Values will be of type any in the returned Metadata. This function is genericized to make it easier to turn any map with string keys into Metadata.

func Values

func Values(v ...any) Metadata

Values returns an immutable Metadata given a sequence of values. The values must occur in a series of pairs, e.g. name1, value1, name2, value2, etc. Thus, even index elements are names and odd index elements are the corresponding values. If there is an odd number of elements passed to this function, the last name is mapped to untyped nil in the returned attributes.

If a name is not a string and does not implement fmt.Stringer, fmt.Sprintf is used to convert it into a string to use as a Metadata key.

func (Metadata) All

func (m Metadata) All() iter.Seq2[string, any]

All provides iteration over each name/value pair in this set.

func (Metadata) Get

func (m Metadata) Get(name string) (value any, exists bool)

Get returns the value for a given name, if one exists.

func (Metadata) Len

func (m Metadata) Len() int

Len returns the number of name/value pairs in this set.

func (Metadata) MarshalJSON

func (m Metadata) MarshalJSON() ([]byte, error)

MarshalJSON writes this Metadata as a JSON object.

func (Metadata) String

func (m Metadata) String() string

String returns a string representation of this Metadata set.

type Monitor

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

Monitor is a health status monitor for application subsystems. All methods on a Monitor are atomic.

Each subsystem in a Monitor can be updated in one of two ways:

(1) After construction, Get can be used to obtain an Updater for a subsystem. This Updater can be used at any time to update the status of a subsystem, which will cause the overall status of the Monitor to be recomputed.

(2) A subsystem can be defined with a Probe. This Probe is a callback that will be invoked on the configured interval. Each time a Probe returns a result, that Probe's subsystem is update and the overall status of the Monitor is recomputed.

func NewMonitor

func NewMonitor(opts ...MonitorOption) (*Monitor, error)

NewMonitor constructs a health Monitor using the supplied set of options. The returned Monitor will not be running and must be started in order to receive Probe updates.

The set of subsystems is fixed and immutable after construction. The initial value returned by the Monitor from the State method will be computed from the initial states of the subsystems. If no subsystems are configured in the options, the returned Monitor will always report StatusGood as its overall status.

func (*Monitor) Get

func (m *Monitor) Get(n Name) (Updater, error)

Get returns the Updater for a Subsystem. If no such Subsystem exists, this method returns (nil, false).

This method always returns the same Updater instance for a given subsystem. The returned Updater may be used at any time, including when the Monitor has not been started or has been shutdown.

func (*Monitor) Len

func (m *Monitor) Len() int

Len returns the count of subsystems that are defined for this Monitor.

func (*Monitor) Shutdown

func (m *Monitor) Shutdown() error

Shutdown stops any running tasks. The status of subsystems are preserved. After this method has been called, Probes are no longer run but any Updaters may still be used to update subsystem states.

This method is idempotent. If this Monitor is not running, this method does nothing and returns ErrMonitorShutdown.

func (*Monitor) Start

func (m *Monitor) Start() error

Start computes the initial, overall state based on the status of the subystems and then starts any background tasks to monitor subsystem Probes. A Monitor may receive updates from subsystems at any time, even before Start is called.

This method is idempotent. If this Monitor has already been started, this method does nothing and returns ErrMonitorStarted.

Start will update the overall timestamp for the State, but will not modify any LastUpdate fields for subsystems.

func (*Monitor) State

func (m *Monitor) State() MonitorState

State returns the last computed state for this Monitor.

type MonitorOption

type MonitorOption interface {
	// contains filtered or unexported methods
}

MonitorOption is a configurable option for tailoring a Monitor.

func WithDefaultProbeInterval

func WithDefaultProbeInterval(i time.Duration) MonitorOption

WithDefaultProbeInterval sets the default interval for invoking any registered probes for this Monitor. If unset or nonpositive, the Monitor will use DefaultProbeInterval.

func WithSubsystems

func WithSubsystems(defs ...Definition) MonitorOption

WithSubsystems defines several subsystems for the monitor.

type MonitorState

type MonitorState struct {
	// Status is the new overall status of the Monitor.
	Status Status `json:"status" yaml:"status"`

	// LastUpdate is the timestamp of the monitor's last update to any subsystem.
	// This will include updates that may not have changed the status.
	//
	// This timestamp will always be in UTC.
	LastUpdate time.Time `json:"lastUpdate" yaml:"lastUpdate"`

	// Subsystems is a snapshot of the state of each subsystem within
	// the Monitor.
	Subsystems Subsystems `json:"subsystems" yaml:"subsystems"`
}

MonitorState holds a snapshot of the state of a Monitor.

type Name

type Name string

Name is the human-readable identifier for a subsystem. Names must be unique within a Monitor.

type Probe

type Probe func(context.Context) (Status, error)

Probe is a callback type to interrogate a subsystem for its health status. A Probe may consult information out-of-process, so it's passed a context.Context that gets canceled when a Monitor is shutdown.

func AsProbe

func AsProbe[F ProbeFunc](f F) Probe

AsProbe converts a closure into a Probe. This allows client code to use simpler closures that have no dependency on this package.

For closures that return a simple error, ErrorStatus is used to determine the health Status of the probe.

type ProbeFunc

type ProbeFunc interface {
	~func() bool |
		~func(context.Context) bool |
		~func() error |
		~func(context.Context) error |
		~func() Status |
		~func(context.Context) Status |
		~func() (Status, error) |
		~func(context.Context) (Status, error)
}

ProbeFunc describes the various closure types that are convertible to Probes. Calling code can convert any closure that satisfies this type via AsProbe.

type SelfBooler

type SelfBooler interface {
	// Status indicates the health status for this error. If this method returns false,
	// StatusBad is assumed. If this method returns true, StatusGood is assumed.
	// Note that this allows errors to indicate a healthy status.
	Status() bool
}

SelfBooler is an alternative to SelfStatuser that lets an error simply indicate good or bad health.

type SelfStatuser

type SelfStatuser interface {
	// Status returns the health status for this error. Note that this allows
	// errors to indicate a healthy status.
	Status() Status
}

SelfStatuser is an optional interface that an error can implement to indicate its health status.

type Status

type Status uint8

Status indicates the health status of a single subsystem or the overall application.

const (
	// StatusGood indicates a healthy application or subsystem.
	StatusGood Status = iota // good

	// StatusWarn indicates an application or subsystem that is usable, but is having problems.
	StatusWarn // warn

	// StatusBad indicates an application or subystem that is completely unusable.
	StatusBad // bad
)

func ErrorStatus

func ErrorStatus(err error) Status

ErrorStatus examines an error to determine what health Status to associated with it.

If err is nil, this function returns StatusGood.

If err implements SelfStatuser, then the result of SelfStatuser.Status() is returned.

If err implements SelfBooler, then StatusGood or StatusBad is returned based on the return value of SelfBooler.Status().

For a non-nil error that does not implement one of the optional interfaces in this package, this function returns StatusBad.

func (Status) MarshalText

func (s Status) MarshalText() ([]byte, error)

MarshalText produces the string value of this Status.

func (Status) String

func (i Status) String() string

type Subsystem

type Subsystem struct {
	// Name is the unique identifier for this subsystem.
	Name Name `json:"name" yaml:"name"`

	// Status is the current status of this subsystem. When creating a
	// Monitor, this is the initial status.
	Status Status `json:"status" yaml:"status"`

	// LastUpdate is the UTC timestamp of the last status update to this subsystem.
	// This field is set to the current time upon creation. Only status updates
	// affect this timestamp. Pausing or disabling a subsystem does not update
	// this field.
	LastUpdate time.Time `json:"lastUpdate,omitempty" yaml:"lastUpdate"`

	// LastError is the error that occurred with the most recent status update, if any.
	// This field is ignored when creating a Monitor.
	LastError error `json:"lastError,omitempty" yaml:"lastError"`

	// NonCritical indicates whether this subsystem is noncritical, i.e. how it affects
	// the overall Monitor status.
	NonCritical bool `json:"nonCritical" yaml:"nonCritical"`

	// Metadata is the optional set of name/value pairs that were supplied when the
	// subsystem was defined.
	Metadata Metadata `json:"metadata,omitempty" yaml:"metadata,omitempty"`
}

Subsystem is a snapshot of the current state of a logical subsystem within a monitor.

type Subsystems

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

Subsystems is an immutable, iterable sequence of Subsystem snapshots.

func AsSubsystems

func AsSubsystems(subs ...Subsystem) (s Subsystems)

AsSubsystems creates an immutable Subsystems sequence from a slice of individual Subsystem instances. The returned Subsystems will be a shallow copy of the given slice.

If the subs slice is empty, the returned Subsystems will be an immutable, empty sequence.

func (Subsystems) All

func (s Subsystems) All() iter.Seq[Subsystem]

All provides an iterator over this immutable sequence.

func (Subsystems) Get

func (s Subsystems) Get(i int) Subsystem

Get returns the Subsystem at the given 0-based index. If i is negative or not less than Len(), this function panics.

func (Subsystems) Len

func (s Subsystems) Len() int

Len returns the count of Subsystem snapshots in this sequence.

func (Subsystems) MarshalJSON

func (s Subsystems) MarshalJSON() ([]byte, error)

MarshalJSON marshals this sequence as a slice of Subsystems.

type Updater

type Updater interface {
	// Update supplies a possibly new status and an optional error that
	// occurred while checking the status or otherwise using the subsystem.
	Update(Status, error)
}

Updater is a interface that can be used to update a subsystem's health Status as well as pause and resume monitoring.

Jump to

Keyboard shortcuts

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