From 5d49a73fff696ecb5dd3f39c2938fb4d25c3a8d9 Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Mon, 8 Apr 2019 08:38:01 +0300 Subject: [PATCH 01/17] Add logging flags --- cmd/jiralert/main.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index f446182..4278592 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -13,6 +13,8 @@ import ( "github.com/free/jiralert/pkg/config" "github.com/free/jiralert/pkg/notify" "github.com/free/jiralert/pkg/template" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" _ "net/http/pprof" @@ -22,11 +24,15 @@ import ( const ( unknownReceiver = "" + logFormatLogfmt = "logfmt" + logFormatJson = "json" ) var ( listenAddress = flag.String("listen-address", ":9097", "The address to listen on for HTTP requests.") configFile = flag.String("config", "config/jiralert.yml", "The JIRAlert configuration file") + logLevel = flag.String("log.level", "info", "Log filtering level") + logFormat = flag.String("log.format", logFormatLogfmt, "Log format to use") // Version is the build version, set by make to latest git tag/hash via `-ldflags "-X main.Version=$(VERSION)"`. Version = "" From 70ca015957bfe4b5495130104f6041f647036889 Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Mon, 8 Apr 2019 08:59:44 +0300 Subject: [PATCH 02/17] Update log messages in main --- cmd/jiralert/main.go | 63 ++++++++++++++++++++++++++++++-------------- go.mod | 4 ++- go.sum | 14 +++++----- 3 files changed, 54 insertions(+), 27 deletions(-) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index 4278592..8d90ece 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -18,7 +18,6 @@ import ( _ "net/http/pprof" - log "github.com/golang/glog" "github.com/prometheus/client_golang/prometheus/promhttp" ) @@ -44,54 +43,73 @@ func main() { runtime.SetMutexProfileFraction(1) } - // Override -alsologtostderr default value. - if alsoLogToStderr := flag.Lookup("alsologtostderr"); alsoLogToStderr != nil { - alsoLogToStderr.DefValue = "true" - alsoLogToStderr.Value.Set("true") - } flag.Parse() - log.Infof("Starting JIRAlert version %s", Version) + var logger log.Logger + { + var lvl level.Option + switch *logLevel { + case "error": + lvl = level.AllowError() + case "warn": + lvl = level.AllowWarn() + case "info": + lvl = level.AllowInfo() + case "debug": + lvl = level.AllowDebug() + default: + panic("unexpected log level") + } + logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) + if *logFormat == logFormatJson { + logger = log.NewJSONLogger(log.NewSyncWriter(os.Stderr)) + } + logger = level.NewFilter(logger, lvl) + + logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) + } + + level.Info(logger).Log("msg", "starting JIRAlert", "version", Version) config, _, err := config.LoadFile(*configFile) if err != nil { - log.Fatalf("Error loading configuration: %s", err) + level.Error(logger).Log("msg", "error loading configuration", "path", *configFile, "err", err) } tmpl, err := template.LoadTemplate(config.Template) if err != nil { - log.Fatalf("Error loading templates from %s: %s", config.Template, err) + level.Error(logger).Log("msg", "error loading templates", "path", config.Template, "err", err) } http.HandleFunc("/alert", func(w http.ResponseWriter, req *http.Request) { - log.V(1).Infof("Handling /alert webhook request") + level.Debug(logger).Log("msg", "handling /alert webhook request") defer req.Body.Close() // https://godoc.org/github.com/prometheus/alertmanager/template#Data data := alertmanager.Data{} if err := json.NewDecoder(req.Body).Decode(&data); err != nil { - errorHandler(w, http.StatusBadRequest, err, unknownReceiver, &data) + errorHandler(w, http.StatusBadRequest, err, unknownReceiver, &data, logger) return } conf := config.ReceiverByName(data.Receiver) if conf == nil { - errorHandler(w, http.StatusNotFound, fmt.Errorf("receiver missing: %s", data.Receiver), unknownReceiver, &data) + errorHandler(w, http.StatusNotFound, fmt.Errorf("receiver missing: %s", data.Receiver), unknownReceiver, &data, logger) return } - log.V(1).Infof("Matched receiver: %q", conf.Name) + level.Debug(logger).Log("msg", "matched receiver", "receiver", conf.Name) // Filter out resolved alerts, not interested in them. alerts := data.Alerts.Firing() if len(alerts) < len(data.Alerts) { - log.Warningf("Please set \"send_resolved: false\" on receiver %s in the Alertmanager config", conf.Name) + level.Warn(logger).Log("msg", "receiver should have \"send_resolved: false\" set in Alertmanager config", "receiver", conf.Name) data.Alerts = alerts } if len(data.Alerts) > 0 { r, err := notify.NewReceiver(conf, tmpl) if err != nil { - errorHandler(w, http.StatusInternalServerError, err, conf.Name, &data) + errorHandler(w, http.StatusInternalServerError, err, conf.Name, &data, logger) return } if retry, err := r.Notify(&data); err != nil { @@ -101,7 +119,7 @@ func main() { } else { status = http.StatusInternalServerError } - errorHandler(w, status, err, conf.Name, &data) + errorHandler(w, status, err, conf.Name, &data, logger) return } } @@ -118,11 +136,16 @@ func main() { *listenAddress = ":" + os.Getenv("PORT") } - log.Infof("Listening on %s", *listenAddress) - log.Fatal(http.ListenAndServe(*listenAddress, nil)) + level.Info(logger).Log("msg", "listening", "address", *listenAddress) + err = http.ListenAndServe(*listenAddress, nil) + if err != nil { + level.Error(logger).Log("msg", "failed to start HTTP server", "address", *listenAddress) + os.Exit(1) + } + } -func errorHandler(w http.ResponseWriter, status int, err error, receiver string, data *alertmanager.Data) { +func errorHandler(w http.ResponseWriter, status int, err error, receiver string, data *alertmanager.Data, logger log.Logger) { w.WriteHeader(status) response := struct { @@ -139,6 +162,6 @@ func errorHandler(w http.ResponseWriter, status int, err error, receiver string, json := string(bytes[:]) fmt.Fprint(w, json) - log.Errorf("%d %s: err=%s receiver=%q groupLabels=%+v", status, http.StatusText(status), err, receiver, data.GroupLabels) + level.Error(logger).Log("msg", "error handling request", "statusCode", status, "statusTest", http.StatusText(status), "err", err, "receiver", receiver, "groupLabels", data.GroupLabels) requestTotal.WithLabelValues(receiver, strconv.FormatInt(int64(status), 10)).Inc() } diff --git a/go.mod b/go.mod index fb8cbb3..9fe0a0f 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,9 @@ require ( github.com/andygrunwald/go-jira v0.0.0-20181018203616-bbce4afa5493 github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a // indirect github.com/fatih/structs v0.0.0-20171020064819-f5faa72e7309 // indirect + github.com/go-kit/kit v0.8.0 + github.com/go-logfmt/logfmt v0.4.0 // indirect + github.com/go-stack/stack v1.8.0 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54 // indirect github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect @@ -16,7 +19,6 @@ require ( github.com/prometheus/procfs v0.0.0-20171017214025-a6e9df898b13 // indirect github.com/trivago/tgo v1.0.1 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect - golang.org/x/tools v0.0.0-20190315214010-f0bfdbff1f9c // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7 ) diff --git a/go.sum b/go.sum index c9ed488..0aa89dc 100644 --- a/go.sum +++ b/go.sum @@ -4,12 +4,20 @@ github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a h1:BtpsbiV638WQZwhA98 github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/fatih/structs v0.0.0-20171020064819-f5faa72e7309 h1:yetGKN1jYaaVt+q69KPz+V2Z64OyTw/KfTNQS90n/tU= github.com/fatih/structs v0.0.0-20171020064819-f5faa72e7309/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54 h1:nRNJXiJvemchkOTn0V4U11TZkvacB94gTzbTZbSA7Rw= github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -29,14 +37,8 @@ github.com/prometheus/procfs v0.0.0-20171017214025-a6e9df898b13 h1:leRfx9kcgnSDk github.com/prometheus/procfs v0.0.0-20171017214025-a6e9df898b13/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/trivago/tgo v1.0.1 h1:bxatjJIXNIpV18bucU4Uk/LaoxvxuOlp/oowRHyncLQ= github.com/trivago/tgo v1.0.1/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190315214010-f0bfdbff1f9c h1:KQ2sRfnx/Xk0E4v13yE9v3gCXAn6qieU1aiQOsbmpQg= -golang.org/x/tools v0.0.0-20190315214010-f0bfdbff1f9c/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7 h1:+t9dhfO+GNOIGJof6kPOAenx7YgrZMTdRPV+EsnPabk= From c37e23c09d4a1e2d042b182f2693a2ac29de27d1 Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Mon, 8 Apr 2019 09:07:35 +0300 Subject: [PATCH 03/17] Further updates to log messages --- cmd/jiralert/main.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index 8d90ece..e07ad28 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -53,12 +53,11 @@ func main() { lvl = level.AllowError() case "warn": lvl = level.AllowWarn() - case "info": - lvl = level.AllowInfo() case "debug": lvl = level.AllowDebug() + case "info": default: - panic("unexpected log level") + lvl = level.AllowInfo() } logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) if *logFormat == logFormatJson { @@ -74,11 +73,13 @@ func main() { config, _, err := config.LoadFile(*configFile) if err != nil { level.Error(logger).Log("msg", "error loading configuration", "path", *configFile, "err", err) + os.Exit(1) } tmpl, err := template.LoadTemplate(config.Template) if err != nil { level.Error(logger).Log("msg", "error loading templates", "path", config.Template, "err", err) + os.Exit(1) } http.HandleFunc("/alert", func(w http.ResponseWriter, req *http.Request) { @@ -162,6 +163,6 @@ func errorHandler(w http.ResponseWriter, status int, err error, receiver string, json := string(bytes[:]) fmt.Fprint(w, json) - level.Error(logger).Log("msg", "error handling request", "statusCode", status, "statusTest", http.StatusText(status), "err", err, "receiver", receiver, "groupLabels", data.GroupLabels) + level.Error(logger).Log("msg", "error handling request", "statusCode", status, "statusText", http.StatusText(status), "err", err, "receiver", receiver, "groupLabels", data.GroupLabels) requestTotal.WithLabelValues(receiver, strconv.FormatInt(int64(status), 10)).Inc() } From 2087a98336022097f9dff53df28e7e1cfd3e8280 Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Mon, 8 Apr 2019 09:15:18 +0300 Subject: [PATCH 04/17] Config package logging updated --- cmd/jiralert/main.go | 2 +- pkg/config/config.go | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index e07ad28..798d51f 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -70,7 +70,7 @@ func main() { level.Info(logger).Log("msg", "starting JIRAlert", "version", Version) - config, _, err := config.LoadFile(*configFile) + config, _, err := config.LoadFile(*configFile, logger) if err != nil { level.Error(logger).Log("msg", "error loading configuration", "path", *configFile, "err", err) os.Exit(1) diff --git a/pkg/config/config.go b/pkg/config/config.go index 620ee40..7b7e2a7 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -2,6 +2,8 @@ package config import ( "fmt" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "io/ioutil" "net/url" "path/filepath" @@ -10,7 +12,6 @@ import ( "strings" "time" - log "github.com/golang/glog" "github.com/trivago/tgo/tcontainer" "gopkg.in/yaml.v2" ) @@ -39,13 +40,12 @@ func Load(s string) (*Config, error) { if err != nil { return nil, err } - log.V(1).Infof("Loaded config:\n%+v", cfg) return cfg, nil } // LoadFile parses the given YAML file into a Config. -func LoadFile(filename string) (*Config, []byte, error) { - log.V(1).Infof("Loading configuration from %q", filename) +func LoadFile(filename string, logger log.Logger) (*Config, []byte, error) { + level.Info(logger).Log("msg", "loading configuration", "path", filename) content, err := ioutil.ReadFile(filename) if err != nil { return nil, nil, err @@ -55,19 +55,19 @@ func LoadFile(filename string) (*Config, []byte, error) { return nil, nil, err } - resolveFilepaths(filepath.Dir(filename), cfg) + resolveFilepaths(filepath.Dir(filename), cfg, logger) return cfg, content, nil } // resolveFilepaths joins all relative paths in a configuration // with a given base directory. -func resolveFilepaths(baseDir string, cfg *Config) { +func resolveFilepaths(baseDir string, cfg *Config, logger log.Logger) { join := func(fp string) string { if len(fp) == 0 || filepath.IsAbs(fp) { return fp } absFp := filepath.Join(baseDir, fp) - log.V(2).Infof("Relative path %q resolved to %q", fp, absFp) + level.Debug(logger).Log("msg", "relative configuration path resolved", "relativePath", fp, "absolutePath", absFp) return absFp } From 22f148bc3b25113307ebe6eb6de868ab2f8f7d25 Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Mon, 8 Apr 2019 09:37:52 +0300 Subject: [PATCH 05/17] Update template and notify logs --- cmd/jiralert/main.go | 4 +- go.mod | 1 - go.sum | 2 - pkg/notify/notify.go | 82 ++++++++++++++++++++-------------------- pkg/template/template.go | 18 ++++----- 5 files changed, 53 insertions(+), 54 deletions(-) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index 798d51f..3a578ba 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -76,7 +76,7 @@ func main() { os.Exit(1) } - tmpl, err := template.LoadTemplate(config.Template) + tmpl, err := template.LoadTemplate(config.Template, logger) if err != nil { level.Error(logger).Log("msg", "error loading templates", "path", config.Template, "err", err) os.Exit(1) @@ -113,7 +113,7 @@ func main() { errorHandler(w, http.StatusInternalServerError, err, conf.Name, &data, logger) return } - if retry, err := r.Notify(&data); err != nil { + if retry, err := r.Notify(&data, logger); err != nil { var status int if retry { status = http.StatusServiceUnavailable diff --git a/go.mod b/go.mod index 9fe0a0f..4095c9c 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/go-kit/kit v0.8.0 github.com/go-logfmt/logfmt v0.4.0 // indirect github.com/go-stack/stack v1.8.0 // indirect - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54 // indirect github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect github.com/kr/pretty v0.1.0 // indirect diff --git a/go.sum b/go.sum index 0aa89dc..4c5c212 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,6 @@ github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80n github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54 h1:nRNJXiJvemchkOTn0V4U11TZkvacB94gTzbTZbSA7Rw= github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= diff --git a/pkg/notify/notify.go b/pkg/notify/notify.go index 1ed4adb..153ad84 100644 --- a/pkg/notify/notify.go +++ b/pkg/notify/notify.go @@ -3,6 +3,8 @@ package notify import ( "bytes" "fmt" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "io/ioutil" "reflect" "strings" @@ -13,7 +15,6 @@ import ( "github.com/andygrunwald/go-jira" "github.com/free/jiralert/pkg/alertmanager" - log "github.com/golang/glog" "github.com/trivago/tgo/tcontainer" ) @@ -39,15 +40,15 @@ func NewReceiver(c *config.ReceiverConfig, t *template.Template) (*Receiver, err } // Notify implements the Notifier interface. -func (r *Receiver) Notify(data *alertmanager.Data) (bool, error) { - project := r.tmpl.Execute(r.conf.Project, data) +func (r *Receiver) Notify(data *alertmanager.Data, logger log.Logger) (bool, error) { + project := r.tmpl.Execute(r.conf.Project, data, logger) if err := r.tmpl.Err(); err != nil { return false, err } // Looks like an ALERT metric name, with spaces removed. issueLabel := toIssueLabel(data.GroupLabels) - issue, retry, err := r.search(project, issueLabel) + issue, retry, err := r.search(project, issueLabel, logger) if err != nil { return retry, err } @@ -56,30 +57,30 @@ func (r *Receiver) Notify(data *alertmanager.Data) (bool, error) { // The set of JIRA status categories is fixed, this is a safe check to make. if issue.Fields.Status.StatusCategory.Key != "done" { // Issue is in a "to do" or "in progress" state, all done here. - log.V(1).Infof("Issue %s for %s is unresolved, nothing to do", issue.Key, issueLabel) + level.Info(logger).Log("msg", "nothing to do as issue is unresolved", "issue", issue.Key, "label", issueLabel) return false, nil } if r.conf.WontFixResolution != "" && issue.Fields.Resolution != nil && issue.Fields.Resolution.Name == r.conf.WontFixResolution { // Issue is resolved as "Won't Fix" or equivalent, log a message just in case. - log.Infof("Issue %s for %s is resolved as %q, not reopening", issue.Key, issueLabel, issue.Fields.Resolution.Name) + level.Info(logger).Log("msg", "issue is resolved, not reopening", "issue", issue.Key, "label", issueLabel, "resolution", issue.Fields.Resolution.Name) return false, nil } resolutionTime := time.Time(issue.Fields.Resolutiondate) if resolutionTime.Add(time.Duration(*r.conf.ReopenDuration)).After(time.Now()) { - log.Infof("Issue %s for %s was resolved on %s, reopening", issue.Key, issueLabel, resolutionTime.Format(time.RFC3339)) - return r.reopen(issue.Key) + level.Info(logger).Log("msg", "issue was resolved after reopen duration, reopening", "issue", issue.Key, "label", issueLabel, "reopenDuration", *r.conf.ReopenDuration, "resolutionTime", resolutionTime) + return r.reopen(issue.Key, logger) } } - log.Infof("No issue matching %s found, creating new issue", issueLabel) + level.Info(logger).Log("msg", "no issue, matching the label, found, opening a new one", "label", issueLabel) issue = &jira.Issue{ Fields: &jira.IssueFields{ Project: jira.Project{Key: project}, - Type: jira.IssueType{Name: r.tmpl.Execute(r.conf.IssueType, data)}, - Description: r.tmpl.Execute(r.conf.Description, data), - Summary: r.tmpl.Execute(r.conf.Summary, data), + Type: jira.IssueType{Name: r.tmpl.Execute(r.conf.IssueType, data, logger)}, + Description: r.tmpl.Execute(r.conf.Description, data, logger), + Summary: r.tmpl.Execute(r.conf.Summary, data, logger), Labels: []string{ issueLabel, }, @@ -87,14 +88,14 @@ func (r *Receiver) Notify(data *alertmanager.Data) (bool, error) { }, } if r.conf.Priority != "" { - issue.Fields.Priority = &jira.Priority{Name: r.tmpl.Execute(r.conf.Priority, data)} + issue.Fields.Priority = &jira.Priority{Name: r.tmpl.Execute(r.conf.Priority, data, logger)} } // Add Components if len(r.conf.Components) > 0 { issue.Fields.Components = make([]*jira.Component, 0, len(r.conf.Components)) for _, component := range r.conf.Components { - issue.Fields.Components = append(issue.Fields.Components, &jira.Component{Name: r.tmpl.Execute(component, data)}) + issue.Fields.Components = append(issue.Fields.Components, &jira.Component{Name: r.tmpl.Execute(component, data, logger)}) } } @@ -106,15 +107,15 @@ func (r *Receiver) Notify(data *alertmanager.Data) (bool, error) { } for key, value := range r.conf.Fields { - issue.Fields.Unknowns[key] = deepCopyWithTemplate(value, r.tmpl, data) + issue.Fields.Unknowns[key] = deepCopyWithTemplate(value, r.tmpl, data, logger) } if err := r.tmpl.Err(); err != nil { return false, err } - retry, err = r.create(issue) + retry, err = r.create(issue, logger) if err == nil { - log.Infof("Issue created: key=%s ID=%s", issue.Key, issue.ID) + level.Info(logger).Log("msg", "issue successfully created", "issue", issue.Key, "issueID", issue.ID) } return retry, err } @@ -122,7 +123,7 @@ func (r *Receiver) Notify(data *alertmanager.Data) (bool, error) { // deepCopyWithTemplate returns a deep copy of a map/slice/array/string/int/bool or combination thereof, executing the // provided template (with the provided data) on all string keys or values. All maps are connverted to // map[string]interface{}, with all non-string keys discarded. -func deepCopyWithTemplate(value interface{}, tmpl *template.Template, data interface{}) interface{} { +func deepCopyWithTemplate(value interface{}, tmpl *template.Template, data interface{}, logger log.Logger) interface{} { if value == nil { return value } @@ -131,13 +132,13 @@ func deepCopyWithTemplate(value interface{}, tmpl *template.Template, data inter switch valueMeta.Kind() { case reflect.String: - return tmpl.Execute(value.(string), data) + return tmpl.Execute(value.(string), data, logger) case reflect.Array, reflect.Slice: arrayLen := valueMeta.Len() converted := make([]interface{}, arrayLen) for i := 0; i < arrayLen; i++ { - converted[i] = deepCopyWithTemplate(valueMeta.Index(i).Interface(), tmpl, data) + converted[i] = deepCopyWithTemplate(valueMeta.Index(i).Interface(), tmpl, data, logger) } return converted @@ -150,8 +151,8 @@ func deepCopyWithTemplate(value interface{}, tmpl *template.Template, data inter if !isString { continue } - strKey = tmpl.Execute(strKey, data) - converted[strKey] = deepCopyWithTemplate(valueMeta.MapIndex(keyMeta).Interface(), tmpl, data) + strKey = tmpl.Execute(strKey, data, logger) + converted[strKey] = deepCopyWithTemplate(valueMeta.MapIndex(keyMeta).Interface(), tmpl, data, logger) } return converted @@ -172,67 +173,68 @@ func toIssueLabel(groupLabels alertmanager.KV) string { return strings.Replace(buf.String(), " ", "", -1) } -func (r *Receiver) search(project, issueLabel string) (*jira.Issue, bool, error) { +func (r *Receiver) search(project, issueLabel string, logger log.Logger) (*jira.Issue, bool, error) { query := fmt.Sprintf("project=\"%s\" and labels=%q order by resolutiondate desc", project, issueLabel) options := &jira.SearchOptions{ Fields: []string{"summary", "status", "resolution", "resolutiondate"}, MaxResults: 2, } - log.V(1).Infof("search: query=%v options=%+v", query, options) + level.Debug(logger).Log("msg", "searching for existing issue", "query", query, "options", options) issues, resp, err := r.client.Issue.Search(query, options) if err != nil { - retry, err := handleJiraError("Issue.Search", resp, err) + retry, err := handleJiraError("Issue.Search", resp, err, logger) return nil, retry, err } if len(issues) > 0 { if len(issues) > 1 { // Swallow it, but log a message. - log.Infof("More than one issue matched %s, will only update last issue: %+v", query, issues) + level.Warn(logger).Log("msg", "more than one issue matched, updating only the last one", "query", query, "issues", issues) } - log.V(1).Infof(" found: %+v", issues[0]) + level.Debug(logger).Log("msg", "found existing issue matching the query", "issue", issues[0], "query", query) return &issues[0], false, nil } - log.V(1).Infof(" no results") + level.Debug(logger).Log("msg", "no existing issues matching query found", "query", query) return nil, false, nil } -func (r *Receiver) reopen(issueKey string) (bool, error) { +func (r *Receiver) reopen(issueKey string, logger log.Logger) (bool, error) { transitions, resp, err := r.client.Issue.GetTransitions(issueKey) if err != nil { - return handleJiraError("Issue.GetTransitions", resp, err) + return handleJiraError("Issue.GetTransitions", resp, err, logger) } for _, t := range transitions { if t.Name == r.conf.ReopenState { - log.V(1).Infof("reopen: issueKey=%v transitionID=%v", issueKey, t.ID) + level.Debug(logger).Log("msg", "reopening issue", "issue", issueKey, "transitionID", t.ID) resp, err = r.client.Issue.DoTransition(issueKey, t.ID) if err != nil { - return handleJiraError("Issue.DoTransition", resp, err) + return handleJiraError("Issue.DoTransition", resp, err, logger) } - log.V(1).Infof(" done") + + level.Debug(logger).Log("msg", "issue successfully reopened") return false, nil } } return false, fmt.Errorf("JIRA state %q does not exist or no transition possible for %s", r.conf.ReopenState, issueKey) } -func (r *Receiver) create(issue *jira.Issue) (bool, error) { - log.V(1).Infof("create: issue=%v", *issue) +func (r *Receiver) create(issue *jira.Issue, logger log.Logger) (bool, error) { + level.Debug(logger).Log("msg", "creating new issue", "issue", *issue) newIssue, resp, err := r.client.Issue.Create(issue) if err != nil { - return handleJiraError("Issue.Create", resp, err) + return handleJiraError("Issue.Create", resp, err, logger) } *issue = *newIssue - log.V(1).Infof(" done: key=%s ID=%s", issue.Key, issue.ID) + level.Debug(logger).Log("msg", "issue successfully created", "issue", issue.Key, "issueID", issue.ID) return false, nil } -func handleJiraError(api string, resp *jira.Response, err error) (bool, error) { +func handleJiraError(api string, resp *jira.Response, err error, logger log.Logger) (bool, error) { if resp == nil || resp.Request == nil { - log.V(1).Infof("handleJiraError: api=%s, err=%s", api, err) + level.Debug(logger).Log("msg", "handleJiraError", "api", api, "err", err) } else { - log.V(1).Infof("handleJiraError: api=%s, url=%s, err=%s", api, resp.Request.URL, err) + level.Debug(logger).Log("msg", "handleJiraError", "api", api, "err", err, "url", resp.Request.URL) } if resp != nil && resp.StatusCode/100 != 2 { diff --git a/pkg/template/template.go b/pkg/template/template.go index e0141a7..f02d6a4 100644 --- a/pkg/template/template.go +++ b/pkg/template/template.go @@ -2,11 +2,11 @@ package template import ( "bytes" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "regexp" "strings" "text/template" - - log "github.com/golang/glog" ) // Template wraps a text template and error, to make it easier to execute multiple templates and only check for errors @@ -32,8 +32,8 @@ var funcs = template.FuncMap{ } // LoadTemplate reads and parses all templates defined in the given file and constructs a jiralert.Template. -func LoadTemplate(path string) (*Template, error) { - log.V(1).Infof("Loading templates from %q", path) +func LoadTemplate(path string, logger log.Logger) (*Template, error) { + level.Debug(logger).Log("msg", "loading templates", "path", path) tmpl, err := template.New("").Option("missingkey=zero").Funcs(funcs).ParseFiles(path) if err != nil { return nil, err @@ -48,10 +48,10 @@ func (t *Template) Err() error { // Execute parses the provided text (or returns it unchanged if not a Go template), associates it with the templates // defined in t.tmpl (so they may be referenced and used) and applies the resulting template to the specified data // object, returning the output as a string. -func (t *Template) Execute(text string, data interface{}) string { - log.V(2).Infof("Executing template %q...", text) +func (t *Template) Execute(text string, data interface{}, logger log.Logger) string { + level.Debug(logger).Log("msg", "executing template", "template", text) if !strings.Contains(text, "{{") { - log.V(2).Infof(" returning unchanged.") + level.Debug(logger).Log("msg", "returning unchanged template") return text } @@ -65,12 +65,12 @@ func (t *Template) Execute(text string, data interface{}) string { } tmpl, t.err = tmpl.New("").Parse(text) if t.err != nil { - log.V(2).Infof(" parse failed.") + level.Warn(logger).Log("msg", "failed to parse template") return "" } var buf bytes.Buffer t.err = tmpl.Execute(&buf, data) ret := buf.String() - log.V(2).Infof(" returning %q.", ret) + level.Debug(logger).Log("msg", "returning parsed template", "template", ret) return ret } From d16cd57db208237206287c6c56109c0fcdcb7783 Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Thu, 11 Apr 2019 16:10:19 +0300 Subject: [PATCH 06/17] Show possible values for log params --- cmd/jiralert/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index 3a578ba..e97237b 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -30,8 +30,8 @@ const ( var ( listenAddress = flag.String("listen-address", ":9097", "The address to listen on for HTTP requests.") configFile = flag.String("config", "config/jiralert.yml", "The JIRAlert configuration file") - logLevel = flag.String("log.level", "info", "Log filtering level") - logFormat = flag.String("log.format", logFormatLogfmt, "Log format to use") + logLevel = flag.String("log.level", "info", "Log filtering level (debug, info, warn, error)") + logFormat = flag.String("log.format", logFormatLogfmt, "Log format to use (" + logFormatLogfmt + ", " + logFormatJson + ")") // Version is the build version, set by make to latest git tag/hash via `-ldflags "-X main.Version=$(VERSION)"`. Version = "" From 5daeafc831bf3c1de6b705d529a2cc808ad0e7dd Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Thu, 11 Apr 2019 16:12:37 +0300 Subject: [PATCH 07/17] Ensure a single logger is created --- cmd/jiralert/main.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index e97237b..28b49c2 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -59,9 +59,11 @@ func main() { default: lvl = level.AllowInfo() } - logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) + if *logFormat == logFormatJson { logger = log.NewJSONLogger(log.NewSyncWriter(os.Stderr)) + } else { + logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) } logger = level.NewFilter(logger, lvl) From 9bedb5fad3de0c2b12688217b307557db5c79034 Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Thu, 11 Apr 2019 16:19:02 +0300 Subject: [PATCH 08/17] Remove blank line --- cmd/jiralert/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index 28b49c2..6a35f2a 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -145,7 +145,6 @@ func main() { level.Error(logger).Log("msg", "failed to start HTTP server", "address", *listenAddress) os.Exit(1) } - } func errorHandler(w http.ResponseWriter, status int, err error, receiver string, data *alertmanager.Data, logger log.Logger) { From 499d4b3c170beff95727c37aa23d985bb9e8e4ef Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Thu, 11 Apr 2019 16:20:28 +0300 Subject: [PATCH 09/17] Update log level --- pkg/notify/notify.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/notify/notify.go b/pkg/notify/notify.go index 153ad84..d679409 100644 --- a/pkg/notify/notify.go +++ b/pkg/notify/notify.go @@ -57,7 +57,7 @@ func (r *Receiver) Notify(data *alertmanager.Data, logger log.Logger) (bool, err // The set of JIRA status categories is fixed, this is a safe check to make. if issue.Fields.Status.StatusCategory.Key != "done" { // Issue is in a "to do" or "in progress" state, all done here. - level.Info(logger).Log("msg", "nothing to do as issue is unresolved", "issue", issue.Key, "label", issueLabel) + level.Debug(logger).Log("msg", "nothing to do as issue is unresolved", "issue", issue.Key, "label", issueLabel) return false, nil } if r.conf.WontFixResolution != "" && issue.Fields.Resolution != nil && From 1db64e1989c4d4651a063e1c73236114bd854b6a Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Thu, 11 Apr 2019 16:41:54 +0300 Subject: [PATCH 10/17] Update log messages --- pkg/notify/notify.go | 24 ++++++++++++------------ pkg/template/template.go | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/notify/notify.go b/pkg/notify/notify.go index d679409..e5273eb 100644 --- a/pkg/notify/notify.go +++ b/pkg/notify/notify.go @@ -57,24 +57,24 @@ func (r *Receiver) Notify(data *alertmanager.Data, logger log.Logger) (bool, err // The set of JIRA status categories is fixed, this is a safe check to make. if issue.Fields.Status.StatusCategory.Key != "done" { // Issue is in a "to do" or "in progress" state, all done here. - level.Debug(logger).Log("msg", "nothing to do as issue is unresolved", "issue", issue.Key, "label", issueLabel) + level.Debug(logger).Log("msg", "doing nothing, as issue is unresolved", "key", issue.Key, "label", issueLabel) return false, nil } if r.conf.WontFixResolution != "" && issue.Fields.Resolution != nil && issue.Fields.Resolution.Name == r.conf.WontFixResolution { // Issue is resolved as "Won't Fix" or equivalent, log a message just in case. - level.Info(logger).Log("msg", "issue is resolved, not reopening", "issue", issue.Key, "label", issueLabel, "resolution", issue.Fields.Resolution.Name) + level.Info(logger).Log("msg", "not reopening issue, as it was resolved", "key", issue.Key, "label", issueLabel, "resolution", issue.Fields.Resolution.Name) return false, nil } resolutionTime := time.Time(issue.Fields.Resolutiondate) if resolutionTime.Add(time.Duration(*r.conf.ReopenDuration)).After(time.Now()) { - level.Info(logger).Log("msg", "issue was resolved after reopen duration, reopening", "issue", issue.Key, "label", issueLabel, "reopenDuration", *r.conf.ReopenDuration, "resolutionTime", resolutionTime) + level.Info(logger).Log("msg", "reopening issue, as it was resolved after reopen duration, ", "key", issue.Key, "label", issueLabel, "reopenDuration", *r.conf.ReopenDuration, "resolutionTime", resolutionTime.Format(time.RFC3339)) return r.reopen(issue.Key, logger) } } - level.Info(logger).Log("msg", "no issue, matching the label, found, opening a new one", "label", issueLabel) + level.Info(logger).Log("msg", "opening a new issue, as no issue matching the label was found, ", "label", issueLabel) issue = &jira.Issue{ Fields: &jira.IssueFields{ Project: jira.Project{Key: project}, @@ -115,7 +115,7 @@ func (r *Receiver) Notify(data *alertmanager.Data, logger log.Logger) (bool, err } retry, err = r.create(issue, logger) if err == nil { - level.Info(logger).Log("msg", "issue successfully created", "issue", issue.Key, "issueID", issue.ID) + level.Info(logger).Log("msg", "issue created", "key", issue.Key, "id", issue.ID) } return retry, err } @@ -179,7 +179,7 @@ func (r *Receiver) search(project, issueLabel string, logger log.Logger) (*jira. Fields: []string{"summary", "status", "resolution", "resolutiondate"}, MaxResults: 2, } - level.Debug(logger).Log("msg", "searching for existing issue", "query", query, "options", options) + level.Debug(logger).Log("msg", "search", "query", query, "options", options) issues, resp, err := r.client.Issue.Search(query, options) if err != nil { retry, err := handleJiraError("Issue.Search", resp, err, logger) @@ -191,10 +191,10 @@ func (r *Receiver) search(project, issueLabel string, logger log.Logger) (*jira. level.Warn(logger).Log("msg", "more than one issue matched, updating only the last one", "query", query, "issues", issues) } - level.Debug(logger).Log("msg", "found existing issue matching the query", "issue", issues[0], "query", query) + level.Debug(logger).Log("msg", " found", "issue", issues[0], "query", query) return &issues[0], false, nil } - level.Debug(logger).Log("msg", "no existing issues matching query found", "query", query) + level.Debug(logger).Log("msg", " no results", "query", query) return nil, false, nil } @@ -205,13 +205,13 @@ func (r *Receiver) reopen(issueKey string, logger log.Logger) (bool, error) { } for _, t := range transitions { if t.Name == r.conf.ReopenState { - level.Debug(logger).Log("msg", "reopening issue", "issue", issueKey, "transitionID", t.ID) + level.Debug(logger).Log("msg", "reopen", "key", issueKey, "transitionID", t.ID) resp, err = r.client.Issue.DoTransition(issueKey, t.ID) if err != nil { return handleJiraError("Issue.DoTransition", resp, err, logger) } - level.Debug(logger).Log("msg", "issue successfully reopened") + level.Debug(logger).Log("msg", " done") return false, nil } } @@ -219,14 +219,14 @@ func (r *Receiver) reopen(issueKey string, logger log.Logger) (bool, error) { } func (r *Receiver) create(issue *jira.Issue, logger log.Logger) (bool, error) { - level.Debug(logger).Log("msg", "creating new issue", "issue", *issue) + level.Debug(logger).Log("msg", "create", "issue", *issue) newIssue, resp, err := r.client.Issue.Create(issue) if err != nil { return handleJiraError("Issue.Create", resp, err, logger) } *issue = *newIssue - level.Debug(logger).Log("msg", "issue successfully created", "issue", issue.Key, "issueID", issue.ID) + level.Debug(logger).Log("msg", " done", "key", issue.Key, "id", issue.ID) return false, nil } diff --git a/pkg/template/template.go b/pkg/template/template.go index f02d6a4..5cc11c3 100644 --- a/pkg/template/template.go +++ b/pkg/template/template.go @@ -51,7 +51,7 @@ func (t *Template) Err() error { func (t *Template) Execute(text string, data interface{}, logger log.Logger) string { level.Debug(logger).Log("msg", "executing template", "template", text) if !strings.Contains(text, "{{") { - level.Debug(logger).Log("msg", "returning unchanged template") + level.Debug(logger).Log("msg", " returning unchanged") return text } From 4bd2f4913edd501bd789582345124ad6767f2677 Mon Sep 17 00:00:00 2001 From: Tomas Dabasinskas Date: Thu, 11 Apr 2019 16:52:54 +0300 Subject: [PATCH 11/17] Move logger setup to a separate func --- cmd/jiralert/main.go | 50 ++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index 6a35f2a..380b9bb 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -45,31 +45,7 @@ func main() { flag.Parse() - var logger log.Logger - { - var lvl level.Option - switch *logLevel { - case "error": - lvl = level.AllowError() - case "warn": - lvl = level.AllowWarn() - case "debug": - lvl = level.AllowDebug() - case "info": - default: - lvl = level.AllowInfo() - } - - if *logFormat == logFormatJson { - logger = log.NewJSONLogger(log.NewSyncWriter(os.Stderr)) - } else { - logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) - } - logger = level.NewFilter(logger, lvl) - - logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) - } - + var logger = setupLogger(*logLevel, *logFormat) level.Info(logger).Log("msg", "starting JIRAlert", "version", Version) config, _, err := config.LoadFile(*configFile, logger) @@ -167,3 +143,27 @@ func errorHandler(w http.ResponseWriter, status int, err error, receiver string, level.Error(logger).Log("msg", "error handling request", "statusCode", status, "statusText", http.StatusText(status), "err", err, "receiver", receiver, "groupLabels", data.GroupLabels) requestTotal.WithLabelValues(receiver, strconv.FormatInt(int64(status), 10)).Inc() } + +func setupLogger(lvl string, fmt string) (logger log.Logger) { + var filter level.Option + switch lvl { + case "error": + filter = level.AllowError() + case "warn": + filter = level.AllowWarn() + case "debug": + filter = level.AllowDebug() + case "info": + default: + filter = level.AllowInfo() + } + + if fmt == logFormatJson { + logger = log.NewJSONLogger(log.NewSyncWriter(os.Stderr)) + } else { + logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) + } + logger = level.NewFilter(logger, filter) + logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) + return +} \ No newline at end of file From 9a7a9d62bc5c69e7984f08609236b15ee8513659 Mon Sep 17 00:00:00 2001 From: Alin Sinpalean Date: Wed, 8 May 2019 08:46:48 +0300 Subject: [PATCH 12/17] Update pkg/notify/notify.go Co-Authored-By: tdabasinskas --- pkg/notify/notify.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/notify/notify.go b/pkg/notify/notify.go index e5273eb..609500d 100644 --- a/pkg/notify/notify.go +++ b/pkg/notify/notify.go @@ -74,7 +74,7 @@ func (r *Receiver) Notify(data *alertmanager.Data, logger log.Logger) (bool, err } } - level.Info(logger).Log("msg", "opening a new issue, as no issue matching the label was found, ", "label", issueLabel) + level.Info(logger).Log("msg", "no recent matching issue found, creating new issue", "label", issueLabel) issue = &jira.Issue{ Fields: &jira.IssueFields{ Project: jira.Project{Key: project}, From 6891096fa529590156b2e0db019d7b4c0ecb1ad5 Mon Sep 17 00:00:00 2001 From: Alin Sinpalean Date: Wed, 8 May 2019 08:47:01 +0300 Subject: [PATCH 13/17] Update pkg/notify/notify.go Co-Authored-By: tdabasinskas --- pkg/notify/notify.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/notify/notify.go b/pkg/notify/notify.go index 609500d..16c3da5 100644 --- a/pkg/notify/notify.go +++ b/pkg/notify/notify.go @@ -188,7 +188,7 @@ func (r *Receiver) search(project, issueLabel string, logger log.Logger) (*jira. if len(issues) > 0 { if len(issues) > 1 { // Swallow it, but log a message. - level.Warn(logger).Log("msg", "more than one issue matched, updating only the last one", "query", query, "issues", issues) + level.Debug(logger).Log("msg", "more than one issue matched, picking most recently resolved", "query", query, "issues", issues) } level.Debug(logger).Log("msg", " found", "issue", issues[0], "query", query) From 74af0746492e02f79077b842ddd0b221ae6a69f1 Mon Sep 17 00:00:00 2001 From: Alin Sinpalean Date: Wed, 8 May 2019 12:33:29 +0300 Subject: [PATCH 14/17] Update cmd/jiralert/main.go Co-Authored-By: tdabasinskas --- cmd/jiralert/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/jiralert/main.go b/cmd/jiralert/main.go index 380b9bb..b6881a1 100644 --- a/cmd/jiralert/main.go +++ b/cmd/jiralert/main.go @@ -76,7 +76,7 @@ func main() { errorHandler(w, http.StatusNotFound, fmt.Errorf("receiver missing: %s", data.Receiver), unknownReceiver, &data, logger) return } - level.Debug(logger).Log("msg", "matched receiver", "receiver", conf.Name) + level.Debug(logger).Log("msg", " matched receiver", "receiver", conf.Name) // Filter out resolved alerts, not interested in them. alerts := data.Alerts.Firing() @@ -166,4 +166,4 @@ func setupLogger(lvl string, fmt string) (logger log.Logger) { logger = level.NewFilter(logger, filter) logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) return -} \ No newline at end of file +} From f172cf50fe027c2c9931bbdfc1540158a3fabcf1 Mon Sep 17 00:00:00 2001 From: Alin Sinpalean Date: Wed, 8 May 2019 12:34:08 +0300 Subject: [PATCH 15/17] Update pkg/config/config.go Co-Authored-By: tdabasinskas --- pkg/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 7b7e2a7..8498864 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -67,7 +67,7 @@ func resolveFilepaths(baseDir string, cfg *Config, logger log.Logger) { return fp } absFp := filepath.Join(baseDir, fp) - level.Debug(logger).Log("msg", "relative configuration path resolved", "relativePath", fp, "absolutePath", absFp) + level.Debug(logger).Log("msg", "resolved relative configuration path", "relativePath", fp, "absolutePath", absFp) return absFp } From 47c792714bc8f1aeac0ad28a2e81c150cb056b24 Mon Sep 17 00:00:00 2001 From: Alin Sinpalean Date: Wed, 8 May 2019 12:34:36 +0300 Subject: [PATCH 16/17] Update pkg/notify/notify.go Co-Authored-By: tdabasinskas --- pkg/notify/notify.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/notify/notify.go b/pkg/notify/notify.go index 16c3da5..5934def 100644 --- a/pkg/notify/notify.go +++ b/pkg/notify/notify.go @@ -57,7 +57,7 @@ func (r *Receiver) Notify(data *alertmanager.Data, logger log.Logger) (bool, err // The set of JIRA status categories is fixed, this is a safe check to make. if issue.Fields.Status.StatusCategory.Key != "done" { // Issue is in a "to do" or "in progress" state, all done here. - level.Debug(logger).Log("msg", "doing nothing, as issue is unresolved", "key", issue.Key, "label", issueLabel) + level.Debug(logger).Log("msg", "issue is unresolved, nothing to do", "key", issue.Key, "label", issueLabel) return false, nil } if r.conf.WontFixResolution != "" && issue.Fields.Resolution != nil && From 2dfa1a11155676a8f8dacf11cc223df727a6af4a Mon Sep 17 00:00:00 2001 From: Alin Sinpalean Date: Wed, 8 May 2019 12:36:00 +0300 Subject: [PATCH 17/17] Apply suggestions from code review Co-Authored-By: tdabasinskas --- pkg/notify/notify.go | 6 +++--- pkg/template/template.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/notify/notify.go b/pkg/notify/notify.go index 5934def..e0261bd 100644 --- a/pkg/notify/notify.go +++ b/pkg/notify/notify.go @@ -63,13 +63,13 @@ func (r *Receiver) Notify(data *alertmanager.Data, logger log.Logger) (bool, err if r.conf.WontFixResolution != "" && issue.Fields.Resolution != nil && issue.Fields.Resolution.Name == r.conf.WontFixResolution { // Issue is resolved as "Won't Fix" or equivalent, log a message just in case. - level.Info(logger).Log("msg", "not reopening issue, as it was resolved", "key", issue.Key, "label", issueLabel, "resolution", issue.Fields.Resolution.Name) + level.Info(logger).Log("msg", "issue was resolved as won't fix, not reopening", "key", issue.Key, "label", issueLabel, "resolution", issue.Fields.Resolution.Name) return false, nil } resolutionTime := time.Time(issue.Fields.Resolutiondate) if resolutionTime.Add(time.Duration(*r.conf.ReopenDuration)).After(time.Now()) { - level.Info(logger).Log("msg", "reopening issue, as it was resolved after reopen duration, ", "key", issue.Key, "label", issueLabel, "reopenDuration", *r.conf.ReopenDuration, "resolutionTime", resolutionTime.Format(time.RFC3339)) + level.Info(logger).Log("msg", "issue was recently resolved, reopening", "key", issue.Key, "label", issueLabel, "resolution_time", resolutionTime.Format(time.RFC3339), "reopen_duration", *r.conf.ReopenDuration) return r.reopen(issue.Key, logger) } } @@ -188,7 +188,7 @@ func (r *Receiver) search(project, issueLabel string, logger log.Logger) (*jira. if len(issues) > 0 { if len(issues) > 1 { // Swallow it, but log a message. - level.Debug(logger).Log("msg", "more than one issue matched, picking most recently resolved", "query", query, "issues", issues) + level.Debug(logger).Log("msg", " more than one issue matched, picking most recently resolved", "query", query, "issues", issues) } level.Debug(logger).Log("msg", " found", "issue", issues[0], "query", query) diff --git a/pkg/template/template.go b/pkg/template/template.go index 5cc11c3..02f11b2 100644 --- a/pkg/template/template.go +++ b/pkg/template/template.go @@ -65,12 +65,12 @@ func (t *Template) Execute(text string, data interface{}, logger log.Logger) str } tmpl, t.err = tmpl.New("").Parse(text) if t.err != nil { - level.Warn(logger).Log("msg", "failed to parse template") + level.Warn(logger).Log("msg", "failed to parse template", "template", text) return "" } var buf bytes.Buffer t.err = tmpl.Execute(&buf, data) ret := buf.String() - level.Debug(logger).Log("msg", "returning parsed template", "template", ret) + level.Debug(logger).Log("msg", " template output", "output", ret) return ret }