-
Erick Hitter authored4706e3b1
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
eth-log-alerting.go 3.58 KiB
package main
import (
"flag"
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"regexp"
"syscall"
"github.com/42wim/matterbridge/matterhook"
"github.com/asaskevich/govalidator"
"github.com/hpcloud/tail"
)
type attachment struct {
Fallback string `json:"fallback,omitempty"`
Pretext string `json:"pretext,omitempty"`
Text string `json:"text"`
Color string `json:"color,omitempty"`
}
type attachments []attachment
var (
logPath string
webhookURL string
username string
channel string
color string
iconURL string
searchRegex string
mh *matterhook.Client
logger *log.Logger
debugDest string
debug bool
)
func init() {
flag.StringVar(&logPath, "log-path", "", "Log to monitor")
flag.StringVar(&webhookURL, "webhook", "", "Webhook to forward log entries to")
flag.StringVar(&username, "username", "logbot", "Username to post as")
flag.StringVar(&channel, "channel", "", "Channel to post log entries to")
flag.StringVar(&color, "color", "default", "Color for entry, either named or hex with `#`")
flag.StringVar(&iconURL, "icon-url", "", "URL of icon to use for bot")
flag.StringVar(&searchRegex, "search", "", "Search term or regex to match")
flag.StringVar(&debugDest, "debug-dest", "os.Stdout", "Destination for debug and other messages, omit to log to Stdout")
flag.BoolVar(&debug, "debug", false, "Include additional log data for debugging")
flag.Parse()
setUpLogger()
validatePath(&logPath)
if !govalidator.IsURL(webhookURL) || len(channel) < 2 {
usage()
}
mh = matterhook.New(webhookURL, matterhook.Config{DisableServer: true})
}
func main() {
logger.Printf("Monitoring %s", logPath)
logger.Printf("Forwarding entries to channel \"%s\" as user \"%s\" at %s", channel, username, webhookURL)
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
t, err := tail.TailFile(logPath, tail.Config{
Follow: true,
Location: &tail.SeekInfo{Offset: 0, Whence: 2},
MustExist: true,
ReOpen: true,
Logger: logger,
})
if err != nil {
logger.Println(err)
t.Cleanup()
close(sig)
os.Exit(3)
}
go parseLinesAndSend(t)
caughtSig := <-sig
t.Stop()
t.Cleanup()
logger.Printf("Stopping, got signal %s", caughtSig)
}
func parseLinesAndSend(t *tail.Tail) {
for line := range t.Lines {
if line.Err != nil {
continue
}
if len(searchRegex) == 0 {
go sendLine(line)
} else if matched, _ := regexp.MatchString(searchRegex, line.Text); matched {
go sendLine(line)
}
}
}
func sendLine(line *tail.Line) {
atts := attachments{
attachment{
Fallback: fmt.Sprintf("New entry in %s", logPath),
Pretext: fmt.Sprintf("In `%s` at `%s`:", logPath, line.Time),
Text: fmt.Sprintf(" %s", line.Text),
Color: color,
},
}
mh.Send(matterhook.OMessage{
Channel: channel,
UserName: username,
Attachments: atts,
IconURL: iconURL,
})
}
func setUpLogger() {
logOpts := log.Ldate | log.Ltime | log.LUTC | log.Lshortfile
if debugDest == "os.Stdout" {
logger = log.New(os.Stdout, "DEBUG: ", logOpts)
} else {
path, err := filepath.Abs(debugDest)
if err != nil {
logger.Fatal(err)
}
logFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
logger = log.New(logFile, "", logOpts)
}
}
func validatePath(path *string) {
if len(*path) > 1 {
var err error
*path, err = filepath.Abs(*path)
if err != nil {
fmt.Printf("Error: %s", err.Error())
os.Exit(3)
}
if _, err = os.Stat(*path); os.IsNotExist(err) {
usage()
}
} else {
usage()
}
}
func usage() {
flag.Usage()
os.Exit(3)
}