2020-08-22 02:07:46 +00:00
|
|
|
![Gatus](static/logo-with-name.png)
|
2019-09-14 23:59:05 +00:00
|
|
|
|
2020-04-10 21:19:59 +00:00
|
|
|
![build](https://github.com/TwinProduction/gatus/workflows/build/badge.svg?branch=master)
|
2020-08-18 02:21:20 +00:00
|
|
|
[![Go Report Card](https://goreportcard.com/badge/github.com/TwinProduction/gatus)](https://goreportcard.com/report/github.com/TwinProduction/gatus)
|
2019-09-14 23:59:05 +00:00
|
|
|
[![Docker pulls](https://img.shields.io/docker/pulls/twinproduction/gatus.svg)](https://cloud.docker.com/repository/docker/twinproduction/gatus)
|
2019-09-04 23:37:13 +00:00
|
|
|
|
2019-09-14 23:25:59 +00:00
|
|
|
A service health dashboard in Go that is meant to be used as a docker
|
|
|
|
image with a custom configuration file.
|
2019-09-11 01:05:57 +00:00
|
|
|
|
2020-04-18 16:13:09 +00:00
|
|
|
I personally deploy it in my Kubernetes cluster and have it monitor the status of my
|
|
|
|
core applications: https://status.twinnation.org/
|
2019-11-11 21:15:35 +00:00
|
|
|
|
2019-09-11 01:05:57 +00:00
|
|
|
|
2020-08-28 02:23:21 +00:00
|
|
|
## Table of Contents
|
|
|
|
|
|
|
|
- [Usage](#usage)
|
|
|
|
- [Configuration](#configuration)
|
|
|
|
- [Conditions](#conditions)
|
|
|
|
- [Docker](#docker)
|
|
|
|
- [Running the tests](#running-the-tests)
|
|
|
|
- [Using in Production](#using-in-production)
|
|
|
|
- [FAQ](#faq)
|
|
|
|
- [Sending a GraphQL request](#sending-a-graphql-request)
|
|
|
|
- [Configuring Slack alerts](#configuring-slack-alerts)
|
|
|
|
- [Configuring custom alert](#configuring-custom-alerts)
|
|
|
|
|
|
|
|
|
2019-09-09 01:07:08 +00:00
|
|
|
## Usage
|
2019-09-04 23:37:13 +00:00
|
|
|
|
2020-03-08 22:16:39 +00:00
|
|
|
By default, the configuration file is expected to be at `config/config.yaml`.
|
|
|
|
|
|
|
|
You can specify a custom path by setting the `GATUS_CONFIG_FILE` environment variable.
|
|
|
|
|
2020-04-15 00:13:06 +00:00
|
|
|
Here's a simple example:
|
|
|
|
|
2019-09-04 23:37:13 +00:00
|
|
|
```yaml
|
2019-11-16 20:49:06 +00:00
|
|
|
metrics: true # Whether to expose metrics at /metrics
|
2019-09-04 23:37:13 +00:00
|
|
|
services:
|
2019-09-09 01:07:08 +00:00
|
|
|
- name: twinnation # Name of your service, can be anything
|
2020-08-28 02:23:21 +00:00
|
|
|
url: "https://twinnation.org/health"
|
|
|
|
interval: 30s # Duration to wait between every status check (default: 10s)
|
2019-09-04 23:37:13 +00:00
|
|
|
conditions:
|
2020-04-12 03:14:20 +00:00
|
|
|
- "[STATUS] == 200" # Status must be 200
|
2020-04-15 00:13:06 +00:00
|
|
|
- "[BODY].status == UP" # The json path "$.status" must be equal to UP
|
2020-04-12 03:14:20 +00:00
|
|
|
- "[RESPONSE_TIME] < 300" # Response time must be under 300ms
|
2020-04-15 00:13:06 +00:00
|
|
|
- name: example
|
2020-08-28 02:23:21 +00:00
|
|
|
url: "https://example.org/"
|
2020-04-12 03:17:31 +00:00
|
|
|
interval: 30s
|
2019-09-09 01:07:08 +00:00
|
|
|
conditions:
|
2019-12-04 22:27:27 +00:00
|
|
|
- "[STATUS] == 200"
|
2019-09-09 01:07:08 +00:00
|
|
|
```
|
|
|
|
|
2019-12-04 22:27:27 +00:00
|
|
|
Note that you can also add environment variables in the your configuration file (i.e. `$DOMAIN`, `${DOMAIN}`)
|
|
|
|
|
2019-09-09 01:07:08 +00:00
|
|
|
|
2020-04-15 00:13:06 +00:00
|
|
|
### Configuration
|
|
|
|
|
2020-08-22 18:15:44 +00:00
|
|
|
| Parameter | Description | Default |
|
|
|
|
| --------------------------------- | --------------------------------------------------------------- | -------------- |
|
|
|
|
| `metrics` | Whether to expose metrics at /metrics | `false` |
|
2020-08-28 02:23:21 +00:00
|
|
|
| `services` | List of services to monitor | Required `[]` |
|
2020-08-22 18:15:44 +00:00
|
|
|
| `services[].name` | Name of the service. Can be anything. | Required `""` |
|
|
|
|
| `services[].url` | URL to send the request to | Required `""` |
|
|
|
|
| `services[].conditions` | Conditions used to determine the health of the service | `[]` |
|
|
|
|
| `services[].interval` | Duration to wait between every status check | `10s` |
|
|
|
|
| `services[].method` | Request method | `GET` |
|
|
|
|
| `services[].graphql` | Whether to wrap the body in a query param (`{"query":"$body"}`) | `false` |
|
|
|
|
| `services[].body` | Request body | `""` |
|
|
|
|
| `services[].headers` | Request headers | `{}` |
|
2020-08-28 02:23:21 +00:00
|
|
|
| `services[].alerts[].type` | Type of alert. Valid types: `slack`, `custom` | Required `""` |
|
2020-08-22 18:15:44 +00:00
|
|
|
| `services[].alerts[].enabled` | Whether to enable the alert | `false` |
|
|
|
|
| `services[].alerts[].threshold` | Number of failures in a row needed before triggering the alert | `3` |
|
|
|
|
| `services[].alerts[].description` | Description of the alert. Will be included in the alert sent | `""` |
|
2020-08-28 02:23:21 +00:00
|
|
|
| `alerting` | Configuration for alerting | `{}` |
|
|
|
|
| `alerting.slack` | Webhook to use for alerts of type `slack` | `""` |
|
|
|
|
| `alerting.custom` | Configuration for custom actions on failure or alerts | `""` |
|
|
|
|
| `alerting.custom.url` | Custom alerting request url | `""` |
|
|
|
|
| `alerting.custom.body` | Custom alerting request body. | `""` |
|
|
|
|
| `alerting.custom.headers` | Custom alerting request headers | `{}` |
|
2020-04-15 00:13:06 +00:00
|
|
|
|
|
|
|
|
2020-04-10 20:34:20 +00:00
|
|
|
### Conditions
|
|
|
|
|
|
|
|
Here are some examples of conditions you can use:
|
|
|
|
|
2020-08-13 01:42:13 +00:00
|
|
|
| Condition | Description | Passing values | Failing values |
|
|
|
|
| -----------------------------| ------------------------------------------------------- | ------------------------ | ----------------------- |
|
|
|
|
| `[STATUS] == 200` | Status must be equal to 200 | 200 | 201, 404, 500 |
|
|
|
|
| `[STATUS] < 300` | Status must lower than 300 | 200, 201, 299 | 301, 302, 400, 500 |
|
|
|
|
| `[STATUS] <= 299` | Status must be less than or equal to 299 | 200, 201, 299 | 301, 302, 400, 500 |
|
|
|
|
| `[STATUS] > 400` | Status must be greater than 400 | 401, 402, 403, 404 | 200, 201, 300, 400 |
|
|
|
|
| `[RESPONSE_TIME] < 500` | Response time must be below 500ms | 100ms, 200ms, 300ms | 500ms, 1500ms |
|
|
|
|
| `[BODY] == 1` | The body must be equal to 1 | 1 | literally anything else |
|
|
|
|
| `[BODY].data.id == 1` | The jsonpath `$.data.id` is equal to 1 | `{"data":{"id":1}}` | literally anything else |
|
|
|
|
| `[BODY].data[0].id == 1` | The jsonpath `$.data[0].id` is equal to 1 | `{"data":[{"id":1}]}` | literally anything else |
|
|
|
|
| `len([BODY].data) > 0` | Array at jsonpath `$.data` has less than 5 elements | `{"data":[{"id":1}]}` | `{"data":[{"id":1}]}` |
|
|
|
|
| `len([BODY].name) == 8` | String at jsonpath `$.name` has a length of 8 | `{"name":"john.doe"}` | `{"name":"bob"}` |
|
2020-04-12 23:51:28 +00:00
|
|
|
|
|
|
|
**NOTE**: `[BODY]` with JSON path (i.e. `[BODY].id == 1`) is currently in BETA. For the most part, the only thing that doesn't work is arrays.
|
2020-04-10 20:34:20 +00:00
|
|
|
|
|
|
|
|
2019-10-28 01:17:55 +00:00
|
|
|
## Docker
|
|
|
|
|
|
|
|
Building the Docker image is done as following:
|
2019-09-09 01:07:08 +00:00
|
|
|
|
|
|
|
```
|
2019-10-28 01:17:55 +00:00
|
|
|
docker build . -t gatus
|
2019-09-09 01:07:08 +00:00
|
|
|
```
|
2019-09-14 23:25:59 +00:00
|
|
|
|
2019-10-28 01:17:55 +00:00
|
|
|
You can then run the container with the following command:
|
2019-09-14 23:25:59 +00:00
|
|
|
|
2019-10-28 01:17:55 +00:00
|
|
|
```
|
|
|
|
docker run -p 8080:8080 --name gatus gatus
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Running the tests
|
2019-09-14 23:25:59 +00:00
|
|
|
|
|
|
|
```
|
2019-10-28 01:17:55 +00:00
|
|
|
go test ./... -mod vendor
|
2019-09-14 23:25:59 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Using in Production
|
|
|
|
|
|
|
|
See the [example](example) folder.
|
2020-07-24 20:45:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
## FAQ
|
|
|
|
|
|
|
|
### Sending a GraphQL request
|
|
|
|
|
|
|
|
By setting `services[].graphql` to true, the body will automatically be wrapped by the standard GraphQL `query` parameter.
|
|
|
|
|
|
|
|
For instance, the following configuration:
|
2020-08-15 22:34:05 +00:00
|
|
|
```yaml
|
2020-07-24 20:45:51 +00:00
|
|
|
services:
|
2020-07-24 22:38:35 +00:00
|
|
|
- name: filter users by gender
|
2020-07-24 20:45:51 +00:00
|
|
|
url: http://localhost:8080/playground
|
|
|
|
method: POST
|
|
|
|
graphql: true
|
|
|
|
body: |
|
|
|
|
{
|
|
|
|
user(gender: "female") {
|
|
|
|
id
|
|
|
|
name
|
|
|
|
gender
|
|
|
|
avatar
|
|
|
|
}
|
|
|
|
}
|
|
|
|
headers:
|
|
|
|
Content-Type: application/json
|
|
|
|
conditions:
|
|
|
|
- "[STATUS] == 200"
|
|
|
|
- "[BODY].data.user[0].gender == female"
|
|
|
|
```
|
|
|
|
|
|
|
|
will send a `POST` request to `http://localhost:8080/playground` with the following body:
|
|
|
|
```json
|
|
|
|
{"query":" {\n user(gender: \"female\") {\n id\n name\n gender\n avatar\n }\n }"}
|
2020-08-22 18:15:44 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Configuring Slack alerts
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
alerting:
|
2020-08-28 02:23:21 +00:00
|
|
|
slack: "https://hooks.slack.com/services/**********/**********/**********"
|
2020-08-22 18:15:44 +00:00
|
|
|
services:
|
|
|
|
- name: twinnation
|
|
|
|
interval: 30s
|
2020-08-28 02:23:21 +00:00
|
|
|
url: "https://twinnation.org/health"
|
2020-08-22 18:15:44 +00:00
|
|
|
alerts:
|
|
|
|
- type: slack
|
|
|
|
enabled: true
|
|
|
|
description: "healthcheck failed 3 times in a row"
|
|
|
|
- type: slack
|
|
|
|
enabled: true
|
|
|
|
threshold: 5
|
|
|
|
description: "healthcheck failed 5 times in a row"
|
|
|
|
conditions:
|
|
|
|
- "[STATUS] == 200"
|
|
|
|
- "[BODY].status == UP"
|
|
|
|
- "[RESPONSE_TIME] < 300"
|
2020-08-28 02:23:21 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Configuring custom alerts
|
|
|
|
|
|
|
|
While they're called alerts, you can use this feature to call anything.
|
|
|
|
|
|
|
|
For instance, you could automate rollbacks by having an application that keeps tracks of new deployments, and by
|
|
|
|
leveraging Gatus, you could have Gatus call that application endpoint when a service starts failing. Your application
|
|
|
|
would then check if the service that started failing was recently deployed, and if it was, then automatically
|
|
|
|
roll it back.
|
|
|
|
|
|
|
|
The values `[ALERT_DESCRIPTION]` and `[SERVICE_NAME]` are automatically substituted for the alert description and the
|
2020-08-28 05:03:52 +00:00
|
|
|
service name respectively in the body (`alerting.custom.body`) and the url (`alerting.custom.url`).
|
2020-08-28 02:23:21 +00:00
|
|
|
|
|
|
|
For all intents and purpose, we'll configure the custom alert with a Slack webhook, but you can call anything you want.
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
alerting:
|
|
|
|
custom:
|
|
|
|
url: "https://hooks.slack.com/services/**********/**********/**********"
|
|
|
|
method: "POST"
|
|
|
|
body: |
|
|
|
|
{
|
|
|
|
"text": "[SERVICE_NAME] - [ALERT_DESCRIPTION]"
|
|
|
|
}
|
|
|
|
services:
|
|
|
|
- name: twinnation
|
|
|
|
interval: 30s
|
|
|
|
url: "https://twinnation.org/health"
|
|
|
|
alerts:
|
|
|
|
- type: custom
|
|
|
|
enabled: true
|
|
|
|
threshold: 10
|
|
|
|
description: "healthcheck failed 10 times in a row"
|
|
|
|
conditions:
|
|
|
|
- "[STATUS] == 200"
|
|
|
|
- "[BODY].status == UP"
|
|
|
|
- "[RESPONSE_TIME] < 300"
|
2020-07-24 20:45:51 +00:00
|
|
|
```
|