Documentation
¶
Overview ¶
Package health is a easy to use, extensible health check library.
Example
package main
import (
"net/http"
"database/sql"
"github.com/mschneider82/health"
"github.com/mschneider82/health/url"
"github.com/mschneider82/health/db"
"github.com/mschneider82/health/redis"
_ "github.com/go-sql-driver/mysql"
)
func main() {
database, _ := sql.Open("mysql", "/")
mysql := db.NewMySQLChecker(database)
companies := health.NewCompositeChecker()
companies.AddChecker("Microsoft", url.NewChecker("https://www.microsoft.com/"))
companies.AddChecker("Oracle", url.NewChecker("https://www.oracle.com/"))
companies.AddChecker("Google", url.NewChecker("https://www.google.com/"))
handler := health.NewHandler()
handler.AddChecker("Go", url.NewChecker("https://golang.org/"))
handler.AddChecker("Big Companies", companies)
handler.AddChecker("MySQL", mysql)
handler.AddChecker("Redis", redis.NewChecker("tcp", ":6379"))
http.Handle("/health/", handler)
http.ListenAndServe(":8080", nil)
}
Executing a curl
$ curl localhost:8080/health/
If everything is ok the server must respond with HTTP Status 200 OK and have following json in the body.
{
"Big Companies": {
"Google": {
"code": 200,
"status": "UP"
},
"Microsoft": {
"code": 200,
"status": "UP"
},
"Oracle": {
"code": 200,
"status": "UP"
},
"status": "UP"
},
"Go": {
"code": 200,
"status": "UP"
},
"MySQL": {
"status": "UP",
"version": "10.1.9-MariaDB"
},
"Redis": {
"status": "UP",
"version": "3.0.5"
},
"status": "UP"
}
The server responds with HTTP Status 503 Service Unavailable if the ckeck is Down and the json response could be something like this.
{
"Big Companies": {
"Google": {
"code": 200,
"status": "UP"
},
"Microsoft": {
"code": 200,
"status": "UP"
},
"Oracle": {
"code": 200,
"status": "UP"
},
"status": "UP"
},
"Go": {
"code": 200,
"status": "UP"
},
"MySQL": {
"status": "DOWN",
"error": "Error 1044: Access denied for user ''@'localhost' to database 'invalid-database'",
},
"status": "DOWN"
}
Motivation ¶
It is very important to verify the status of your system, not only the system itself, but all its dependencies, If your system is not Up you can easily know what is the cause of the problem only looking the health check.
Also it serves as a kind of basic itegration test between the systems.
Inspiration ¶
I took a lot of ideas from the spring framework (http://spring.io/).
Installation ¶
This package is a go getable packake.
$ go get github.com/mschneider82/health
API ¶
The API is stable and I do not have any plans to break compatibility, but I recommend you to vendor this dependency in your project, as it is a good practice.
Testing ¶
You have to install the test dependencies.
$ go get gopkg.in/DATA-DOG/go-sqlmock.v1
or you can go get this package with the -t flag
$ go get -t github.com/mschneider82/health
Implementing custom checkers ¶
The key interface is health.Checker, you only have to implement a type that satisfies that interface.
type Checker interface {
Check() Health
}
Here an example of Disk Space usage (unix only).
package main
import (
"syscall"
"os"
)
type DiskSpaceChecker struct {
Dir string
Threshold uint64
}
func NewDiskSpaceChecker(dir string, threshold uint64) DiskSpaceChecker {
return DiskSpaceChecker{Dir: dir, Threshold: threshold}
}
func (d DiskSpaceChecker) Check() health.Health {
health := health.NewHealth()
var stat syscall.Statfs_t
wd, err := os.Getwd()
if err != nil {
health.Down().AddInfo("error", err.Error()) // Why the check is Down
return health
}
syscall.Statfs(wd, &stat)
diskFreeInBytes := stat.Bavail * uint64(stat.Bsize)
if diskFreeInBytes < d.Threshold {
health.Down()
} else {
health.Up()
}
health.
AddInfo("free", diskFreeInBytes).
AddInfo("threshold", d.Threshold)
return health
}
Important ¶
The **status** key in the json have priority over a "status" key added by a Checker, so if some checker add a "status" key to the json, it will not be rendered
Index ¶
- Constants
- func StatusOf(h Health) string
- type CachedChecker
- func (c *CachedChecker) AddChecker(name string, checker Checker)
- func (c *CachedChecker) AddInfo(key string, value interface{}) *CachedChecker
- func (c CachedChecker) Check() Health
- func (c CachedChecker) CheckContext(ctx context.Context) Health
- func (c *CachedChecker) SetTimeout(timeout time.Duration) *CachedChecker
- func (c *CachedChecker) Start(interval time.Duration)
- func (c *CachedChecker) StartContext(ctx context.Context, interval time.Duration)
- func (c *CachedChecker) Stop()
- type Checker
- type CheckerFunc
- type CompositeChecker
- type ContextChecker
- type ContextCheckerFunc
- type Handler
- type Health
Constants ¶
const ( // DefaultCachedCheckerInterval is the refresh interval used when // CachedChecker.Start is called with a non positive interval. DefaultCachedCheckerInterval = 30 * time.Second // DefaultCachedCheckerTimeout is the timeout used for a background // refresh of a CachedChecker created with NewCachedChecker. // It only bounds the refresh, so a single hanging checker cannot wedge // the refresh loop forever. DefaultCachedCheckerTimeout = 30 * time.Second )
Variables ¶
This section is empty.
Functions ¶
Types ¶
type CachedChecker ¶
type CachedChecker struct {
// contains filtered or unexported fields
}
CachedChecker is a Cached Composite Checker You need to Start() the Cache Updater
func NewCachedChecker ¶
func NewCachedChecker() CachedChecker
NewCachedChecker creates a new CachedChecker using DefaultCachedCheckerTimeout as the timeout of a background refresh.
func NewCachedCheckerWithTimeout ¶
func NewCachedCheckerWithTimeout(timeout time.Duration) CachedChecker
NewCachedCheckerWithTimeout creates a new CachedChecker which gives every background refresh at most the given timeout to complete. A non positive timeout means no timeout at all.
func (*CachedChecker) AddChecker ¶
func (c *CachedChecker) AddChecker(name string, checker Checker)
AddChecker add a Checker to the aggregator
func (*CachedChecker) AddInfo ¶
func (c *CachedChecker) AddInfo(key string, value interface{}) *CachedChecker
AddInfo adds a info value to the Info map
func (CachedChecker) Check ¶
func (c CachedChecker) Check() Health
Check returns the combination of all checkers added if some check is not up, the combined is marked as down. As long as Start was not called it returns an unknown Health.
func (CachedChecker) CheckContext ¶
func (c CachedChecker) CheckContext(ctx context.Context) Health
CheckContext returns the cached Health, it never blocks. The checks run in the background, so there is nothing ctx could cancel here, it exists so a CachedChecker satisfies the ContextChecker interface as well. A CachedChecker nested in a CompositeChecker is therefore never treated as a check which cannot be cancelled.
func (*CachedChecker) SetTimeout ¶
func (c *CachedChecker) SetTimeout(timeout time.Duration) *CachedChecker
SetTimeout sets the timeout of a background refresh. A non positive timeout means no timeout at all. It has to be called before Start, later calls do not affect a refresh loop which is already running.
func (*CachedChecker) Start ¶
func (c *CachedChecker) Start(interval time.Duration)
Start will start a background Ticker to update lastState. If interval is not positive DefaultCachedCheckerInterval is used. The refresh runs until Stop is called, use StartContext to bind it to the lifetime of a context instead.
func (*CachedChecker) StartContext ¶
func (c *CachedChecker) StartContext(ctx context.Context, interval time.Duration)
StartContext is Start bound to the given context. The background refresh ends when ctx is done or when Stop is called, whichever comes first, and every single refresh is cancelled with ctx as well. That way a CachedChecker can follow the root context of the application without an extra Stop. If interval is not positive DefaultCachedCheckerInterval is used.
func (*CachedChecker) Stop ¶
func (c *CachedChecker) Stop()
Stop the background Ticker. Stop is safe to call more than once and it does not block when Start was never called.
type Checker ¶
type Checker interface {
Check() Health
}
Checker is a interface used to provide an indication of application health.
type CheckerFunc ¶
type CheckerFunc func() Health
CheckerFunc is an adapter to allow the use of ordinary go functions as Checkers.
func (CheckerFunc) Check ¶
func (f CheckerFunc) Check() Health
type CompositeChecker ¶
type CompositeChecker struct {
// contains filtered or unexported fields
}
CompositeChecker aggregate a list of Checkers
func NewCompositeChecker ¶
func NewCompositeChecker() CompositeChecker
NewCompositeChecker creates a new CompositeChecker
func (*CompositeChecker) AddChecker ¶
func (c *CompositeChecker) AddChecker(name string, checker Checker)
AddChecker add a Checker to the aggregator
func (*CompositeChecker) AddInfo ¶
func (c *CompositeChecker) AddInfo(key string, value interface{}) *CompositeChecker
AddInfo adds a info value to the Info map
func (CompositeChecker) Check ¶
func (c CompositeChecker) Check() Health
Check returns the combination of all checkers added if some check is not up, the combined is marked as down
func (CompositeChecker) CheckContext ¶
func (c CompositeChecker) CheckContext(ctx context.Context) Health
CheckContext returns the combination of all checkers added if some check is not up, the combined is marked as down.
Every checker implementing ContextChecker gets the given context and is expected to honour it. A checker only implementing Checker cannot be cancelled, it is executed on its own goroutine so CheckContext still returns as soon as ctx is done, that sub check is then marked as down.
type ContextChecker ¶
ContextChecker is a interface used to provide an indication of application health, honouring a context supplied by the caller.
A Checker may optionally also implement ContextChecker, in that case CompositeChecker.CheckContext calls CheckContext instead of Check, so the caller is able to impose a deadline on or to cancel a running check.
type ContextCheckerFunc ¶
ContextCheckerFunc is an adapter to allow the use of ordinary go functions as ContextCheckers.
func (ContextCheckerFunc) Check ¶
func (f ContextCheckerFunc) Check() Health
Check calls f with a context.Background(), so a ContextCheckerFunc also satisfies the Checker interface and can be registered with AddChecker.
func (ContextCheckerFunc) CheckContext ¶
func (f ContextCheckerFunc) CheckContext(ctx context.Context) Health
CheckContext calls f with the given context.
type Handler ¶
type Handler struct {
CompositeChecker
}
Handler is a HTTP Server Handler implementation
type Health ¶
type Health interface {
// MarshalJSON is a custom JSON marshaller
MarshalJSON() ([]byte, error)
// AddInfo adds a info value to the Info map
AddInfo(key string, value interface{}) Health
// GetInfo returns a value from the info map
GetInfo(key string) interface{}
// IsUnknown returns true if Status is Unknown
IsUnknown() bool
// IsUp returns true if Status is Up
IsUp() bool
// IsDown returns true if Status is Down
IsDown() bool
// IsOutOfService returns true if Status is IsOutOfService
IsOutOfService() bool
// Down set the status to Down
Down() Health
// OutOfService set the status to OutOfService
OutOfService() Health
// Unknown set the status to Unknown
Unknown() Health
// Up set the status to Up
Up() Health
}
Health is a health status interface