Documentation
¶
Overview ¶
Package status provides a comprehensive, thread-safe health check and status monitoring system designed for production-grade HTTP APIs.
It integrates seamlessly with the Gin web framework to expose status endpoints that aggregate health metrics from various application components (databases, caches, external services) using flexible and configurable validation strategies.
Overview ¶
This package is built to address the needs of microservices and distributed systems where simple "up/down" checks are often insufficient. It offers:
- **Flexible Validation**: Support for complex dependency rules via control modes (Must, Should, AnyOf, Quorum).
- **High Performance**: Built-in caching mechanism using atomic operations to minimize lock contention and reduce load on downstream services during frequent health checks (e.g., Kubernetes probes).
- **Thread-Safety**: All public API methods and internal state mutations are safe for concurrent access.
- **Multi-Format Output**: Native support for JSON (default), plain text (for simple parsers), and structured map outputs.
- **Dynamic Configuration**: Capability to load mandatory component definitions dynamically from configuration keys, allowing for runtime adaptability.
- **Ecosystem Integration**: Designed to work hand-in-hand with `github.com/nabbar/golib/monitor` for the actual health checking logic.
Architecture ¶
The package is structured into modular subpackages to separate concerns and improve maintainability:
status/ ├── control/ # Defines the validation logic and enum types for control modes (Must, Should, etc.). ├── mandatory/ # Manages a single group of components that share a specific validation mode. ├── listmandatory/ # Manages a collection of mandatory groups, enabling complex, multi-layered validation rules. ├── interface.go # Defines the main public interfaces (Status, Route, Info, Pool). ├── model.go # Contains the core implementation of the Status interface and the aggregation logic. ├── config.go # Defines configuration structures and validation logic. ├── cache.go # Implements the caching layer using atomic values for lock-free reads. └── route.go # Provides the HTTP handler and middleware for Gin integration.
Component Overview ¶
The following diagram illustrates the high-level components and their interactions:
┌──────────────────────────────────────────────────────┐
│ Status Package │
│ HTTP Endpoint + Component Health Aggregation │
└──────────────┬────────────┬──────────────┬───────────┘
│ │ │
┌────────▼───┐ ┌────▼─────┐ ┌────▼────────┐
│ control │ │mandatory │ │listmandatory│
│ │ │ │ │ │
│ Validation │ │ Group │ │ Group │
│ Modes │ │ Manager │ │ Collection │
└────────────┘ └──────────┘ └─────────────┘
│ │ │
└────────────┴──────────────┘
│
┌─────────▼──────────┐
│ monitor/types │
│ Component Health │
└────────────────────┘
Data Flow & Logic ¶
The following diagram details the request processing flow, from the incoming HTTP request to the final response, highlighting the caching and computation steps:
[HTTP Request] (GET /status)
│
▼
[MiddleWare] (route.go)
│
├─> Parse Query Params & Headers (short, format, map)
│ Determines verbosity and output format.
│
▼
[Status Computation] (model.go)
│
├─> Check Cache (cache.go)
│ │
│ ├─> Valid? ───> Return Cached Status (Fast Path)
│ │ (Atomic read, < 10ns)
│ │
│ └─> Invalid? ─┐ (Slow Path)
│ │
│ [Walk Monitor Pool] (pool.go)
│ Iterate over all registered monitors.
│ │
│ ▼
│ [Apply Control Modes] (control/mandatory)
│ Evaluate health based on configured rules.
│ │
│ ┌─────┴─────┐
│ │ │
│ [Must/Should] [AnyOf/Quorum]
│ │ │
│ ▼ ▼
│ Check Indiv. Check Group
│ Component Logic (Thresholds)
│ │ │
│ └─────┬─────┘
│ │
│ ▼
│ [Aggregate Status]
│ Determine Global Status (OK / WARN / KO)
│ │
│ ▼
└─<── Update Cache ─┘
(Atomic write)
│
▼
[Response Encoding] (encode.go)
│
├─> Format: JSON / Text
├─> Verbosity: Full (details) / Short (status only)
├─> Structure: List / Map
│
▼
[HTTP Response] (Status Code + Body)
Key Features Detail ¶
## Component Monitoring The system aggregates health status from multiple sources. Each source is a "Monitor" (defined in `github.com/nabbar/golib/monitor`) that performs the actual check (e.g., pinging a DB).
## Control Modes Control modes dictate how the failure of a specific component affects the global application status:
- **Ignore**: The component is monitored, but its status is completely ignored in the global calculation.
- **Should**: Non-critical dependency. Failure results in a `WARN` global status, but not `KO`.
- **Must**: Critical dependency. Failure results in a `KO` global status.
- **AnyOf**: Redundancy check. The group is healthy if *at least one* component is healthy.
- **Quorum**: Consensus check. The group is healthy if *more than 50%* of components are healthy.
## Caching To prevent "thundering herd" problems or excessive load on dependencies during high-frequency health checks (like Kubernetes liveness probes), the status is cached.
- **Duration**: Configurable, defaults to 3 seconds.
- **Mechanism**: Uses `atomic.Value` to store the result and timestamp, allowing for lock-free reads in the hot path.
## Output Formats
- **JSON**: Standard format, easy to parse.
- **Text**: Human-readable, useful for command-line tools (curl/grep).
- **Map Mode**: Returns components as a JSON map (keyed by name) instead of a list, facilitating direct access by component name.
Usage ¶
## Basic Setup
import (
"github.com/gin-gonic/gin"
"github.com/nabbar/golib/context"
"github.com/nabbar/golib/status"
"github.com/nabbar/golib/monitor/pool"
"github.com/nabbar/golib/monitor/types"
)
func main() {
// Initialize the global context
ctx := context.NewGlobal()
// Create the status manager
sts := status.New(ctx)
sts.SetInfo("my-app", "v1.0.0", "build-hash")
// Create and register the monitor pool
monPool := pool.New(ctx)
sts.RegisterPool(func() montps.Pool { return monPool })
// Setup Gin router
r := gin.Default()
// Register the status middleware
r.GET("/status", func(c *gin.Context) {
sts.MiddleWare(c)
})
r.Run(":8080")
}
## Configuration
You can configure HTTP return codes and mandatory components. This example shows how to mix static definitions with dynamic loading.
cfg := status.Config{
// Map internal status to HTTP status codes
ReturnCode: map[monsts.Status]int{
monsts.OK: 200,
monsts.Warn: 207, // Multi-Status
monsts.KO: 503, // Service Unavailable
},
// Define mandatory component groups
Component: []status.Mandatory{
{
Mode: control.Must,
Keys: []string{"database"}, // Static definition: "database" must be up
},
{
Mode: control.Should,
ConfigKeys: []string{"cache-component"}, // Dynamic: load keys from config "cache-component"
},
},
}
sts.SetConfig(cfg)
// Register a resolver for dynamic loading (ConfigKeys)
sts.RegisterGetConfigCpt(func(key string) cfgtypes.Component {
// Logic to retrieve component by key from your config system
return myConfig.ComponentGet(key)
})
Programmatic Health Checks ¶
The package provides several methods to check the system's health programmatically, useful for internal logic or custom probes.
## Live vs. Cached Checks
**Live Checks** (`IsHealthy()`, `IsStrictlyHealthy()`): These methods force a re-evaluation of all monitors. They provide the most up-to-date state but are more expensive. Use them when you need immediate confirmation of a state change (e.g., during startup or shutdown).
**Cached Checks** (`IsCacheHealthy()`, `IsCacheStrictlyHealthy()`): These methods return the cached result if it is still valid (within the TTL). They are extremely fast (<10ns) and thread-safe. Use them for high-frequency endpoints like `/health` or `/status`.
## Strict vs. Tolerant Checks
**Tolerant Check** (`IsHealthy`, `IsCacheHealthy`): Returns `true` if the global status is `OK` or `WARN`. This is suitable for **Readiness Probes**, where a degraded service (WARN) might still be able to serve some traffic.
**Strict Check** (`IsStrictlyHealthy`, `IsCacheStrictlyHealthy`): Returns `true` *only* if the global status is `OK`. This is suitable for **Liveness Probes**, where you might want to restart the service if it's not fully healthy (depending on your restart policy).
## Checking Specific Components
You can also check the health of one or more specific components. The control logic (Must/Should/etc.) associated with these components is still applied during the check.
// Check if "database" and "cache" are healthy
if sts.IsHealthy("database", "cache") {
// Proceed with logic requiring DB and Cache
}
HTTP API ¶
The exposed endpoint supports several query parameters and headers for content negotiation:
- `short=true` (query) or `X-Verbose: false` (header): Returns only the overall status without component details.
- `format=text` (query) or `Accept: text/plain` (header): Returns plain text output.
- `map=true` (query) or `X-MapMode: true` (header): Returns components as a map instead of a list.
Subpackages ¶
The package is modularized to separate concerns:
- `control`: Defines validation modes (e.g., Must, Should) and their encoding/decoding logic. It is the brain of the validation strategy.
- `mandatory`: Manages a single group of components associated with a specific validation mode. It is a thread-safe container for a list of component keys and their control mode.
- `listmandatory`: Manages a collection of `mandatory` groups, allowing for the creation of complex validation rules across different sets of components.
Control Modes & Logic ¶
The health of the application is determined by aggregating the status of monitored components according to their assigned control mode.
## Available Modes
- `Ignore`: The component's status is completely ignored and does not affect the global status.
- `Should`: The component is important but not critical. A failure (`KO`) or warning (`WARN`) in this component will result in a global `WARN` status, but not `KO`.
- `Must`: The component is critical. A failure (`KO`) will result in a global `KO` status. A warning (`WARN`) will result in a global `WARN`.
- `AnyOf`: Used for redundant groups (e.g., a cluster of services). The global status will be `KO` only if all components in the group are `KO`. Otherwise, the group's status is determined by the best-status member.
- `Quorum`: Used for distributed consensus groups. The global status will be `KO` if more than 50% of the components in the group are `KO`.
## Status Transitions
The global status is calculated dynamically based on the worst-case scenario allowed by the configuration.
- `OK`: All `Must` components are `OK`, `Quorum` is satisfied, and `AnyOf` has healthy candidates.
- `WARN`: A `Should` component is `KO`, or a `Must` component is `WARN`. The service is considered degraded but still operational.
- `KO`: A `Must` component is `KO`, `Quorum` is lost, or an `AnyOf` group has no healthy candidates. The service is considered unavailable.
Transitions occur automatically as component health changes. The `IsHealthy()` method returns `true` for both `OK` and `WARN` states, while `IsStrictlyHealthy()` returns `true` only for the `OK` state.
Index ¶
Constants ¶
const ( // ErrorParamEmpty occurs when required parameters are missing. For example, // this can happen when attempting to marshal a status response without having // first set the application info (name, release, hash) via `SetInfo` or `SetVersion`. ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgStatus // ErrorValidatorError occurs when the configuration validation fails. This // error is returned by `Config.Validate()` when the provided configuration // does not meet the required constraints defined by the struct tags (e.g., a // required field is missing). ErrorValidatorError )
const ( // HeadVerbose is the HTTP header for controlling response verbosity. // A value of "false" enables short mode (equivalent to `short=true` query param). HeadVerbose = "X-Verbose" // HeadFormat is the standard "Accept" HTTP header used for content negotiation. // It supports "application/json" and "text/plain". HeadFormat = "Accept" // HeadMapMode is the HTTP header for enabling map mode for component output. // A value of "true" enables map mode. HeadMapMode = "X-MapMode" // QueryVerbose is the query parameter for enabling short output mode. // A value of "true" or "1" will omit component details from the response. QueryVerbose = "short" // QueryFormat is the query parameter for selecting the output format. // Supported values are "text" or "json". QueryFormat = "format" // QueryMapMode is the query parameter for enabling map mode for component output. // A value of "true" or "1" will format the component list as a map. QueryMapMode = "map" )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶ added in v1.10.0
type Config struct {
// ReturnCode maps internal health status levels (OK, Warn, KO) to HTTP status codes.
//
// Default values if not set:
// - monsts.OK: 200 (http.StatusOK)
// - monsts.Warn: 207 (http.StatusMultiStatus)
// - monsts.KO: 500 (http.StatusInternalServerError)
ReturnCode map[monsts.Status]int `mapstructure:"return-code" json:"return-code" yaml:"return-code" toml:"return-code" validate:"required"`
// Component defines the list of mandatory component groups. Each group specifies
// a set of components and the control mode that applies to them.
Component []Mandatory `mapstructure:"component" json:"component" yaml:"component" toml:"component" validate:""`
}
Config defines the complete configuration for the status system. It controls how the application's health is computed and how it is reported via HTTP.
func (Config) Validate ¶ added in v1.10.0
Validate checks if the configuration is valid using the `validator` package. It ensures that all required fields are present and meet the defined constraints.
Returns:
An error if validation fails, containing details about which fields failed and why. Returns nil if the configuration is valid.
type Encode ¶ added in v1.10.0
type Encode interface {
// String returns the status as a formatted string, suitable for logging or
// plain text responses.
String() string
// Bytes returns the status as a byte slice, equivalent to `[]byte(String())`.
Bytes() []byte
// GinRender renders the status response to a Gin context. It handles content
// negotiation (JSON vs. text) and verbosity (full vs. short).
GinRender(c *ginsdk.Context, isText bool, isShort bool)
// GinCode returns the appropriate HTTP status code for the response, based on
// the overall health status and configuration.
GinCode() int
}
Encode defines the interface for status response encoding. It provides methods for rendering the status in different formats (JSON, plain text) and for integration with the Gin framework.
type FuncGetCfgCpt ¶ added in v1.20.0
type FuncGetCfgCpt func(key string) cfgtps.ComponentMonitor
FuncGetCfgCpt defines a function type for retrieving a component by its key. This function acts as a bridge between the status package and an external component management system. It is used to dynamically load monitor names from component configurations when `ConfigKeys` is used in the `Mandatory` section of the status configuration.
The returned `cfgtps.ComponentMonitor` must provide the monitor names via its `GetMonitorNames()` method.
type Info ¶ added in v1.5.5
type Info interface {
// SetInfo manually sets the application name, release version, and build hash.
// This is a straightforward way to provide static version information.
//
// Parameters:
// - name: The name of the application (e.g., "my-api").
// - release: The release version (e.g., "v1.2.3").
// - hash: The build commit hash (e.g., "abcdef1").
SetInfo(name, release, hash string)
// SetVersion sets the application information from a `version.Version` object.
// This is the recommended approach as it allows the version information to be
// managed centrally and updated dynamically if needed.
//
// Parameters:
// - vers: An object that implements the `libver.Version` interface.
SetVersion(vers libver.Version)
}
Info defines the interface for setting the application's version and build information. This information is included in the status response to help identify the exact version of the running service.
type Mandatory ¶ added in v1.11.3
type Mandatory struct {
// Mode defines how this group of components affects the overall status.
// Possible values include:
// - Ignore: The components are monitored but do not affect global status.
// - Should: Failure causes a warning but not a critical failure.
// - Must: Failure causes a critical global failure.
// - AnyOf: At least one component in the group must be healthy.
// - Quorum: A majority of components in the group must be healthy.
Mode stsctr.Mode `mapstructure:"mode" json:"mode" yaml:"mode" toml:"mode" validate:"required"`
// Keys is a list of static monitor names belonging to this group.
// These names must match the names of the monitors registered in the monitor pool.
// This field is used when the component names are known at configuration time.
Keys []string `mapstructure:"keys" json:"keys" yaml:"keys" toml:"keys"`
// ConfigKeys is used to specify the keys of config components. This allows for
// dynamic resolution of monitor names. When `SetConfig` is called, the system
// will look up the component configuration using these keys (via the function
// registered with `RegisterGetConfigCpt`) and add the associated monitor names
// to this mandatory group.
ConfigKeys []string `mapstructure:"configKeys" json:"configKeys" yaml:"configKeys" toml:"configKeys"`
}
Mandatory defines a group of components that share a specific control mode. It allows grouping multiple components (e.g., "all databases") and defining how their collective health affects the overall application status.
This structure is typically used when loading configuration from a file (JSON, YAML, etc.).
See github.com/nabbar/golib/status/control for details on available control modes.
func ParseList ¶ added in v1.19.0
ParseList converts a slice of `mandatory.Mandatory` interfaces to a slice of `Mandatory` structs.
This is a utility function for bulk conversion, useful when exporting the current configuration state.
Parameters:
- m: A variadic list of `mandatory.Mandatory` interfaces.
Returns:
A slice of `Mandatory` structs. Nil entries in the input are skipped.
func ParseMandatory ¶ added in v1.19.0
ParseMandatory converts a `mandatory.Mandatory` interface (from the internal logic) to a `Mandatory` struct (for configuration/export).
This is a utility function for converting between the runtime interface representation and the configuration struct representation.
Parameters:
- m: The `mandatory.Mandatory` interface to convert.
Returns:
A `Mandatory` struct populated with the mode and keys from the interface. Returns an empty struct if the input is nil.
type Pool ¶ added in v1.10.0
type Pool interface {
montps.PoolStatus
// RegisterPool registers a function that provides the monitor pool. This
// dependency injection pattern is crucial, as it decouples the status
// package from the monitor pool's lifecycle. The status package can then
// retrieve the most up-to-date pool instance whenever it needs to perform
// a health check.
//
// Parameters:
// - fct: A function that returns an instance of `montps.Pool`.
RegisterPool(fct montps.FuncPool)
}
Pool defines the interface for managing the monitor components that contribute to the overall health status. It embeds `montps.PoolStatus` to provide basic monitor management (Add, Del, Get, etc.) and adds a method for registering the pool itself.
type Route ¶ added in v1.10.0
type Route interface {
// Expose provides a generic handler for status requests that can be used
// with any framework that uses `context.Context`. It acts as a wrapper
// around the `MiddleWare` method, allowing for broader framework compatibility.
// If the provided context is a `*gin.Context`, it will be handled; otherwise,
// the call is a no-op.
//
// Parameters:
// - ctx: The context of the request, which may be a `*gin.Context`.
Expose(ctx context.Context)
// MiddleWare is a Gin middleware that processes status requests. It handles
// content negotiation for format (JSON/text) and verbosity (full/short)
// based on query parameters and HTTP headers. It calculates the current
// health status and renders the appropriate response.
//
// Parameters:
// - c: The `*gin.Context` for the incoming HTTP request.
MiddleWare(c *ginsdk.Context)
// SetErrorReturn registers a custom factory function for creating error
// formatters. This allows you to define how errors generated within the
// status middleware are rendered in the HTTP response, ensuring consistent
// error formatting across your application.
//
// Parameters:
// - f: A function that returns an instance of `liberr.ReturnGin`.
SetErrorReturn(f func() liberr.ReturnGin)
}
Route defines the HTTP routing interface for exposing the status endpoint. This interface groups all methods related to handling HTTP requests, primarily for integration with the Gin web framework.
type Status ¶
type Status interface {
encoding.TextMarshaler
json.Marshaler
Route
Info
Pool
// RegisterGetConfigCpt registers a function to retrieve component configurations
// by key. This is essential for the dynamic `ConfigKeys` feature, allowing
// the status system to query an external configuration manager for components
// and their associated monitors.
//
// Parameters:
// - fct: The function that will be called to resolve a component key.
RegisterGetConfigCpt(fct FuncGetCfgCpt)
// SetConfig applies a configuration for status computation and HTTP response codes.
// This is the primary method for defining your health check policies, including
// which components are critical and how their failures should be handled.
//
// Parameters:
// - cfg: The `Config` object containing the desired settings.
SetConfig(cfg Config)
// GetConfig returns the current configuration used for status computation.
// This can be useful for debugging or for services that need to inspect
// the current health check policy.
//
// Returns:
// The current `Config` object.
GetConfig() Config
// IsHealthy performs a live (non-cached) health check to determine if the
// overall system or a specific set of components are "healthy," meaning their
// status is either `OK` or `WARN`. This is a "tolerant" check.
//
// Parameters:
// - name: An optional list of component names to check. If empty, checks all components.
//
// Returns:
// `true` if the aggregated status is `OK` or `WARN`, `false` otherwise.
IsHealthy(name ...string) bool
// IsStrictlyHealthy performs a live (non-cached) health check to determine if
// the overall system or specific components are "strictly healthy," meaning
// their status is `OK`. This is a "strict" check.
//
// Parameters:
// - name: An optional list of component names to check. If empty, checks all components.
//
// Returns:
// `true` only if the aggregated status is `OK`, `false` otherwise.
IsStrictlyHealthy(name ...string) bool
// IsCacheHealthy performs a "tolerant" health check using the cached status.
// It returns `true` if the cached status is `OK` or `WARN`. This is a
// high-performance check suitable for frequent calls (e.g., in a middleware).
//
// Returns:
// `true` if the cached status is `OK` or `WARN`, `false` otherwise.
IsCacheHealthy() bool
// IsCacheStrictlyHealthy performs a "strict" health check using the cached status.
// It returns `true` only if the cached status is `OK`. This is also a
// high-performance check.
//
// Returns:
// `true` only if the cached status is `OK`, `false` otherwise.
IsCacheStrictlyHealthy() bool
}
Status is the main interface that combines all health status functionality. It provides a complete solution for application health monitoring and reporting, from configuration to HTTP response rendering.
func New ¶ added in v1.5.5
New creates a new, fully initialized `Status` instance.
The returned instance is thread-safe but requires further configuration before it can be used effectively. At a minimum, you must:
- Call `SetInfo` or `SetVersion` to provide application identity.
- Call `RegisterPool` to link a monitor pool for health checks.
You can also optionally call `SetConfig` to define custom health policies and `SetErrorReturn` to customize error formatting.
Parameters:
- ctx: The root `context.Context` for the application.
Returns:
A new `Status` instance.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package control provides the validation modes that govern how component health affects the overall application status.
|
Package control provides the validation modes that govern how component health affects the overall application status. |
|
Package listmandatory provides management of multiple mandatory component groups.
|
Package listmandatory provides management of multiple mandatory component groups. |
|
Package mandatory provides a thread-safe mechanism for managing groups of components that share a common validation mode.
|
Package mandatory provides a thread-safe mechanism for managing groups of components that share a common validation mode. |