health

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Jul 29, 2026 License: MIT Imports: 5 Imported by: 0

README

Go Report Card GoDoc

This is a fork of github.com/dimiro1/health.

Go Health Check

An easy to use, extensible health check library for Go applications.

Table of Contents

Example

package main

import (
    "net/http"
    "database/sql"
    "time"

    "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)
    timeout := 5 * time.Second
    
    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.NewCheckerWithTimeout("https://golang.org/", timeout))
    handler.AddChecker("Big Companies", companies)
    handler.AddChecker("MySQL", mysql)
    handler.AddChecker("Redis", redis.NewChecker("tcp", ":6379"))

    http.Handle("/health/", handler)
    http.ListenAndServe(":8080", nil)
}
$ 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'",
    },
    "Redis": {
        "status": "UP",
        "version": "3.0.5"
    },
    "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 integration test between the systems.

Inspiration

I took a lot of ideas from the spring framework.

Installation

This package is a go getable package.

$ go get github.com/mschneider82/health

The core package has no dependencies at all. Every checker which needs a third party package is a module of its own, so you only pull in what you use.

$ go get github.com/mschneider82/health/url
$ go get github.com/mschneider82/health/db
$ go get github.com/mschneider82/health/tcp
$ go get github.com/mschneider82/health/redis

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
$ go get github.com/rafaeljusto/redigomock

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 is 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 has priority over a status key added by a Checker, so if some checker adds a status key to the json, it will not be rendered

Implemented health check indicators

Health Description Package
url.Checker Check the connection with some URL https://github.com/mschneider82/health/tree/master/url
db.Checker Check the connection with the database https://github.com/mschneider82/health/tree/master/db
redis.Checker Check the connection with the redis https://github.com/mschneider82/health/tree/master/redis

LICENSE

The MIT License (MIT)

Copyright (c) 2016 Claudemiro

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

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

View Source
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

func StatusOf

func StatusOf(h Health) string

StatusOf returns the status of h as a string, one of "UP", "DOWN", "OUT OF SERVICE" or "UNKNOWN". A nil Health is reported as "UNKNOWN".

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

type ContextChecker interface {
	CheckContext(ctx context.Context) Health
}

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

type ContextCheckerFunc func(ctx context.Context) Health

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

func NewHandler

func NewHandler() Handler

NewHandler returns a new Handler

func (Handler) ServeHTTP

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP returns a json encoded Health set the status to http.StatusServiceUnavailable if the check is down

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

func NewHealth

func NewHealth() Health

NewHealth return a new Health with status Down

Directories

Path Synopsis
db module
redis module
tcp module
url module

Jump to

Keyboard shortcuts

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