https://github.com/orange-cloudfoundry/statusetat
status page with very HA in mind and notifier
https://github.com/orange-cloudfoundry/statusetat
high-availability notifications status-page
Last synced: 5 months ago
JSON representation
status page with very HA in mind and notifier
- Host: GitHub
- URL: https://github.com/orange-cloudfoundry/statusetat
- Owner: orange-cloudfoundry
- License: apache-2.0
- Created: 2020-07-03T14:52:11.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2026-01-12T21:11:48.000Z (5 months ago)
- Last Synced: 2026-01-13T01:44:34.351Z (5 months ago)
- Topics: high-availability, notifications, status-page
- Language: Go
- Homepage:
- Size: 27.8 MB
- Stars: 20
- Watchers: 5
- Forks: 6
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Statusetat [](https://github.com/orange-cloudfoundry/statusetat/actions?query=workflow%3Aginkgo-test)
status page with very HA in mind and notification system to send information about incident(s) or scheduled task(s)
to external system like slack, email or whatever plugin you implement.
[](/screenshots/home_one_incident_and_maintenance.png)
Features:
- Easy admin web interface to manage incidents and scheduled tasks
- Send notifications to external system (slack, email, plugins...) when incident come
- Full rest api to create/read/update/delete incident/scheduled tasks
- Subscribes systems
## Why another status page ?
A status page **must** be more resilient than the service you want to be monitored because you need to have the page
always available even when your a part of your infra is partially down to give the information to your client.
When you're a hosting service be more resilient on your status page become complicated.
This implementation allow you to set multiple storage system in same time to ensure you always can store/retrieve incidents and
scheduled tasks.
Statusetat will replicate in all storage what you write and ensure that the data can be retrieved.
## Getting started
1. Download latest release for your system
2. Create a `config.yml` file with this content for a dev deployment
```yaml
listen: 0.0.0.0:8080 # this will listen in http on port 8080
targets:
- sqlite://./store.db
log:
level: debug
components:
- name: my-service
description: description of my service
group: ~
notifiers:
- type: slack
params:
endpoint: http://my-mattermost.com/hooks/aj6na7hz5ib1mfs3eggc1bu8tk
- type: plugin
params:
path: /path/to/my/plugin.so
username: admin
password: admin
cookie_key: encryption-key-for-cookies
base_info:
base_url: http://localhost:8080
support: https://doc.to.my.service.com
contact: http://my-mattermost.com/channel/town
time_zone: UTC
```
## Configuration
For understanding config definition format:
- `[]` means optional (by default parameter is required)
- `<>` means type to use
### Root configuration in config.yml
```yaml
# Listen address for listening in http
# If empty and env var `PORT` set default listen will 0.0.0.0:${PORT}
[ listen: | default = 0.0.0.0:8080 ]
# If config tls not set no https will be enabled
# only set tls if you want https on statusetat
tls:
# Path to cert file
[ cert_file: ]
# Path to key file
[ key_file: ]
log:
# log level to use for server
# you can chose: `trace`, `debug`, `info`, `warn`, `error`, `fatal` or `panic`
[ level: | default = info ]
# Set to true to force not have color when seeing logs
[ no_color: ]
# et to true to see logs as json format
[ in_json: ]
# username for basic authentication to access admin page or api
username:
# password for basic authentication to access admin page or api
password:
# cookie key for cookie encryption (generate a random value and set it here)
cookie_key:
base_info:
# Url of your statusetat for forging urls on notifications
base_url:
# Title of your status page
[ title: | default = "Statusetat" ]
# Url for your user to know where they can found support/doc page
[ support: ]
# Url for your user to know where they can contact you
[ contact: ]
# Default timezone when creating/updating/show incident(s)
[ timezone: | default = "UTC" ]
# customize web page
theme:
# Markdown content to show before status boxes
[ pre_status: ]
# Markdown content to show after status boxes
[ post_status: ]
# Markdown content to show before timeline
[ pre_timeline: ]
# Markdown content to show after timeline
[ post_timeline: ]
# Markdown content to show before maintenance/scheduled tasks box
[ pre_maintenance: ]
# Markdown content to show after maintenance/scheduled tasks box
[ post_maintenance: ]
# Markdown content to put in footer
[ footer: ]
# Persistent name to display, default to Persistent Incident but you could set Known Issues for example
[ persistent_display_name: ]
# Markdown content to show before persistent incident tasks box
[ pre_persistent: ]
# Markdown content to show after persistent incident tasks box
[ post_persistent: ]
# list of targets store to use, this can be in form of:
# mysql://user:password@host:3306?options
# mariadb://user:password@host:3306?options
# postgres://user:password@host:3306?options
# sqlite://:memory:
# sqlite:///a/path
# s3://access_key_id:access_key_secret@host.com/bucket?region=us-east-1&insecure-skip-verify=false
# file:///a/path/to/a/folder
targets:
-
notifiers:
[ - ]
```
### notifiers configuration
```yaml
# type of notifier to use, you can found them in notifiers section of this doc
type:
# only trigger for particular component(s)
[ for: ]
# map of params for the notifier you use
params:
[ : ]
```
### for_component configurations
```yaml
# Set to true to mandatory match all filter
# Think that you want to use an AND condition on true and OR condition on false
[require_all: | default = false ]
# Group which match component(s)
groups:
[ - ]
# Names which match component(s)
names:
[ - ]
```
## Notifiers
### Slack
Notify on a slack channel or mattermost channel new incidents or scheduled tasks.
- **Type name**: `slack`
- **Params**:
```yaml
# incoming endpoint url
endpoint:
# Specify channel to send notif
[ channel: ]
# Specify username to show on message
[ channel: ]
# Specify icon emoji incident to show on message
[ icon_emoji_incident: | default = "bell" ]
# Specify icon emoji scheduled tasks to show when planified
[ icon_emoji_scheduled: | default = "clock1" ]
# Specify icon emoji scheduled tasks to show when started
[ icon_emoji_scheduled_started: | default = "clock1" ]
# Specify icon emoji scheduled tasks to show when finished
[ icon_emoji_scheduled_finish: | default = "clock1" ]
# skip ssl verification when sending notification
[ insecure_skip_verify: ]
```
### Grafana annotation
Put a grafana annotation when incident start and when it's finished on a graph.
- **Type name**: `grafana_annotation`
- **Params**:
```yaml
# Grafana api endpoint
endpoint:
# Grafana api key to use
api_key:
# Dashboard id to set annotation
dashboard_id:
# Panel id in dashboard to set annotation
panel_id:
# tag used in grafana to filter global annotations
[ tag: ]
# time zone to use when sending annotation
[ time_zone: ]
# skip ssl verification when sending notification
[ insecure_skip_verify: ]
# organization id to use when sending annotation
[ org_id: ]
```
### Email
Send incidents and scheduled tasks to subscribers via subscribe api and/or emails in notifier param.
**Type name**: `email`
**Params**:
```yaml
# Email server host
host:
# Email server port
[ port: | default = 25 ]
# Username to use when connect to email server
[ username: ]
# Password to use when connect to email server
[ password: ]
# Set to true to use ssl/tls when connect to email server
[ use_ssl: ]
# Email to insert in from field
[ From: | default = "no-reply@local" ]
# List of emails address to send email, e.g.: admins of the monitored service
subscribers:
[ - ]
# Go template to use to write subject for incident
[ subject_incident: | default = "[{{ .TitleSite }} {{ .Incident.State | textIncidentState | title }} Incident] {{ .IncidentTitle | title }}" ]
# Go template to use to write subject for scheduled tasks
[ subject_scheduled: | default = "[{{ .TitleSite }} Scheduled task] {{ .IncidentTitle | title }}" ]
# Go template to use to write content of email when get an incident
[ txt_incident: ]
```
For customize content of email you can see data passed to template at https://github.com/orange-cloudfoundry/statusetat/blob/master/notifiers/email/email.go#L223-L236
and template function available at https://github.com/orange-cloudfoundry/statusetat/blob/master/extemplate/template.go#L25-L51
## Plugin
You can create a plugin for notification for your own need.
Plugin are grpc golang plugin which doc can be found here: https://github.com/hashicorp/go-plugin .
You must implement [plugin.Notifier](/notifiers/plugin/interface.go).
Example of implementation:
```go
package main
import (
pluginhc "github.com/hashicorp/go-plugin"
"github.com/orange-cloudfoundry/statusetat/config"
"github.com/orange-cloudfoundry/statusetat/models"
"github.com/orange-cloudfoundry/statusetat/notifiers/plugin"
log "github.com/sirupsen/logrus"
"strings"
)
type LogNotifier struct {
}
func (n LogNotifier) PreCheck(incident *models.Incident) error {
return nil
}
func (n *LogNotifier) Init(baseInfo config.BaseInfo, params map[string]interface{}) error {
return nil
}
func (n LogNotifier) Name() (string, error) {
return "log_notifier", nil
}
func (n LogNotifier) Id() (string, error) {
return "log_notifier1", nil
}
func (n LogNotifier) MetadataFields() ([]models.MetadataField, error) {
return []models.MetadataField{}, nil
}
func (n LogNotifier) Notify(notifyReq *models.NotifyRequest) error {
log.
WithField("subscribers", strings.Join(notifyReq.Subscribers, ", ")).
WithField("triggerred_by_user", notifyReq.TriggerByUser).
Info(notifyReq.Incident)
return nil
}
func main() {
pluginhc.Serve(&pluginhc.ServeConfig{
HandshakeConfig: plugin.Handshake,
Plugins: map[string]pluginhc.Plugin{
"notifier": &plugin.NotifierGRPCPlugin{
Impl: &LogNotifier{},
},
},
// A non-nil value here enables gRPC serving for this plugin...
GRPCServer: pluginhc.DefaultGRPCServer,
})
}
```
You can build it with command line `go build -o log-notif .`
You can now use it in your config with:
- **Type name**: `plugin` or notifier name you have set in func signature `Name() string`
- **Params**:
```yaml
# path to .so to load
# in our example it would be `./log-notif`
path:
# all remaining arguments will be pass at Init
```
## Api
To document
## Credits
This project was heavily inspired by [statusfy](https://github.com/juliomrqz/statusfy) mostly on the design part and
models of incidents/components.
[Cachethq](https://cachethq.io/) is another source of inspiration for some details on the admin design part.