Skip to content
Snippets Groups Projects
Commit b9193650 authored by Erick Hitter's avatar Erick Hitter
Browse files

Implement goroutine per log file

parent dc687c32
Branches
Tags
1 merge request!1Convert to Golang
Pipeline #
This commit is part of merge request !1. Comments created here will be created in the context of that merge request.
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
"io/ioutil"
"log" "log"
"os" "os"
"os/signal" "os/signal"
...@@ -17,21 +18,19 @@ import ( ...@@ -17,21 +18,19 @@ import (
) )
type config struct { type config struct {
DebugDest string DebugDest string `json:"debug-dest"`
Debug bool Debug bool `json:"debug"`
Logs logConfigs Logs []logConfig `json:"logs"`
} }
type logConfigs []logConfig
type logConfig struct { type logConfig struct {
logPath string LogPath string `json:"log_path"`
webhookURL string WebhookURL string `json:"webhook_url"`
username string Username string `json:"username"`
channel string Channel string `json:"channel"`
color string Color string `json:"color"`
iconURL string IconURL string `json:"icon_url"`
searchRegex string SearchRegex string `json:"search"`
} }
type attachment struct { type attachment struct {
...@@ -44,15 +43,8 @@ type attachment struct { ...@@ -44,15 +43,8 @@ type attachment struct {
type attachments []attachment type attachments []attachment
var ( var (
logPath string // Deprecate configPath string
webhookURL string // Deprecate logConfigs []logConfig
username string // Deprecate
channel string // Deprecate
color string // Deprecate
iconURL string // Deprecate
searchRegex string // Deprecate
mh *matterhook.Client // Deprecate
logger *log.Logger logger *log.Logger
debugDest string debugDest string
...@@ -60,102 +52,115 @@ var ( ...@@ -60,102 +52,115 @@ var (
) )
func init() { func init() {
var configPath string
// 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.StringVar(&configPath, "config", "./config.json", "Path to configuration file") flag.StringVar(&configPath, "config", "./config.json", "Path to configuration file")
flag.Parse() flag.Parse()
validatePath(&configPath) cfgPathValid := validatePath(&configPath)
if !cfgPathValid {
usage()
}
configFile, err := os.Open(configPath) configFile, err := ioutil.ReadFile(configPath)
jsonDecoder := json.NewDecoder(configFile)
config := config{}
err = jsonDecoder.Decode(&config)
if err != nil { if err != nil {
usage() usage()
} }
fmt.Println(fmt.Sprintf("%+v\n", config)) config := config{}
os.Exit(3) if err = json.Unmarshal(configFile, &config); err != nil {
setUpLogger()
validatePath(&logPath)
if !govalidator.IsURL(webhookURL) || len(channel) < 2 {
usage() usage()
} }
// mh = matterhook.New(webhookURL, matterhook.Config{DisableServer: true}) debugDest = config.DebugDest
debug = config.Debug
setUpLogger()
logConfigs = config.Logs
} }
func main() { func main() {
// logger.Printf("Monitoring %s", logPath) logger.Printf("Starting log monitoring with config %s", configPath)
// logger.Printf("Forwarding entries to channel \"%s\" as user \"%s\" at %s", channel, username, webhookURL)
sig := make(chan os.Signal, 1) sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
// t, err := tail.TailFile(logPath, tail.Config{ for _, logCfg := range logConfigs {
// Follow: true, go tailLog(logCfg)
// 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 caughtSig := <-sig
// t.Stop()
// t.Cleanup()
logger.Printf("Stopping, got signal %s", caughtSig) logger.Printf("Stopping, got signal %s", caughtSig)
} }
func parseLinesAndSend(t *tail.Tail) { func tailLog(logCfg logConfig) {
if logPathValid := validatePath(&logCfg.LogPath); !logPathValid {
if debug {
logger.Println("Invalid path: ", fmt.Sprintf("%+v\n", logCfg))
}
return
}
if !govalidator.IsURL(logCfg.WebhookURL) || len(logCfg.Username) == 0 || len(logCfg.Channel) < 2 {
if debug {
logger.Println("Invalid webhook, username, channel: ", fmt.Sprintf("%+v\n", logCfg))
}
return
}
t, err := tail.TailFile(logCfg.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()
return
}
mh := matterhook.New(logCfg.WebhookURL, matterhook.Config{DisableServer: true})
parseLinesAndSend(t, mh, logCfg)
t.Stop()
t.Cleanup()
}
func parseLinesAndSend(t *tail.Tail, mh *matterhook.Client, logCfg logConfig) {
for line := range t.Lines { for line := range t.Lines {
if line.Err != nil { if line.Err != nil {
continue continue
} }
if len(searchRegex) == 0 { if len(logCfg.SearchRegex) == 0 {
go sendLine(line) go sendLine(line, mh, logCfg)
} else if matched, _ := regexp.MatchString(searchRegex, line.Text); matched { } else if matched, _ := regexp.MatchString(logCfg.SearchRegex, line.Text); matched {
go sendLine(line) go sendLine(line, mh, logCfg)
} }
} }
} }
func sendLine(line *tail.Line) { func sendLine(line *tail.Line, mh *matterhook.Client, logCfg logConfig) {
// atts := attachments{ atts := attachments{
// attachment{ attachment{
// Fallback: fmt.Sprintf("New entry in %s", logPath), Fallback: fmt.Sprintf("New entry in %s", logCfg.LogPath),
// Pretext: fmt.Sprintf("In `%s` at `%s`:", logPath, line.Time), Pretext: fmt.Sprintf("In `%s` at `%s`:", logCfg.LogPath, line.Time),
// Text: fmt.Sprintf(" %s", line.Text), Text: fmt.Sprintf(" %s", line.Text),
// Color: color, Color: logCfg.Color,
// }, },
// } }
// mh.Send(matterhook.OMessage{ mh.Send(matterhook.OMessage{
// Channel: channel, Channel: logCfg.Channel,
// UserName: username, UserName: logCfg.Username,
// Attachments: atts, Attachments: atts,
// IconURL: iconURL, IconURL: logCfg.IconURL,
// }) })
} }
func setUpLogger() { func setUpLogger() {
...@@ -178,22 +183,24 @@ func setUpLogger() { ...@@ -178,22 +183,24 @@ func setUpLogger() {
} }
} }
func validatePath(path *string) { func validatePath(path *string) bool {
if len(*path) > 1 { if len(*path) <= 1 {
var err error return false
*path, err = filepath.Abs(*path) }
if err != nil { var err error
fmt.Printf("Error: %s", err.Error()) *path, err = filepath.Abs(*path)
os.Exit(3)
}
if _, err = os.Stat(*path); os.IsNotExist(err) { if err != nil {
usage() logger.Printf("Error: %s", err.Error())
} return false
} else {
usage()
} }
if _, err = os.Stat(*path); os.IsNotExist(err) {
return false
}
return true
} }
func usage() { func usage() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment