basic refactor + new prototype
This commit is contained in:
7
api.go
Normal file
7
api.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package cachet
|
||||||
|
|
||||||
|
type CachetAPI struct {
|
||||||
|
Url string `json:"api_url"`
|
||||||
|
Token string `json:"api_token"`
|
||||||
|
Insecure bool `json:"insecure"`
|
||||||
|
}
|
||||||
122
cli/main.go
122
cli/main.go
@@ -3,40 +3,60 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
cachet "github.com/castawaylabs/cachet-monitor"
|
cachet "github.com/castawaylabs/cachet-monitor"
|
||||||
|
docopt "github.com/docopt/docopt-go"
|
||||||
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var configPath string
|
const usage = `cachet-monitor
|
||||||
var systemName string
|
|
||||||
var logPath string
|
Usage:
|
||||||
|
cachet-monitor (-c PATH | --config PATH) [--log=LOGPATH] [--name=NAME]
|
||||||
|
cachet-monitor -h | --help | --version
|
||||||
|
cachet-monitor print-config
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
PATH path to config.yml
|
||||||
|
LOGPATH path to log output (defaults to STDOUT)
|
||||||
|
NAME name of this logger
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
cachet-monitor -c /root/cachet-monitor.yml
|
||||||
|
cachet-monitor -c /root/cachet-monitor.yml --log=/var/log/cachet-monitor.log --name="development machine"
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-c PATH.yml --config PATH Path to configuration file
|
||||||
|
-h --help Show this screen.
|
||||||
|
--version Show version
|
||||||
|
print-config Print example configuration
|
||||||
|
|
||||||
|
Environment varaibles:
|
||||||
|
CACHET_API override API url from configuration
|
||||||
|
CACHET_TOKEN override API token from configuration
|
||||||
|
CACHET_DEV set to enable dev logging`
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.StringVar(&configPath, "c", "/etc/cachet-monitor.config.json", "Config path")
|
arguments, _ := docopt.Parse(usage, nil, true, "cachet-monitor", false)
|
||||||
flag.StringVar(&systemName, "name", "", "System Name")
|
|
||||||
flag.StringVar(&logPath, "log", "", "Log path")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
cfg, err := getConfiguration(configPath)
|
cfg, err := getConfiguration(arguments["--config"].(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
logrus.Panicf("Unable to start (reading config): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(systemName) > 0 {
|
if name := arguments["--name"]; name != nil {
|
||||||
cfg.SystemName = systemName
|
cfg.SystemName = name.(string)
|
||||||
}
|
|
||||||
if len(logPath) > 0 {
|
|
||||||
cfg.LogPath = logPath
|
|
||||||
}
|
}
|
||||||
|
logrus.SetOutput(getLogger(arguments["--log"]))
|
||||||
|
|
||||||
if len(os.Getenv("CACHET_API")) > 0 {
|
if len(os.Getenv("CACHET_API")) > 0 {
|
||||||
cfg.APIUrl = os.Getenv("CACHET_API")
|
cfg.APIUrl = os.Getenv("CACHET_API")
|
||||||
@@ -44,29 +64,39 @@ func main() {
|
|||||||
if len(os.Getenv("CACHET_TOKEN")) > 0 {
|
if len(os.Getenv("CACHET_TOKEN")) > 0 {
|
||||||
cfg.APIToken = os.Getenv("CACHET_TOKEN")
|
cfg.APIToken = os.Getenv("CACHET_TOKEN")
|
||||||
}
|
}
|
||||||
|
if len(os.Getenv("CACHET_DEV")) > 0 {
|
||||||
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
}
|
||||||
|
|
||||||
if err := cfg.ValidateConfiguration(); err != nil {
|
if err := cfg.ValidateConfiguration(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.Logger.Printf("System: %s\nAPI: %s\nMonitors: %d\n\n", cfg.SystemName, cfg.APIUrl, len(cfg.Monitors))
|
logrus.Infof("System: %s\nAPI: %s\nMonitors: %d\n\n", cfg.SystemName, cfg.APIUrl, len(cfg.Monitors))
|
||||||
|
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
for _, mon := range cfg.Monitors {
|
for _, mon := range cfg.Monitors {
|
||||||
cfg.Logger.Printf(" Starting %s: %d seconds check interval\n - %v %s (%d second/s timeout)", mon.Name, mon.CheckInterval, mon.Method, mon.URL, mon.HttpTimeout)
|
l := logrus.WithFields(logrus.Fields{
|
||||||
|
"name": mon.Name,
|
||||||
|
"interval": mon.CheckInterval,
|
||||||
|
"method": mon.Method,
|
||||||
|
"url": mon.URL,
|
||||||
|
"timeout": mon.HttpTimeout,
|
||||||
|
})
|
||||||
|
l.Info(" Starting monitor")
|
||||||
|
|
||||||
// print features
|
// print features
|
||||||
if mon.ExpectedStatusCode > 0 {
|
if mon.ExpectedStatusCode > 0 {
|
||||||
cfg.Logger.Printf(" - Expect HTTP %d", mon.ExpectedStatusCode)
|
l.Infof(" - Expect HTTP %d", mon.ExpectedStatusCode)
|
||||||
}
|
}
|
||||||
if len(mon.ExpectedBody) > 0 {
|
if len(mon.ExpectedBody) > 0 {
|
||||||
cfg.Logger.Printf(" - Expect Body to match \"%v\"", mon.ExpectedBody)
|
l.Infof(" - Expect Body to match \"%v\"", mon.ExpectedBody)
|
||||||
}
|
}
|
||||||
if mon.MetricID > 0 {
|
if mon.MetricID > 0 {
|
||||||
cfg.Logger.Printf(" - Log lag to metric id %d\n", mon.MetricID)
|
l.Infof(" - Log lag to metric id %d\n", mon.MetricID)
|
||||||
}
|
}
|
||||||
if mon.ComponentID > 0 {
|
if mon.ComponentID > 0 {
|
||||||
cfg.Logger.Printf(" - Update component id %d\n\n", mon.ComponentID)
|
l.Infof(" - Update component id %d\n\n", mon.ComponentID)
|
||||||
}
|
}
|
||||||
|
|
||||||
go mon.Start(cfg, wg)
|
go mon.Start(cfg, wg)
|
||||||
@@ -76,7 +106,7 @@ func main() {
|
|||||||
signal.Notify(signals, os.Interrupt, os.Kill)
|
signal.Notify(signals, os.Interrupt, os.Kill)
|
||||||
<-signals
|
<-signals
|
||||||
|
|
||||||
cfg.Logger.Println("Abort: Waiting monitors to finish")
|
logrus.Warnf("Abort: Waiting monitors to finish")
|
||||||
for _, mon := range cfg.Monitors {
|
for _, mon := range cfg.Monitors {
|
||||||
mon.Stop()
|
mon.Stop()
|
||||||
}
|
}
|
||||||
@@ -84,24 +114,17 @@ func main() {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLogger(logPath string) *log.Logger {
|
func getLogger(logPath *string) *os.File {
|
||||||
var logWriter = os.Stdout
|
if logPath == nil || len(*logPath) == 0 {
|
||||||
var err error
|
return os.Stdout
|
||||||
|
|
||||||
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 file, err := os.Create(logPath); err != nil {
|
||||||
if len(os.Getenv("CACHET_DEV")) > 0 {
|
logrus.Errorf("Unable to open file '%v' for logging: \n%v", logPath, err)
|
||||||
flags = 0
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
return log.New(logWriter, "", flags)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConfiguration(path string) (*cachet.CachetMonitor, error) {
|
func getConfiguration(path string) (*cachet.CachetMonitor, error) {
|
||||||
@@ -114,26 +137,31 @@ func getConfiguration(path string) (*cachet.CachetMonitor, error) {
|
|||||||
// download config
|
// download config
|
||||||
response, err := http.Get(path)
|
response, err := http.Get(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Cannot download network config: " + err.Error())
|
logrus.Warn("Unable to download network configuration")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
data, _ = ioutil.ReadAll(response.Body)
|
data, _ = ioutil.ReadAll(response.Body)
|
||||||
|
|
||||||
fmt.Println("Downloaded network configuration.")
|
logrus.Info("Downloaded network configuration.")
|
||||||
} else {
|
} else {
|
||||||
data, err = ioutil.ReadFile(path)
|
data, err = ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Config file '" + path + "' missing!")
|
return nil, errors.New("Unable to open file: '" + path + "'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(data, &cfg); err != nil {
|
// test file path for yml
|
||||||
fmt.Println(err)
|
if strings.HasSuffix(path, ".yml") || strings.HasSuffix(path, ".yaml") {
|
||||||
return nil, errors.New("Cannot parse config!")
|
err = yaml.Unmarshal(data, &cfg)
|
||||||
|
} else {
|
||||||
|
err = json.Unmarshal(data, &cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.Logger = getLogger(cfg.LogPath)
|
if err != nil {
|
||||||
|
logrus.Warnf("Unable to parse configuration file")
|
||||||
|
}
|
||||||
|
|
||||||
return &cfg, nil
|
return &cfg, err
|
||||||
}
|
}
|
||||||
|
|||||||
59
config.go
59
config.go
@@ -1,65 +1,58 @@
|
|||||||
package cachet
|
package cachet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"log"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CachetMonitor struct {
|
type CachetMonitor struct {
|
||||||
Logger *log.Logger `json:"-"`
|
Name string `json:"system_name"`
|
||||||
|
API CachetAPI `json:"api"`
|
||||||
APIUrl string `json:"api_url"`
|
|
||||||
APIToken string `json:"api_token"`
|
|
||||||
SystemName string `json:"system_name"`
|
|
||||||
LogPath string `json:"log_path"`
|
|
||||||
InsecureAPI bool `json:"insecure_api"`
|
|
||||||
|
|
||||||
Monitors []*Monitor `json:"monitors"`
|
Monitors []*Monitor `json:"monitors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *CachetMonitor) ValidateConfiguration() error {
|
func (cfg *CachetMonitor) Validate() bool {
|
||||||
if cfg.Logger == nil {
|
valid := true
|
||||||
cfg.Logger = log.New(os.Stdout, "", log.Llongfile|log.Ldate|log.Ltime)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cfg.SystemName) == 0 {
|
if len(cfg.Name) == 0 {
|
||||||
// get hostname
|
// get hostname
|
||||||
cfg.SystemName = getHostname()
|
cfg.Name = getHostname()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.APIToken) == 0 || len(cfg.APIUrl) == 0 {
|
if len(cfg.API.Token) == 0 || len(cfg.API.Url) == 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")
|
logrus.Warnf("API URL or API Token missing.\nGet help at https://github.com/castawaylabs/cachet-monitor")
|
||||||
|
valid = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.Monitors) == 0 {
|
if len(cfg.Monitors) == 0 {
|
||||||
return errors.New("No monitors defined!\nSee sample configuration: https://github.com/castawaylabs/cachet-monitor/blob/master/example.config.json\n")
|
logrus.Warnf("No monitors defined!\nSee help for example configuration")
|
||||||
|
valid = false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, monitor := range cfg.Monitors {
|
for _, monitor := range cfg.Monitors {
|
||||||
if err := monitor.ValidateConfiguration(); err != nil {
|
if err := monitor.Validate(); !valid {
|
||||||
return err
|
valid = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return valid
|
||||||
}
|
}
|
||||||
|
|
||||||
// getHostname returns id of the current system
|
// getHostname returns id of the current system
|
||||||
func getHostname() string {
|
func getHostname() string {
|
||||||
hostname, err := os.Hostname()
|
hostname, err := os.Hostname()
|
||||||
if err != nil || len(hostname) == 0 {
|
if err == nil && len(hostname) > 0 {
|
||||||
addrs, err := net.InterfaceAddrs()
|
return hostname
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, addr := range addrs {
|
|
||||||
return addr.String()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hostname
|
addrs, err := net.InterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
return addr.String()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
example.config.yml
Normal file
16
example.config.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
apiurl: https://demo.cachethq.io/api/v1
|
||||||
|
apitoken: 9yMHsdioQosnyVK4iCVR
|
||||||
|
insecureapi: true
|
||||||
|
monitors:
|
||||||
|
- name: google
|
||||||
|
type: http
|
||||||
|
url: https://google.com
|
||||||
|
stricttls: true
|
||||||
|
threshold: 80
|
||||||
|
componentid: 1
|
||||||
|
interval: 10
|
||||||
|
timeout: 5
|
||||||
|
expectedstatuscode: 200
|
||||||
|
headers:
|
||||||
|
- name: Authorization
|
||||||
|
value: Basic <xyz>
|
||||||
20
http.go
20
http.go
@@ -7,10 +7,30 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type HttpMonitor struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
StrictTLS bool `json:"strict_tls"`
|
||||||
|
CheckInterval time.Duration `json:"interval"`
|
||||||
|
HttpTimeout time.Duration `json:"timeout"`
|
||||||
|
|
||||||
|
// Threshold = percentage
|
||||||
|
Threshold float32 `json:"threshold"`
|
||||||
|
ExpectedStatusCode int `json:"expected_status_code"`
|
||||||
|
// compiled to Regexp
|
||||||
|
ExpectedBody string `json:"expected_body"`
|
||||||
|
bodyRegexp *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
type TCPMonitor struct{}
|
||||||
|
type ICMPMonitor struct{}
|
||||||
|
type DNSMonitor struct{}
|
||||||
|
|
||||||
func (monitor *CachetMonitor) makeRequest(requestType string, url string, reqBody []byte) (*http.Response, []byte, error) {
|
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, err := http.NewRequest(requestType, monitor.APIUrl+url, bytes.NewBuffer(reqBody))
|
||||||
|
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ func (monitor *Monitor) AnalyseData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (monitor *Monitor) ValidateConfiguration() error {
|
func (monitor *Monitor) Validate() error {
|
||||||
if len(monitor.ExpectedBody) > 0 {
|
if len(monitor.ExpectedBody) > 0 {
|
||||||
exp, err := regexp.Compile(monitor.ExpectedBody)
|
exp, err := regexp.Compile(monitor.ExpectedBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user