Hootsuite Healthchecks Save

A go implementation of the Health Checks API used for microservice exploration, documentation and monitoring.

Project README

go healthchecks

Introduction

A go implementation of the Health Checks API used for microservice exploration, documentation and monitoring.

How to Use It

Using the healthchecks framework in your service is easy.

  • Define a StatusEndpoint for each dependency in your service.
  • Register the healthchecks framework to respond to all /status/... requests passing a slice of all your StatusEndpoints.
  • That's it! As long as you have defined your StatusEndpoints correctly, the framework will take care of the rest.

Example:

// Define a StatusEndpoint at '/status/db' for a database dependency
db := healthchecks.StatusEndpoint{
  Name: "The DB",
  Slug: "db",
  Type: "internal",
  IsTraversable: false,
  StatusCheck: sqlsc.SQLDBStatusChecker{
    DB: myDB
  },
  TraverseCheck: nil,
}

// Define a StatusEndpoint at '/status/service-organization' for the Organization service
org := healthchecks.StatusEndpoint{
  Name: "Organization Service",
  Slug: "service-organization",
  Type: "http",
  IsTraversable: true,
  StatusCheck: httpsc.HttpStatusChecker{
    BaseUrl: "[Read value from config]",
  },
  TraverseCheck: httpsc.HttpStatusChecker{
    BaseUrl: "[Read value from config]",
  },
}

// Define the list of StatusEndpoints for your service
statusEndpoints := []healthchecks.StatusEndpoint{ db, org }

// Set the path for the about and version files
aboutFilePath := "conf/about.json"
versionFilePath := "conf/version.txt"

// Set up any service injected customData for /status/about response.
// Values can be any valid JSON conversion and will override values set in about.json.
customData := make(map[string]interface{})
// Examples:
//
// String value
// customData["a-string"] = "some-value"
//
// Number value
// customData["a-number"] = 123
//
// Boolean value
// customData["a-bool"] = true
//
// Array
// customData["an-array"] = []string{"val1", "val2"}
//
// Custom object
// customObject := make(map[string]interface{})
// customObject["key1"] = 1
// customObject["key2"] = "some-value"
// customData["an-object"] = customObject

// Register all the "/status/..." requests to use our health checking framework
http.Handle("/status/", healthchecks.Handler(statusEndpoints, aboutFilePath, versionFilePath, customData))

Writing a StatusCheck

A StatusCheck is a struct which implements the function func CheckStatus(name string) StatusList. A StatusCheck is defined or used in a service but executed by the healthchecks framework. The key to a successful StatusCheck is to handle all errors on the dependency you are checking. Below is an example of a StatusCheck that checks the connection of Redis using the gopkg.in/redis.v4 driver.

type RedisStatusChecker struct {
	client RedisClient
}

func (r RedisStatusChecker) CheckStatus(name string) healthchecks.StatusList {
	pong, err := r.client.Ping()

	// Set a default response
	s := healthchecks.Status{
		Description:  name,
		Result: healthchecks.OK,
		Details: "",
	}

	// Handle any errors that Ping() function returned
	if err != nil {
		s = healthchecks.Status{
			Description:  name,
			Result: healthchecks.CRITICAL,
			Details: err.Error(),
		}
	}

	// Make sure the pong response is what we expected
	if pong != "PONG" {
		s = healthchecks.Status{
			Description:  name,
			Result: healthchecks.CRITICAL,
			Details: fmt.Sprintf("Expecting `PONG` response, got `%s`", pong),
		}
	}

	// Return our response
	return healthchecks.StatusList{ StatusList: []healthchecks.Status{ s }}
}

Writing a TraverseCheck

A TraverseCheck is a struct which implements the function func Traverse(traversalPath []string, action string) (string, error). A TraverseCheck is defined or used in a service but executed by the healthchecks framework. The key to a successful TraverseCheck is to build and execute the /status/traverse?action=[action]&dependencies=[dependencies] request to the service you are trying to traverse to and returning the response or error you got. Below is an example of a TraverseCheck for an HTTP service.

type HttpStatusChecker struct {
	BaseUrl string
	Name    string
}

func (h HttpStatusChecker) Traverse(traversalPath []string, action string) (string, error) {
	dependencies := ""
	if len(traversalPath) > 0 {
		dependencies = fmt.Sprintf("&dependencies=%s", strings.Join(traversalPath, ","))
	}

	// Build our HTTP request
	url := fmt.Sprintf("%s/status/traverse?action=%s%s", h.BaseUrl, action, dependencies)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		fmt.Printf("Error creating request: %s \n", err.Error())
		return "", err
	}

	// Execute HTTP request
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("Error executing request: %s \n", err.Error())
		return "", err
	}

	// Defer the closing of the body
	defer resp.Body.Close()

	// Read our response
	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("Error reading response body: %s", err.Error())
		return "", err
	}

	// Return our response
	return string(responseBody), nil
}

How To Contribute

Contribute by submitting a PR and a bug report in GitHub.

License

healthchecks is released under the Apache License, Version 2.0. See LICENSE for details.

Maintainers

Open Source Agenda is not affiliated with "Hootsuite Healthchecks" Project. README Source: hootsuite/healthchecks
Stars
131
Open Issues
2
Last Commit
4 years ago

Open Source Agenda Badge

Open Source Agenda Rating