From 5e66ed0d0066fd50d903e5bafa89ddfdd90efc23 Mon Sep 17 00:00:00 2001 From: Jan Grewe Date: Sun, 4 Nov 2018 02:57:56 +0100 Subject: [PATCH 1/9] add Dockefile --- Dockerfile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bad4572 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM golang:1.8 +ADD . /go/src/github.com/kumina/postfix_exporter +WORKDIR /go/src/github.com/kumina/postfix_exporter +RUN apt-get update -qq && apt-get install -qqy \ + build-essential \ + libsystemd-dev +RUN go get -v ./... +RUN go build + +FROM debian:latest +EXPOSE 9154 +WORKDIR / +COPY --from=0 /go/src/github.com/kumina/postfix_exporter/postfix_exporter . +ENTRYPOINT ["/postfix_exporter"] From 7fa2e37607917112670c93b617cf9a0269ab6836 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Tue, 4 Dec 2018 16:10:28 +0100 Subject: [PATCH 2/9] postfix_exporter.go: Fix some gosec issues. See, $ gometalinter --vendor ./... postfix_exporter.go:249::warning: Potential file inclusion via variable,MEDIUM,HIGH (gosec) postfix_exporter.go:80::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:121::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:296::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:298::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:300::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:302::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:309::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:311::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:313::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:315::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:322::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:324::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:333::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:335::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:337::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:339::warning: Errors unhandled.,LOW,HIGH (gosec) postfix_exporter.go:650::warning: Errors unhandled.,LOW,HIGH (gosec) --- postfix_exporter.go | 86 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/postfix_exporter.go b/postfix_exporter.go index d7b56fe..78f8d28 100644 --- a/postfix_exporter.go +++ b/postfix_exporter.go @@ -77,7 +77,10 @@ type PostfixExporter struct { // for null bytes in the first 128 bytes of output. func CollectShowqFromReader(file io.Reader, ch chan<- prometheus.Metric) error { reader := bufio.NewReader(file) - buf, _ := reader.Peek(128) + buf, err := reader.Peek(128) + if err != nil { + log.Printf("Could not read postfix output, %v", err) + } if bytes.IndexByte(buf, 0) >= 0 { return CollectBinaryShowqFromReader(reader, ch) } @@ -118,7 +121,11 @@ func CollectTextualShowqFromReader(file io.Reader, ch chan<- prometheus.Metric) } now := time.Now() - location, _ := time.LoadLocation("Local") + location, err := time.LoadLocation("Local") + if err != nil { + log.Println(err) + } + for scanner.Scan() { matches := messageLine.FindStringSubmatch(scanner.Text()) if matches != nil { @@ -293,35 +300,65 @@ func (e *PostfixExporter) CollectFromLogline(line string) { } } else if logMatches[1] == "lmtp" { if lmtpMatches := lmtpPipeSMTPLine.FindStringSubmatch(logMatches[2]); lmtpMatches != nil { - pdelay, _ := strconv.ParseFloat(lmtpMatches[2], 64) + pdelay, err := strconv.ParseFloat(lmtpMatches[2], 64) + if err != nil { + log.Printf("Couldn't convert LMTP pdelay: %v", err) + } e.lmtpDelays.WithLabelValues("before_queue_manager").Observe(pdelay) - adelay, _ := strconv.ParseFloat(lmtpMatches[3], 64) + adelay, err := strconv.ParseFloat(lmtpMatches[3], 64) + if err != nil { + log.Printf("Couldn't convert LMTP adelay: %v", err) + } e.lmtpDelays.WithLabelValues("queue_manager").Observe(adelay) - sdelay, _ := strconv.ParseFloat(lmtpMatches[4], 64) + sdelay, err := strconv.ParseFloat(lmtpMatches[4], 64) + if err != nil { + log.Printf("Couldn't convert LMTP adelay: %v", err) + } e.lmtpDelays.WithLabelValues("connection_setup").Observe(sdelay) - xdelay, _ := strconv.ParseFloat(lmtpMatches[5], 64) + xdelay, err := strconv.ParseFloat(lmtpMatches[5], 64) + if err != nil { + log.Printf("Couldn't convert LMTP xdelay: %v", err) + } e.lmtpDelays.WithLabelValues("transmission").Observe(xdelay) } else { e.unsupportedLogEntries.WithLabelValues(logMatches[1]).Inc() } } else if logMatches[1] == "pipe" { if pipeMatches := lmtpPipeSMTPLine.FindStringSubmatch(logMatches[2]); pipeMatches != nil { - pdelay, _ := strconv.ParseFloat(pipeMatches[2], 64) + pdelay, err := strconv.ParseFloat(pipeMatches[2], 64) + if err != nil { + log.Printf("Couldn't convert PIPE pdelay: %v", err) + } e.pipeDelays.WithLabelValues(pipeMatches[1], "before_queue_manager").Observe(pdelay) - adelay, _ := strconv.ParseFloat(pipeMatches[3], 64) + adelay, err := strconv.ParseFloat(pipeMatches[3], 64) + if err != nil { + log.Printf("Couldn't convert PIPE adelay: %v", err) + } e.pipeDelays.WithLabelValues(pipeMatches[1], "queue_manager").Observe(adelay) - sdelay, _ := strconv.ParseFloat(pipeMatches[4], 64) + sdelay, err := strconv.ParseFloat(pipeMatches[4], 64) + if err != nil { + log.Printf("Couldn't convert PIPE sdelay: %v", err) + } e.pipeDelays.WithLabelValues(pipeMatches[1], "connection_setup").Observe(sdelay) - xdelay, _ := strconv.ParseFloat(pipeMatches[5], 64) + xdelay, err := strconv.ParseFloat(pipeMatches[5], 64) + if err != nil { + log.Printf("Couldn't convert PIPE xdelay: %v", err) + } e.pipeDelays.WithLabelValues(pipeMatches[1], "transmission").Observe(xdelay) } else { e.unsupportedLogEntries.WithLabelValues(logMatches[1]).Inc() } } else if logMatches[1] == "qmgr" { if qmgrInsertMatches := qmgrInsertLine.FindStringSubmatch(logMatches[2]); qmgrInsertMatches != nil { - size, _ := strconv.ParseFloat(qmgrInsertMatches[1], 64) + size, err := strconv.ParseFloat(qmgrInsertMatches[1], 64) + if err != nil { + log.Printf("Couldn't convert QMGR size: %v", err) + } e.qmgrInsertsSize.Observe(size) - nrcpt, _ := strconv.ParseFloat(qmgrInsertMatches[2], 64) + nrcpt, err := strconv.ParseFloat(qmgrInsertMatches[2], 64) + if err != nil { + log.Printf("Couldn't convert QMGR nrcpt: %v", err) + } e.qmgrInsertsNrcpt.Observe(nrcpt) } else if strings.HasSuffix(logMatches[2], ": removed") { e.qmgrRemoves.Inc() @@ -330,13 +367,25 @@ func (e *PostfixExporter) CollectFromLogline(line string) { } } else if logMatches[1] == "smtp" { if smtpMatches := lmtpPipeSMTPLine.FindStringSubmatch(logMatches[2]); smtpMatches != nil { - pdelay, _ := strconv.ParseFloat(smtpMatches[2], 64) + pdelay, err := strconv.ParseFloat(smtpMatches[2], 64) + if err != nil { + log.Printf("Couldn't convert SMTP pdelay: %v", err) + } e.smtpDelays.WithLabelValues("before_queue_manager").Observe(pdelay) - adelay, _ := strconv.ParseFloat(smtpMatches[3], 64) + adelay, err := strconv.ParseFloat(smtpMatches[3], 64) + if err != nil { + log.Printf("Couldn't convert SMTP adelay: %v", err) + } e.smtpDelays.WithLabelValues("queue_manager").Observe(adelay) - sdelay, _ := strconv.ParseFloat(smtpMatches[4], 64) + sdelay, err := strconv.ParseFloat(smtpMatches[4], 64) + if err != nil { + log.Printf("Couldn't convert SMTP sdelay: %v", err) + } e.smtpDelays.WithLabelValues("connection_setup").Observe(sdelay) - xdelay, _ := strconv.ParseFloat(smtpMatches[5], 64) + xdelay, err := strconv.ParseFloat(smtpMatches[5], 64) + if err != nil { + log.Printf("Couldn't convert SMTP xdelay: %v", err) + } e.smtpDelays.WithLabelValues("transmission").Observe(xdelay) } else if smtpTLSMatches := smtpTLSLine.FindStringSubmatch(logMatches[2]); smtpTLSMatches != nil { e.smtpTLSConnects.WithLabelValues(smtpTLSMatches[1:]...).Inc() @@ -647,7 +696,7 @@ func main() { http.Handle(*metricsPath, prometheus.Handler()) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(` + _, err = w.Write([]byte(` Postfix Exporter @@ -655,6 +704,9 @@ func main() {

Metrics

`)) + if err != nil { + panic(err) + } }) log.Print("Listening on ", *listenAddress) From b22b536722a568455ab45ebbd5202c3458976a58 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Tue, 4 Dec 2018 16:15:33 +0100 Subject: [PATCH 3/9] .gitignore: Exclude binary and vim editor temporary files. --- .gitignore | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 27626c8..f238da4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ +# Editor files +*~ +-.idea/ + +# Test binary, build with `go test -c` +*.test + +# Binaries postfix_exporter -.idea/ From 76f8dd448baf910ddcccab643ecc316fbedba5a8 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Tue, 4 Dec 2018 16:50:01 +0100 Subject: [PATCH 4/9] postfix_exporter.go: Comment out unused `CollectShowqFromFile` function See, $ gometalinter --vendor ./... postfix_exporter.go:256:1:warning: CollectShowqFromFile is unused (deadcode) --- postfix_exporter.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/postfix_exporter.go b/postfix_exporter.go index 78f8d28..795c5d9 100644 --- a/postfix_exporter.go +++ b/postfix_exporter.go @@ -252,14 +252,14 @@ func CollectBinaryShowqFromReader(file io.Reader, ch chan<- prometheus.Metric) e } // CollectShowqFromFile collects Postfix queue statistics from a file. -func CollectShowqFromFile(path string, ch chan<- prometheus.Metric) error { - fd, err := os.Open(path) - if err != nil { - return err - } - defer fd.Close() - return CollectShowqFromReader(fd, ch) -} +//func CollectShowqFromFile(path string, ch chan<- prometheus.Metric) error { +// fd, err := os.Open(path) +// if err != nil { +// return err +// } +// defer fd.Close() +// return CollectShowqFromReader(fd, ch) +//} // CollectShowqFromSocket collects Postfix queue statistics from a socket. func CollectShowqFromSocket(path string, ch chan<- prometheus.Metric) error { From a0059f793e69166d4ce3280891eb1b7f61cc1772 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Tue, 4 Dec 2018 17:13:17 +0100 Subject: [PATCH 5/9] systemd.go: Fix gosec issue. See, $ gometalinter --vendor ./... systemd.go:49::warning: Errors unhandled.,LOW,HIGH (gosec) --- systemd.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/systemd.go b/systemd.go index c263e35..9a78ff8 100644 --- a/systemd.go +++ b/systemd.go @@ -46,8 +46,10 @@ func NewJournal(unit, slice, path string) (j *Journal, err error) { } // Start at end of journal - j.SeekRealtimeUsec(uint64(time.Now().UnixNano() / 1000)) - + err = j.SeekRealtimeUsec(uint64(time.Now().UnixNano() / 1000)) + if err != nil { + log.Printf("%v", err) + } return } From 4d195655fda1140fbbb0f1f35ff28f55cd3cc0a1 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Sun, 16 Dec 2018 10:55:34 +0100 Subject: [PATCH 6/9] postfix_exporter.go: Fix megacheck issues See, $ gometalinter --vendor --deadline 10m --disable-all --enable=megacheck ./... postfix_exporter.go:97:17:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:276:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:277:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:278:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:279:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:280:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:281:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:282:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:283:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:284:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) postfix_exporter.go:285:40:warning: should use raw string (`...`) with regexp.MustCompile to avoid having to escape twice (S1007) (megacheck) Signed-off-by: Mario Trangoni --- postfix_exporter.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/postfix_exporter.go b/postfix_exporter.go index 795c5d9..adcac92 100644 --- a/postfix_exporter.go +++ b/postfix_exporter.go @@ -94,7 +94,7 @@ func CollectTextualShowqFromReader(file io.Reader, ch chan<- prometheus.Metric) // Regular expression for matching postqueue's output. Example: // "A07A81514 5156 Tue Feb 14 13:13:54 MAILER-DAEMON" - messageLine := regexp.MustCompile("^[0-9A-F]+([\\*!]?) +(\\d+) (\\w{3} \\w{3} +\\d+ +\\d+:\\d{2}:\\d{2}) +") + messageLine := regexp.MustCompile(`^[0-9A-F]+([\*!]?) +(\d+) (\w{3} \w{3} +\d+ +\d+:\d{2}:\d{2}) +`) // Histograms tracking the messages by size and age. sizeHistogram := prometheus.NewHistogramVec( @@ -273,16 +273,16 @@ func CollectShowqFromSocket(path string, ch chan<- prometheus.Metric) error { // Patterns for parsing log messages. var ( - logLine = regexp.MustCompile(" ?postfix/(\\w+)\\[\\d+\\]: (.*)") - lmtpPipeSMTPLine = regexp.MustCompile(", relay=(\\S+), .*, delays=([0-9\\.]+)/([0-9\\.]+)/([0-9\\.]+)/([0-9\\.]+), ") - qmgrInsertLine = regexp.MustCompile(":.*, size=(\\d+), nrcpt=(\\d+) ") - smtpTLSLine = regexp.MustCompile("^(\\S+) TLS connection established to \\S+: (\\S+) with cipher (\\S+) \\((\\d+)/(\\d+) bits\\)$") - smtpdFCrDNSErrorsLine = regexp.MustCompile("^warning: hostname \\S+ does not resolve to address ") - smtpdProcessesSASLLine = regexp.MustCompile(": client=.*, sasl_username=(\\S+)") - smtpdRejectsLine = regexp.MustCompile("^NOQUEUE: reject: RCPT from \\S+: ([0-9]+) ") - smtpdLostConnectionLine = regexp.MustCompile("^lost connection after (\\w+) from ") - smtpdSASLAuthenticationFailuresLine = regexp.MustCompile("^warning: \\S+: SASL \\S+ authentication failed: ") - smtpdTLSLine = regexp.MustCompile("^(\\S+) TLS connection established from \\S+: (\\S+) with cipher (\\S+) \\((\\d+)/(\\d+) bits\\)$") + logLine = regexp.MustCompile(` ?postfix/(\w+)\[\d+\]: (.*)`) + lmtpPipeSMTPLine = regexp.MustCompile(`, relay=(\S+), .*, delays=([0-9\.]+)/([0-9\.]+)/([0-9\.]+)/([0-9\.]+), `) + qmgrInsertLine = regexp.MustCompile(`:.*, size=(\d+), nrcpt=(\d+) `) + smtpTLSLine = regexp.MustCompile(`^(\S+) TLS connection established to \S+: (\S+) with cipher (\S+) \((\d+)/(\d+) bits\)$`) + smtpdFCrDNSErrorsLine = regexp.MustCompile(`^warning: hostname \S+ does not resolve to address `) + smtpdProcessesSASLLine = regexp.MustCompile(`: client=.*, sasl_username=(\S+)`) + smtpdRejectsLine = regexp.MustCompile(`^NOQUEUE: reject: RCPT from \S+: ([0-9]+) `) + smtpdLostConnectionLine = regexp.MustCompile(`^lost connection after (\w+) from `) + smtpdSASLAuthenticationFailuresLine = regexp.MustCompile(`^warning: \S+: SASL \S+ authentication failed: `) + smtpdTLSLine = regexp.MustCompile(`^(\S+) TLS connection established from \S+: (\S+) with cipher (\S+) \((\d+)/(\d+) bits\)$`) ) // CollectFromLogline collects metrict from a Postfix log line. From f51b1f882d9e785172120ea864497b6878a4bfaf Mon Sep 17 00:00:00 2001 From: Bart Vercoulen Date: Mon, 17 Dec 2018 17:01:01 +0100 Subject: [PATCH 7/9] Refactored to kingpin and fixed a EOF bug in CollectShowqFromReader. --- nosystemd.go | 9 +++++++-- postfix_exporter.go | 21 +++++++++++---------- systemd.go | 12 ++++++------ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/nosystemd.go b/nosystemd.go index cfbffce..33c1a16 100644 --- a/nosystemd.go +++ b/nosystemd.go @@ -3,14 +3,19 @@ package main -import "io" +import( + "io" + + "github.com/alecthomas/kingpin" +) + type Journal struct { io.Closer Path string } -func systemdFlags(enable *bool, unit, slice, path *string) {} +func systemdFlags(enable *bool, unit, slice, path *string, app *kingpin.Application) {} func NewJournal(unit, slice, path string) (*Journal, error) { return nil, nil diff --git a/postfix_exporter.go b/postfix_exporter.go index adcac92..b853209 100644 --- a/postfix_exporter.go +++ b/postfix_exporter.go @@ -17,8 +17,8 @@ import ( "bufio" "bytes" "errors" - "flag" "fmt" + "github.com/alecthomas/kingpin" "io" "log" "net" @@ -78,7 +78,7 @@ type PostfixExporter struct { func CollectShowqFromReader(file io.Reader, ch chan<- prometheus.Metric) error { reader := bufio.NewReader(file) buf, err := reader.Peek(128) - if err != nil { + if err != nil && err != io.EOF { log.Printf("Could not read postfix output, %v", err) } if bytes.IndexByte(buf, 0) >= 0 { @@ -663,16 +663,17 @@ func (e *PostfixExporter) Collect(ch chan<- prometheus.Metric) { func main() { var ( - listenAddress = flag.String("web.listen-address", ":9154", "Address to listen on for web interface and telemetry.") - metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.") - postfixShowqPath = flag.String("postfix.showq_path", "/var/spool/postfix/public/showq", "Path at which Postfix places its showq socket.") - postfixLogfilePath = flag.String("postfix.logfile_path", "/var/log/postfix_exporter_input.log", "Path where Postfix writes log entries. This file will be truncated by this exporter.") - - systemdEnable bool + app = kingpin.New("postfix_exporter", "Prometheus metrics exporter for postfix") + listenAddress = app.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9154").String() + metricsPath = app.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String() + postfixShowqPath = app.Flag("postfix.showq_path", "Path at which Postfix places its showq socket.").Default("/var/spool/postfix/public/showq").String() + postfixLogfilePath = app.Flag("postfix.logfile_path", "Path where Postfix writes log entries. This file will be truncated by this exporter.").Default("/var/log/postfix_exporter_input.log").String() + systemdEnable bool systemdUnit, systemdSlice, systemdJournalPath string ) - systemdFlags(&systemdEnable, &systemdUnit, &systemdSlice, &systemdJournalPath) - flag.Parse() + systemdFlags(&systemdEnable, &systemdUnit, &systemdSlice, &systemdJournalPath, app) + + kingpin.MustParse(app.Parse(os.Args[1:])) var journal *Journal if systemdEnable { diff --git a/systemd.go b/systemd.go index 9a78ff8..d9d02f7 100644 --- a/systemd.go +++ b/systemd.go @@ -3,12 +3,12 @@ package main import ( - "flag" "fmt" "log" "sync" "time" + "github.com/alecthomas/kingpin" "github.com/coreos/go-systemd/sdjournal" ) @@ -88,11 +88,11 @@ func (j *Journal) NextMessage() (s string, c uint64, err error) { } // systemdFlags sets the flags for use with systemd -func systemdFlags(enable *bool, unit, slice, path *string) { - flag.BoolVar(enable, "systemd.enable", false, "Read from the systemd journal instead of log") - flag.StringVar(unit, "systemd.unit", "postfix.service", "Name of the Postfix systemd unit.") - flag.StringVar(slice, "systemd.slice", "", "Name of the Postfix systemd slice. Overrides the systemd unit.") - flag.StringVar(path, "systemd.journal_path", "", "Path to the systemd journal") +func systemdFlags(enable *bool, unit, slice, path *string, app *kingpin.Application) { + app.Flag("systemd.enable", "Read from the systemd journal instead of log").Default("false").BoolVar(enable) + app.Flag("systemd.unit", "Name of the Postfix systemd unit.").Default("postfix.service").StringVar(unit) + app.Flag("systemd.slice", "Name of the Postfix systemd slice. Overrides the systemd unit.").Default("").StringVar(slice) + app.Flag("systemd.journal_path", "Path to the systemd journal").Default("").StringVar(path) } // CollectLogfileFromJournal Collects entries from the systemd journal. From 27ac982de7c2e44d51e8d2feac903a8c5548042c Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Wed, 6 Feb 2019 13:42:09 +0100 Subject: [PATCH 8/9] postfix_exporter.go: Handle the case where EOF is reached. See these annoying messages, Feb 06 13:34:03 hostname postfix_exporter[30713]: 2019/02/06 13:34:03 Could not read postfix output, EOF Feb 06 13:34:27 hostname postfix_exporter[30713]: 2019/02/06 13:34:27 Could not read postfix output, EOF Feb 06 13:35:27 hostname postfix_exporter[30713]: 2019/02/06 13:35:27 Could not read postfix output, EOF Feb 06 13:36:27 hostname postfix_exporter[30713]: 2019/02/06 13:36:27 Could not read postfix output, EOF Feb 06 13:37:27 hostname postfix_exporter[30713]: 2019/02/06 13:37:27 Could not read postfix output, EOF Feb 06 13:38:27 hostname postfix_exporter[30713]: 2019/02/06 13:38:27 Could not read postfix output, EOF Feb 06 13:39:27 hostname postfix_exporter[30713]: 2019/02/06 13:39:27 Could not read postfix output, EOF Feb 06 13:40:27 hostname postfix_exporter[30713]: 2019/02/06 13:40:27 Could not read postfix output, EOF Feb 06 13:41:27 hostname postfix_exporter[30713]: 2019/02/06 13:41:27 Could not read postfix output, EOF Feb 06 13:42:27 hostname postfix_exporter[30713]: 2019/02/06 13:42:27 Could not read postfix output, EOF --- postfix_exporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postfix_exporter.go b/postfix_exporter.go index adcac92..6633f3e 100644 --- a/postfix_exporter.go +++ b/postfix_exporter.go @@ -78,7 +78,7 @@ type PostfixExporter struct { func CollectShowqFromReader(file io.Reader, ch chan<- prometheus.Metric) error { reader := bufio.NewReader(file) buf, err := reader.Peek(128) - if err != nil { + if err != nil && err != io.EOF { log.Printf("Could not read postfix output, %v", err) } if bytes.IndexByte(buf, 0) >= 0 { From d73bd20065c904350ae4339b5de4b50a39852da0 Mon Sep 17 00:00:00 2001 From: Bart Vercoulen Date: Fri, 15 Feb 2019 10:41:53 +0100 Subject: [PATCH 9/9] Fixed formatting. --- postfix_exporter.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/postfix_exporter.go b/postfix_exporter.go index b853209..82376bb 100644 --- a/postfix_exporter.go +++ b/postfix_exporter.go @@ -238,11 +238,11 @@ func CollectBinaryShowqFromReader(file io.Reader, ch chan<- prometheus.Metric) e sizeHistogram.WithLabelValues(queue).Observe(size) } else if key == "time" { // Message time as a UNIX timestamp. - time, err := strconv.ParseFloat(value, 64) + utime, err := strconv.ParseFloat(value, 64) if err != nil { return err } - ageHistogram.WithLabelValues(queue).Observe(now - time) + ageHistogram.WithLabelValues(queue).Observe(now - utime) } } @@ -663,12 +663,12 @@ func (e *PostfixExporter) Collect(ch chan<- prometheus.Metric) { func main() { var ( - app = kingpin.New("postfix_exporter", "Prometheus metrics exporter for postfix") - listenAddress = app.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9154").String() - metricsPath = app.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String() - postfixShowqPath = app.Flag("postfix.showq_path", "Path at which Postfix places its showq socket.").Default("/var/spool/postfix/public/showq").String() - postfixLogfilePath = app.Flag("postfix.logfile_path", "Path where Postfix writes log entries. This file will be truncated by this exporter.").Default("/var/log/postfix_exporter_input.log").String() - systemdEnable bool + app = kingpin.New("postfix_exporter", "Prometheus metrics exporter for postfix") + listenAddress = app.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9154").String() + metricsPath = app.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String() + postfixShowqPath = app.Flag("postfix.showq_path", "Path at which Postfix places its showq socket.").Default("/var/spool/postfix/public/showq").String() + postfixLogfilePath = app.Flag("postfix.logfile_path", "Path where Postfix writes log entries. This file will be truncated by this exporter.").Default("/var/log/postfix_exporter_input.log").String() + systemdEnable bool systemdUnit, systemdSlice, systemdJournalPath string ) systemdFlags(&systemdEnable, &systemdUnit, &systemdSlice, &systemdJournalPath, app)