From 8113240edfbad57a2891d7ab6b06d0cc185e4844 Mon Sep 17 00:00:00 2001 From: Per Abich Date: Sun, 23 Feb 2020 20:41:35 +0100 Subject: [PATCH] Reduced the cardinality of postfix_smtpd_messages_processed_total for #38 by not aggregating per user but only for the sasl_method --- postfix_exporter.go | 8 ++-- postfix_exporter_test.go | 89 ++++++++++++++++++---------------------- 2 files changed, 44 insertions(+), 53 deletions(-) diff --git a/postfix_exporter.go b/postfix_exporter.go index 8908d07..4bbe70c 100644 --- a/postfix_exporter.go +++ b/postfix_exporter.go @@ -277,7 +277,7 @@ var ( smtpTLSLine = regexp.MustCompile(`^(\S+) TLS connection established to \S+: (\S+) with cipher (\S+) \((\d+)/(\d+) bits\)`) smtpConnectionTimedOut = regexp.MustCompile(`^connect\s+to\s+(.*)\[(.*)\]:(\d+):\s+(Connection timed out)$`) smtpdFCrDNSErrorsLine = regexp.MustCompile(`^warning: hostname \S+ does not resolve to address `) - smtpdProcessesSASLLine = regexp.MustCompile(`: client=.*, sasl_username=(\S+)`) + smtpdProcessesSASLLine = regexp.MustCompile(`: client=.*, sasl_method=(\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: `) @@ -364,8 +364,8 @@ func (e *PostfixExporter) CollectFromLogLine(line string) { e.smtpdLostConnections.WithLabelValues(smtpdLostConnectionMatches[1]).Inc() } else if smtpdProcessesSASLMatches := smtpdProcessesSASLLine.FindStringSubmatch(remainder); smtpdProcessesSASLMatches != nil { e.smtpdProcesses.WithLabelValues(smtpdProcessesSASLMatches[1]).Inc() - } else if strings.Contains(logMatches[2], ": client=") { - e.smtpdProcesses.WithLabelValues("").Inc() + } else if strings.Contains(remainder, ": client=") { + e.smtpdProcesses.WithLabelValues(smtpdProcessesSASLMatches[1]).Inc() } else if smtpdRejectsMatches := smtpdRejectsLine.FindStringSubmatch(remainder); smtpdRejectsMatches != nil { e.smtpdRejects.WithLabelValues(smtpdRejectsMatches[1]).Inc() } else if smtpdSASLAuthenticationFailuresLine.MatchString(remainder) { @@ -557,7 +557,7 @@ func NewPostfixExporter(showqPath string, logfilePath string, journal *Journal, Name: "smtpd_messages_processed_total", Help: "Total number of messages processed.", }, - []string{"sasl_username"}), + []string{"sasl_method"}), smtpdRejects: prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: "postfix", diff --git a/postfix_exporter_test.go b/postfix_exporter_test.go index b3bcecf..a56309d 100644 --- a/postfix_exporter_test.go +++ b/postfix_exporter_test.go @@ -35,10 +35,11 @@ func TestPostfixExporter_CollectFromLogline(t *testing.T) { unsupportedLogEntries *prometheus.CounterVec } type args struct { - line []string - removedCount int - saslFailedCount int - outgoingTLS int + line []string + removedCount int + saslFailedCount int + outgoingTLS int + smtpdMessagesProcessed int } tests := []struct { name string @@ -55,7 +56,7 @@ func TestPostfixExporter_CollectFromLogline(t *testing.T) { saslFailedCount: 0, }, fields: fields{ - qmgrRemoves: &testCounter{count: 0}, + qmgrRemoves: prometheus.NewCounter(prometheus.CounterOpts{}), unsupportedLogEntries: prometheus.NewCounterVec(prometheus.CounterOpts{}, []string{"process"}), }, }, @@ -99,7 +100,7 @@ func TestPostfixExporter_CollectFromLogline(t *testing.T) { saslFailedCount: 0, }, fields: fields{ - qmgrRemoves: &testCounter{count: 0}, + qmgrRemoves: prometheus.NewCounter(prometheus.CounterOpts{}), unsupportedLogEntries: prometheus.NewCounterVec(prometheus.CounterOpts{}, []string{"process"}), }, }, @@ -115,10 +116,26 @@ func TestPostfixExporter_CollectFromLogline(t *testing.T) { removedCount: 0, }, fields: fields{ - smtpdSASLAuthenticationFailures: &testCounter{count: 0}, + smtpdSASLAuthenticationFailures: prometheus.NewCounter(prometheus.CounterOpts{}), unsupportedLogEntries: prometheus.NewCounterVec(prometheus.CounterOpts{}, []string{"process"}), }, }, + { + name: "SASL login", + args: args{ + line: []string{ + "Oct 30 13:19:26 mailgw-out1 postfix/smtpd[27530]: EB4B2C19E2: client=xxx[1.2.3.4], sasl_method=PLAIN, sasl_username=user@domain", + }, + removedCount: 0, + saslFailedCount: 0, + outgoingTLS: 0, + smtpdMessagesProcessed: 1, + }, + fields: fields{ + unsupportedLogEntries: prometheus.NewCounterVec(prometheus.CounterOpts{}, []string{"process"}), + smtpdProcesses: prometheus.NewCounterVec(prometheus.CounterOpts{}, []string{"sasl_method"}), + }, + }, { name: "Issue #35", args: args{ @@ -169,11 +186,12 @@ func TestPostfixExporter_CollectFromLogline(t *testing.T) { } assertCounterEquals(t, e.qmgrRemoves, tt.args.removedCount, "Wrong number of lines counted") assertCounterEquals(t, e.smtpdSASLAuthenticationFailures, tt.args.saslFailedCount, "Wrong number of Sasl counter counted") - assertCounterVecEquals(t, e.smtpTLSConnects, tt.args.outgoingTLS, "Wrong number of TLS connections counted") + assertCounterEquals(t, e.smtpTLSConnects, tt.args.outgoingTLS, "Wrong number of TLS connections counted") + assertCounterEquals(t, e.smtpdProcesses, tt.args.smtpdMessagesProcessed, "Wrong number of smtpd messages processed") }) } } -func assertCounterVecEquals(t *testing.T, counter prometheus.Collector, expected int, message string) { +func assertCounterEquals(t *testing.T, counter prometheus.Collector, expected int, message string) { if counter != nil && expected > 0 { switch counter.(type) { @@ -191,48 +209,21 @@ func assertCounterVecEquals(t *testing.T, counter prometheus.Collector, expected count += int(*metricDto.Counter.Value) } assert.Equal(t, expected, count, message) + case prometheus.Counter: + metricsChan := make(chan prometheus.Metric) + go func() { + counter.Collect(metricsChan) + close(metricsChan) + }() + var count int = 0 + for metric := range metricsChan { + metricDto := io_prometheus_client.Metric{} + metric.Write(&metricDto) + count += int(*metricDto.Counter.Value) + } + assert.Equal(t, expected, count, message) default: t.Fatal("Type not implemented") } } } -func assertCounterEquals(t *testing.T, counter prometheus.Counter, expected int, message string) { - - if counter != nil && expected > 0 { - switch counter.(type) { - case *testCounter: - counter := counter.(*testCounter) - assert.Equal(t, expected, counter.Count(), message) - default: - t.Fatal("Type not implemented") - } - } -} - -type testCounter struct { - count int -} - -func (t *testCounter) setCount(count int) { - t.count = count -} - -func (t *testCounter) Count() int { - return t.count -} - -func (t *testCounter) Add(_ float64) { -} -func (t *testCounter) Collect(_ chan<- prometheus.Metric) { -} -func (t *testCounter) Describe(_ chan<- *prometheus.Desc) { -} -func (t *testCounter) Desc() *prometheus.Desc { - return nil -} -func (t *testCounter) Inc() { - t.count++ -} -func (t *testCounter) Write(_ *io_prometheus_client.Metric) error { - return nil -}