Skip to content

Commit

Permalink
Move metrics ticker to log pkg for #67
Browse files Browse the repository at this point in the history
  • Loading branch information
jhillyerd committed Dec 27, 2017
1 parent dec6762 commit fcc0848
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 54 deletions.
62 changes: 62 additions & 0 deletions log/metrics.go
@@ -0,0 +1,62 @@
package log

import (
"container/list"
"expvar"
"strings"
"time"
)

// TickerFunc is the type of metrics function accepted by AddTickerFunc
type TickerFunc func()

var tickerFuncChan = make(chan TickerFunc)

func init() {
go metricsTicker()
}

// AddTickerFunc adds a new function callback to the list of metrics TickerFuncs that get
// called each minute.
func AddTickerFunc(f TickerFunc) {
tickerFuncChan <- f
}

// PushMetric adds the metric to the end of the list and returns a comma separated string of the
// previous 61 entries. We return 61 instead of 60 (an hour) because the chart on the client
// tracks deltas between these values - there is nothing to compare the first value against.
func PushMetric(history *list.List, ev expvar.Var) string {
history.PushBack(ev.String())
if history.Len() > 61 {
history.Remove(history.Front())
}
return joinStringList(history)
}

// joinStringList joins a List containing strings by commas
func joinStringList(listOfStrings *list.List) string {
if listOfStrings.Len() == 0 {
return ""
}
s := make([]string, 0, listOfStrings.Len())
for e := listOfStrings.Front(); e != nil; e = e.Next() {
s = append(s, e.Value.(string))
}
return strings.Join(s, ",")
}

func metricsTicker() {
funcs := make([]TickerFunc, 0)
ticker := time.NewTicker(time.Minute)

for {
select {
case <-ticker.C:
for _, f := range funcs {
f()
}
case f := <-tickerFuncChan:
funcs = append(funcs, f)
}
}
}
63 changes: 22 additions & 41 deletions smtpd/listener.go
Expand Up @@ -16,6 +16,28 @@ import (
"github.com/jhillyerd/inbucket/msghub"
)

func init() {
m := expvar.NewMap("smtp")
m.Set("ConnectsTotal", expConnectsTotal)
m.Set("ConnectsHist", expConnectsHist)
m.Set("ConnectsCurrent", expConnectsCurrent)
m.Set("ReceivedTotal", expReceivedTotal)
m.Set("ReceivedHist", expReceivedHist)
m.Set("ErrorsTotal", expErrorsTotal)
m.Set("ErrorsHist", expErrorsHist)
m.Set("WarnsTotal", expWarnsTotal)
m.Set("WarnsHist", expWarnsHist)

log.AddTickerFunc(func() {
expReceivedHist.Set(log.PushMetric(deliveredHist, expReceivedTotal))
expConnectsHist.Set(log.PushMetric(connectsHist, expConnectsTotal))
expErrorsHist.Set(log.PushMetric(errorsHist, expErrorsTotal))
expWarnsHist.Set(log.PushMetric(warnsHist, expWarnsTotal))
expRetentionDeletesHist.Set(log.PushMetric(retentionDeletesHist, expRetentionDeletesTotal))
expRetainedHist.Set(log.PushMetric(retainedHist, expRetainedCurrent))
})
}

// Server holds the configuration and state of our SMTP server
type Server struct {
// Configuration
Expand Down Expand Up @@ -179,44 +201,3 @@ func (s *Server) Drain() {
log.Tracef("SMTP connections have drained")
s.retentionScanner.Join()
}

// When the provided Ticker ticks, we update our metrics history
func metricsTicker(t *time.Ticker) {
ok := true
for ok {
_, ok = <-t.C
expReceivedHist.Set(pushMetric(deliveredHist, expReceivedTotal))
expConnectsHist.Set(pushMetric(connectsHist, expConnectsTotal))
expErrorsHist.Set(pushMetric(errorsHist, expErrorsTotal))
expWarnsHist.Set(pushMetric(warnsHist, expWarnsTotal))
expRetentionDeletesHist.Set(pushMetric(retentionDeletesHist, expRetentionDeletesTotal))
expRetainedHist.Set(pushMetric(retainedHist, expRetainedCurrent))
}
}

// pushMetric adds the metric to the end of the list and returns a comma separated string of the
// previous 61 entries. We return 61 instead of 60 (an hour) because the chart on the client
// tracks deltas between these values - there is nothing to compare the first value against.
func pushMetric(history *list.List, ev expvar.Var) string {
history.PushBack(ev.String())
if history.Len() > 61 {
history.Remove(history.Front())
}
return JoinStringList(history)
}

func init() {
m := expvar.NewMap("smtp")
m.Set("ConnectsTotal", expConnectsTotal)
m.Set("ConnectsHist", expConnectsHist)
m.Set("ConnectsCurrent", expConnectsCurrent)
m.Set("ReceivedTotal", expReceivedTotal)
m.Set("ReceivedHist", expReceivedHist)
m.Set("ErrorsTotal", expErrorsTotal)
m.Set("ErrorsHist", expErrorsHist)
m.Set("WarnsTotal", expWarnsTotal)
m.Set("WarnsHist", expWarnsHist)

t := time.NewTicker(time.Minute)
go metricsTicker(t)
}
13 changes: 0 additions & 13 deletions smtpd/utils.go
Expand Up @@ -2,7 +2,6 @@ package smtpd

import (
"bytes"
"container/list"
"crypto/sha1"
"fmt"
"io"
Expand Down Expand Up @@ -53,18 +52,6 @@ func HashMailboxName(mailbox string) string {
return fmt.Sprintf("%x", h.Sum(nil))
}

// JoinStringList joins a List containing strings by commas
func JoinStringList(listOfStrings *list.List) string {
if listOfStrings.Len() == 0 {
return ""
}
s := make([]string, 0, listOfStrings.Len())
for e := listOfStrings.Front(); e != nil; e = e.Next() {
s = append(s, e.Value.(string))
}
return strings.Join(s, ",")
}

// ValidateDomainPart returns true if the domain part complies to RFC3696, RFC1035
func ValidateDomainPart(domain string) bool {
if len(domain) == 0 {
Expand Down

0 comments on commit fcc0848

Please sign in to comment.