refactoring
This commit is contained in:
106
cli/main.go
106
cli/main.go
@@ -1,31 +1,105 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
|
||||||
cachet "github.com/castawaylabs/cachet-monitor"
|
cachet "github.com/castawaylabs/cachet-monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var configPath string
|
||||||
|
var systemName string
|
||||||
|
var logPath string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cachet.New()
|
flag.StringVar(&configPath, "c", "/etc/cachet-monitor.config.json", "Config path")
|
||||||
config := cachet.Config
|
flag.StringVar(&systemName, "name", "", "System Name")
|
||||||
log := cachet.Logger
|
flag.StringVar(&logPath, "log", "", "Log path")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
log.Printf("System: %s, Interval: %d second(s), API: %s\n", config.SystemName, config.Interval, config.APIUrl)
|
cfg, err := getConfiguration(configPath)
|
||||||
log.Printf("Starting %d monitors:\n", len(config.Monitors))
|
if err != nil {
|
||||||
for _, mon := range config.Monitors {
|
panic(err)
|
||||||
log.Printf(" %s: GET %s & Expect HTTP %d\n", mon.Name, mon.URL, mon.ExpectedStatusCode)
|
|
||||||
if mon.MetricID > 0 {
|
|
||||||
log.Printf(" - Logs lag to metric id: %d\n", mon.MetricID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println()
|
if len(systemName) > 0 {
|
||||||
|
cfg.SystemName = systemName
|
||||||
|
}
|
||||||
|
if len(logPath) > 0 {
|
||||||
|
cfg.LogPath = logPath
|
||||||
|
}
|
||||||
|
|
||||||
ticker := time.NewTicker(time.Duration(config.Interval) * time.Second)
|
if len(os.Getenv("CACHET_API")) > 0 {
|
||||||
for range ticker.C {
|
cfg.APIUrl = os.Getenv("CACHET_API")
|
||||||
for _, mon := range config.Monitors {
|
|
||||||
go mon.Run()
|
|
||||||
}
|
}
|
||||||
|
if len(os.Getenv("CACHET_TOKEN")) > 0 {
|
||||||
|
cfg.APIToken = os.Getenv("CACHET_TOKEN")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cfg.ValidateConfiguration(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLogger(logPath string) *log.Logger {
|
||||||
|
var logWriter = os.Stdout
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if len(logPath) > 0 {
|
||||||
|
logWriter, err = os.Create(logPath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Unable to open file '%v' for logging\n", logPath)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := log.Llongfile | log.Ldate | log.Ltime
|
||||||
|
if len(os.Getenv("CACHET_DEV")) > 0 {
|
||||||
|
flags = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return log.New(logWriter, "", flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfiguration(path string) (*cachet.CachetMonitor, error) {
|
||||||
|
var cfg cachet.CachetMonitor
|
||||||
|
var data []byte
|
||||||
|
|
||||||
|
// test if its a url
|
||||||
|
url, err := url.ParseRequestURI(path)
|
||||||
|
if err == nil && len(url.Scheme) > 0 {
|
||||||
|
// download config
|
||||||
|
response, err := http.Get(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Cannot download network config: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
defer response.Body.Close()
|
||||||
|
data, _ = ioutil.ReadAll(response.Body)
|
||||||
|
|
||||||
|
fmt.Println("Downloaded network configuration.")
|
||||||
|
} else {
|
||||||
|
data, err = ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Config file '" + path + "' missing!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &cfg); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return nil, errors.New("Cannot parse config!")
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Logger = getLogger(cfg.LogPath)
|
||||||
|
|
||||||
|
return &cfg, nil
|
||||||
}
|
}
|
||||||
|
|||||||
20
component.go
20
component.go
@@ -1,20 +0,0 @@
|
|||||||
package cachet
|
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
// Component Cachet model
|
|
||||||
type Component struct {
|
|
||||||
ID json.Number `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Status json.Number `json:"status_id"`
|
|
||||||
HumanStatus string `json:"-"`
|
|
||||||
IncidentCount int `json:"-"`
|
|
||||||
CreatedAt *string `json:"created_at"`
|
|
||||||
UpdatedAt *string `json:"updated_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComponentData json response model
|
|
||||||
type ComponentData struct {
|
|
||||||
Component Component `json:"data"`
|
|
||||||
}
|
|
||||||
100
config.go
100
config.go
@@ -1,117 +1,47 @@
|
|||||||
package cachet
|
package cachet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Static config
|
type CachetMonitor struct {
|
||||||
var Config CachetConfig
|
Logger *log.Logger `json:"-"`
|
||||||
|
|
||||||
// Central logger
|
|
||||||
var Logger *log.Logger
|
|
||||||
|
|
||||||
// CachetConfig is the monitoring tool configuration
|
|
||||||
type CachetConfig struct {
|
|
||||||
APIUrl string `json:"api_url"`
|
APIUrl string `json:"api_url"`
|
||||||
APIToken string `json:"api_token"`
|
APIToken string `json:"api_token"`
|
||||||
Interval int64 `json:"interval"`
|
Interval int64 `json:"interval"`
|
||||||
Monitors []*Monitor `json:"monitors"`
|
|
||||||
SystemName string `json:"system_name"`
|
SystemName string `json:"system_name"`
|
||||||
LogPath string `json:"log_path"`
|
LogPath string `json:"log_path"`
|
||||||
InsecureAPI bool `json:"insecure_api"`
|
InsecureAPI bool `json:"insecure_api"`
|
||||||
|
|
||||||
|
Monitors []*Monitor `json:"monitors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() error {
|
func (mon *CachetMonitor) ValidateConfiguration() error {
|
||||||
var configPath string
|
if mon.Logger == nil {
|
||||||
var systemName string
|
mon.Logger = log.New(os.Stdout, "", log.Llongfile|log.Ldate|log.Ltime)
|
||||||
var logPath string
|
|
||||||
flag.StringVar(&configPath, "c", "/etc/cachet-monitor.config.json", "Config path")
|
|
||||||
flag.StringVar(&systemName, "name", "", "System Name")
|
|
||||||
flag.StringVar(&logPath, "log", "", "Log path")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
var data []byte
|
|
||||||
|
|
||||||
// test if its a url
|
|
||||||
url, err := url.ParseRequestURI(configPath)
|
|
||||||
if err == nil && len(url.Scheme) > 0 {
|
|
||||||
// download config
|
|
||||||
response, err := http.Get(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("Cannot download network config: " + err.Error())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defer response.Body.Close()
|
if len(mon.SystemName) == 0 {
|
||||||
data, _ = ioutil.ReadAll(response.Body)
|
|
||||||
|
|
||||||
fmt.Println("Downloaded network configuration.")
|
|
||||||
} else {
|
|
||||||
data, err = ioutil.ReadFile(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("Config file '" + configPath + "' missing!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(data, &Config); err != nil {
|
|
||||||
return errors.New("Cannot parse config!")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(systemName) > 0 {
|
|
||||||
Config.SystemName = systemName
|
|
||||||
}
|
|
||||||
if len(Config.SystemName) == 0 {
|
|
||||||
// get hostname
|
// get hostname
|
||||||
Config.SystemName = getHostname()
|
mon.SystemName = getHostname()
|
||||||
}
|
|
||||||
if Config.Interval <= 0 {
|
|
||||||
Config.Interval = 60
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(os.Getenv("CACHET_API")) > 0 {
|
if mon.Interval <= 0 {
|
||||||
Config.APIUrl = os.Getenv("CACHET_API")
|
mon.Interval = 60
|
||||||
}
|
|
||||||
if len(os.Getenv("CACHET_TOKEN")) > 0 {
|
|
||||||
Config.APIToken = os.Getenv("CACHET_TOKEN")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(Config.APIToken) == 0 || len(Config.APIUrl) == 0 {
|
if len(mon.APIToken) == 0 || len(mon.APIUrl) == 0 {
|
||||||
return errors.New("API URL or API Token not set. cachet-monitor won't be able to report incidents.\n\nPlease set:\n CACHET_API and CACHET_TOKEN environment variable to override settings.\n\nGet help at https://github.com/CastawayLabs/cachet-monitor\n")
|
return errors.New("API URL or API Token not set. cachet-monitor won't be able to report incidents.\n\nPlease set:\n CACHET_API and CACHET_TOKEN environment variable to override settings.\n\nGet help at https://github.com/castawaylabs/cachet-monitor\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(Config.Monitors) == 0 {
|
if len(mon.Monitors) == 0 {
|
||||||
return errors.New("No monitors defined!\nSee sample configuration: https://github.com/CastawayLabs/cachet-monitor/blob/master/example.config.json\n")
|
return errors.New("No monitors defined!\nSee sample configuration: https://github.com/castawaylabs/cachet-monitor/blob/master/example.config.json\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(logPath) > 0 {
|
|
||||||
Config.LogPath = logPath
|
|
||||||
}
|
|
||||||
|
|
||||||
var logWriter io.Writer
|
|
||||||
logWriter = os.Stdout
|
|
||||||
if len(Config.LogPath) > 0 {
|
|
||||||
logWriter, err = os.Create(Config.LogPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("Unable to open file '" + Config.LogPath + "' for logging\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := log.Llongfile | log.Ldate | log.Ltime
|
|
||||||
if len(os.Getenv("DEVELOPMENT")) > 0 {
|
|
||||||
flags = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger = log.New(logWriter, "", flags)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
45
http.go
Normal file
45
http.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package cachet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Component Cachet model
|
||||||
|
type Component struct {
|
||||||
|
ID json.Number `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Status json.Number `json:"status_id"`
|
||||||
|
HumanStatus string `json:"-"`
|
||||||
|
IncidentCount int `json:"-"`
|
||||||
|
CreatedAt *string `json:"created_at"`
|
||||||
|
UpdatedAt *string `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (monitor *CachetMonitor) makeRequest(requestType string, url string, reqBody []byte) (*http.Response, []byte, error) {
|
||||||
|
req, err := http.NewRequest(requestType, monitor.APIUrl+url, bytes.NewBuffer(reqBody))
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("X-Cachet-Token", monitor.APIToken)
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
if monitor.InsecureAPI == true {
|
||||||
|
client.Transport = &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
body, _ := ioutil.ReadAll(res.Body)
|
||||||
|
|
||||||
|
return res, body, nil
|
||||||
|
}
|
||||||
100
incident.go
100
incident.go
@@ -2,6 +2,8 @@ package cachet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,36 +20,26 @@ type Incident struct {
|
|||||||
UpdatedAt *string `json:"updated_at"`
|
UpdatedAt *string `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IncidentData is a response when creating/updating an incident
|
|
||||||
type IncidentData struct {
|
|
||||||
Incident Incident `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// IncidentList - from API /incidents
|
|
||||||
type IncidentList struct {
|
|
||||||
Incidents []Incident `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetIncidents - Get list of incidents
|
// GetIncidents - Get list of incidents
|
||||||
func GetIncidents() []Incident {
|
func (monitor *CachetMonitor) GetIncidents() ([]Incident, error) {
|
||||||
_, body, err := makeRequest("GET", "/incidents", nil)
|
_, body, err := monitor.makeRequest("GET", "/incidents", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.Printf("Cannot get incidents: %v\n", err)
|
return []Incident{}, fmt.Errorf("Cannot get incidents: %v\n", err)
|
||||||
return []Incident{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var data IncidentList
|
var data struct {
|
||||||
|
Incidents []Incident `json:"data"`
|
||||||
|
}
|
||||||
err = json.Unmarshal(body, &data)
|
err = json.Unmarshal(body, &data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.Printf("Cannot parse incidents: %v\n", err)
|
return []Incident{}, fmt.Errorf("Cannot parse incidents: %v\n", err)
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.Incidents
|
return data.Incidents, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send - Create or Update incident
|
// Send - Create or Update incident
|
||||||
func (incident *Incident) Send() {
|
func (monitor *CachetMonitor) SendIncident(incident *Incident) error {
|
||||||
jsonBytes, _ := json.Marshal(map[string]interface{}{
|
jsonBytes, _ := json.Marshal(map[string]interface{}{
|
||||||
"name": incident.Name,
|
"name": incident.Name,
|
||||||
"message": incident.Message,
|
"message": incident.Message,
|
||||||
@@ -63,58 +55,57 @@ func (incident *Incident) Send() {
|
|||||||
requestURL += "/" + string(incident.ID)
|
requestURL += "/" + string(incident.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, body, err := makeRequest(requestType, requestURL, jsonBytes)
|
resp, body, err := monitor.makeRequest(requestType, requestURL, jsonBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.Printf("Cannot create/update incident: %v\n", err)
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Println(strconv.Itoa(resp.StatusCode) + " " + string(body))
|
var data struct {
|
||||||
|
Incident Incident `json:"data"`
|
||||||
var data IncidentData
|
}
|
||||||
err = json.Unmarshal(body, &data)
|
if err := json.Unmarshal(body, &data); err != nil {
|
||||||
if err != nil {
|
return errors.New("Cannot parse incident body." + string(body))
|
||||||
Logger.Println("Cannot parse incident body.", string(body))
|
|
||||||
panic(err)
|
|
||||||
} else {
|
} else {
|
||||||
incident.ID = data.Incident.ID
|
incident.ID = data.Incident.ID
|
||||||
incident.Component = data.Incident.Component
|
incident.Component = data.Incident.Component
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
Logger.Println("Could not create/update incident!")
|
return errors.New("Could not create/update incident!")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (incident *Incident) fetchComponent() error {
|
|
||||||
_, body, err := makeRequest("GET", "/components/"+string(*incident.ComponentID), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var data ComponentData
|
|
||||||
err = json.Unmarshal(body, &data)
|
|
||||||
if err != nil {
|
|
||||||
Logger.Println("Cannot parse component body. %v", string(body))
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
incident.Component = &data.Component
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (incident *Incident) UpdateComponent() {
|
func (monitor *CachetMonitor) fetchComponent(componentID string) (*Component, error) {
|
||||||
|
_, body, err := monitor.makeRequest("GET", "/components/"+componentID, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data struct {
|
||||||
|
Component Component `json:"data"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(body, &data); err != nil {
|
||||||
|
return nil, errors.New("Cannot parse component body. " + string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &data.Component, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (monitor *CachetMonitor) UpdateComponent(incident *Incident) error {
|
||||||
if incident.ComponentID == nil || len(*incident.ComponentID) == 0 {
|
if incident.ComponentID == nil || len(*incident.ComponentID) == 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if incident.Component == nil {
|
if incident.Component == nil {
|
||||||
// fetch component
|
// fetch component
|
||||||
if err := incident.fetchComponent(); err != nil {
|
component, err := monitor.fetchComponent(string(*incident.ComponentID))
|
||||||
Logger.Printf("Cannot fetch component for incident. %v\n", err)
|
if err != nil {
|
||||||
return
|
return fmt.Errorf("Cannot fetch component for incident. %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
incident.Component = component
|
||||||
}
|
}
|
||||||
|
|
||||||
status, _ := strconv.Atoi(string(incident.Status))
|
status, _ := strconv.Atoi(string(incident.Status))
|
||||||
@@ -133,11 +124,12 @@ func (incident *Incident) UpdateComponent() {
|
|||||||
"status": incident.Component.Status,
|
"status": incident.Component.Status,
|
||||||
})
|
})
|
||||||
|
|
||||||
resp, _, err := makeRequest("PUT", "/components/"+string(incident.Component.ID), jsonBytes)
|
resp, _, err := monitor.makeRequest("PUT", "/components/"+string(incident.Component.ID), jsonBytes)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil || resp.StatusCode != 200 {
|
||||||
Logger.Printf("Could not update component: (resp code %d) %v", resp.StatusCode, err)
|
return fmt.Errorf("Could not update component: (resp code %d) %v", resp.StatusCode, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetInvestigating sets status to Investigating
|
// SetInvestigating sets status to Investigating
|
||||||
|
|||||||
12
metrics.go
12
metrics.go
@@ -2,22 +2,24 @@ package cachet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SendMetric sends lag metric point
|
// SendMetric sends lag metric point
|
||||||
func SendMetric(metricID int, delay int64) {
|
func (monitor *CachetMonitor) SendMetric(metricID int, delay int64) error {
|
||||||
if metricID <= 0 {
|
if metricID <= 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBytes, _ := json.Marshal(&map[string]interface{}{
|
jsonBytes, _ := json.Marshal(&map[string]interface{}{
|
||||||
"value": delay,
|
"value": delay,
|
||||||
})
|
})
|
||||||
|
|
||||||
resp, _, err := makeRequest("POST", "/metrics/"+strconv.Itoa(metricID)+"/points", jsonBytes)
|
resp, _, err := monitor.makeRequest("POST", "/metrics/"+strconv.Itoa(metricID)+"/points", jsonBytes)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil || resp.StatusCode != 200 {
|
||||||
Logger.Printf("Could not log data point!\n%v\n", err)
|
return fmt.Errorf("Could not log data point!\n%v\n", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
40
monitor.go
40
monitor.go
@@ -23,6 +23,28 @@ type Monitor struct {
|
|||||||
History []bool `json:"-"`
|
History []bool `json:"-"`
|
||||||
LastFailReason *string `json:"-"`
|
LastFailReason *string `json:"-"`
|
||||||
Incident *Incident `json:"-"`
|
Incident *Incident `json:"-"`
|
||||||
|
config *CachetMonitor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *CachetMonitor) Run() {
|
||||||
|
cfg.Logger.Printf("System: %s\nInterval: %d second(s)\nAPI: %s\n\n", cfg.SystemName, cfg.Interval, cfg.APIUrl)
|
||||||
|
cfg.Logger.Printf("Starting %d monitors:\n", len(cfg.Monitors))
|
||||||
|
for _, mon := range cfg.Monitors {
|
||||||
|
cfg.Logger.Printf(" %s: GET %s & Expect HTTP %d\n", mon.Name, mon.URL, mon.ExpectedStatusCode)
|
||||||
|
if mon.MetricID > 0 {
|
||||||
|
cfg.Logger.Printf(" - Logs lag to metric id: %d\n", mon.MetricID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Logger.Println()
|
||||||
|
|
||||||
|
ticker := time.NewTicker(time.Duration(cfg.Interval) * time.Second)
|
||||||
|
for range ticker.C {
|
||||||
|
for _, mon := range cfg.Monitors {
|
||||||
|
mon.config = cfg
|
||||||
|
go mon.Run()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run loop
|
// Run loop
|
||||||
@@ -38,7 +60,7 @@ func (monitor *Monitor) Run() {
|
|||||||
monitor.AnalyseData()
|
monitor.AnalyseData()
|
||||||
|
|
||||||
if isUp == true && monitor.MetricID > 0 {
|
if isUp == true && monitor.MetricID > 0 {
|
||||||
SendMetric(monitor.MetricID, lag)
|
monitor.config.SendMetric(monitor.MetricID, lag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +103,7 @@ func (monitor *Monitor) AnalyseData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t := (float32(numDown) / float32(len(monitor.History))) * 100
|
t := (float32(numDown) / float32(len(monitor.History))) * 100
|
||||||
Logger.Printf("%s %.2f%% Down at %v. Threshold: %.2f%%\n", monitor.URL, t, time.Now().UnixNano()/int64(time.Second), monitor.Threshold)
|
monitor.config.Logger.Printf("%s %.2f%% Down at %v. Threshold: %.2f%%\n", monitor.URL, t, time.Now().UnixNano()/int64(time.Second), monitor.Threshold)
|
||||||
|
|
||||||
if len(monitor.History) != 10 {
|
if len(monitor.History) != 10 {
|
||||||
// not enough data
|
// not enough data
|
||||||
@@ -90,11 +112,11 @@ func (monitor *Monitor) AnalyseData() {
|
|||||||
|
|
||||||
if t > monitor.Threshold && monitor.Incident == nil {
|
if t > monitor.Threshold && monitor.Incident == nil {
|
||||||
// is down, create an incident
|
// is down, create an incident
|
||||||
Logger.Println("Creating incident...")
|
monitor.config.Logger.Println("Creating incident...")
|
||||||
|
|
||||||
component_id := json.Number(strconv.Itoa(*monitor.ComponentID))
|
component_id := json.Number(strconv.Itoa(*monitor.ComponentID))
|
||||||
monitor.Incident = &Incident{
|
monitor.Incident = &Incident{
|
||||||
Name: monitor.Name + " - " + Config.SystemName,
|
Name: monitor.Name + " - " + monitor.config.SystemName,
|
||||||
Message: monitor.Name + " check failed",
|
Message: monitor.Name + " check failed",
|
||||||
ComponentID: &component_id,
|
ComponentID: &component_id,
|
||||||
}
|
}
|
||||||
@@ -107,11 +129,11 @@ func (monitor *Monitor) AnalyseData() {
|
|||||||
monitor.Incident.SetInvestigating()
|
monitor.Incident.SetInvestigating()
|
||||||
|
|
||||||
// create/update incident
|
// create/update incident
|
||||||
monitor.Incident.Send()
|
monitor.config.SendIncident(monitor.Incident)
|
||||||
monitor.Incident.UpdateComponent()
|
monitor.config.UpdateComponent(monitor.Incident)
|
||||||
} else if t < monitor.Threshold && monitor.Incident != nil {
|
} else if t < monitor.Threshold && monitor.Incident != nil {
|
||||||
// was down, created an incident, its now ok, make it resolved.
|
// was down, created an incident, its now ok, make it resolved.
|
||||||
Logger.Println("Updating incident to resolved...")
|
monitor.config.Logger.Println("Updating incident to resolved...")
|
||||||
|
|
||||||
component_id := json.Number(strconv.Itoa(*monitor.ComponentID))
|
component_id := json.Number(strconv.Itoa(*monitor.ComponentID))
|
||||||
monitor.Incident = &Incident{
|
monitor.Incident = &Incident{
|
||||||
@@ -121,8 +143,8 @@ func (monitor *Monitor) AnalyseData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
monitor.Incident.SetFixed()
|
monitor.Incident.SetFixed()
|
||||||
monitor.Incident.Send()
|
monitor.config.SendIncident(monitor.Incident)
|
||||||
monitor.Incident.UpdateComponent()
|
monitor.config.UpdateComponent(monitor.Incident)
|
||||||
|
|
||||||
monitor.Incident = nil
|
monitor.Incident = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ Environment variables
|
|||||||
| ------------ | --------------------------- | --------------------------- |
|
| ------------ | --------------------------- | --------------------------- |
|
||||||
| CACHET_API | http://demo.cachethq.io/api | URL endpoint for cachet api |
|
| CACHET_API | http://demo.cachethq.io/api | URL endpoint for cachet api |
|
||||||
| CACHET_TOKEN | randomvalue | API Authentication token |
|
| CACHET_TOKEN | randomvalue | API Authentication token |
|
||||||
| DEVELOPMENT | 1 | Strips logging |
|
| CACHET_DEV | 1 | Strips logging |
|
||||||
|
|
||||||
Vision and goals
|
Vision and goals
|
||||||
----------------
|
----------------
|
||||||
|
|||||||
32
request.go
32
request.go
@@ -1,32 +0,0 @@
|
|||||||
package cachet
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeRequest(requestType string, url string, reqBody []byte) (*http.Response, []byte, error) {
|
|
||||||
req, err := http.NewRequest(requestType, Config.APIUrl+url, bytes.NewBuffer(reqBody))
|
|
||||||
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
req.Header.Set("X-Cachet-Token", Config.APIToken)
|
|
||||||
|
|
||||||
client := &http.Client{}
|
|
||||||
if Config.InsecureAPI == true {
|
|
||||||
client.Transport = &http.Transport{
|
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer res.Body.Close()
|
|
||||||
body, _ := ioutil.ReadAll(res.Body)
|
|
||||||
|
|
||||||
return res, body, nil
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user