mirror of
https://github.com/coredns/coredns.git
synced 2025-12-06 10:25:10 -05:00
plugin/errors: 'consolidate' option (#2192)
- see more details at https://github.com/infobloxopen/coredns-plugin-errors/pull/3
This commit is contained in:
committed by
Miek Gieben
parent
b0a89452ef
commit
7b25d18019
@@ -1,8 +1,12 @@
|
||||
// Package errors implements an HTTP error handling plugin.
|
||||
// Package errors implements an error handling plugin.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||
@@ -11,19 +15,98 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
var log = clog.NewWithPlugin("errors")
|
||||
|
||||
type pattern struct {
|
||||
ptimer unsafe.Pointer
|
||||
count uint32
|
||||
period time.Duration
|
||||
pattern *regexp.Regexp
|
||||
}
|
||||
|
||||
func (p *pattern) timer() *time.Timer {
|
||||
return (*time.Timer)(atomic.LoadPointer(&p.ptimer))
|
||||
}
|
||||
|
||||
func (p *pattern) setTimer(t *time.Timer) {
|
||||
atomic.StorePointer(&p.ptimer, unsafe.Pointer(t))
|
||||
}
|
||||
|
||||
// errorHandler handles DNS errors (and errors from other plugin).
|
||||
type errorHandler struct{ Next plugin.Handler }
|
||||
type errorHandler struct {
|
||||
patterns []*pattern
|
||||
eLogger func(int, string, string, string)
|
||||
cLogger func(uint32, string, time.Duration)
|
||||
stopFlag uint32
|
||||
Next plugin.Handler
|
||||
}
|
||||
|
||||
func newErrorHandler() *errorHandler {
|
||||
return &errorHandler{eLogger: errorLogger, cLogger: consLogger}
|
||||
}
|
||||
|
||||
func errorLogger(code int, qName, qType, err string) {
|
||||
log.Errorf("%d %s %s: %s", code, qName, qType, err)
|
||||
}
|
||||
|
||||
func consLogger(cnt uint32, pattern string, p time.Duration) {
|
||||
log.Errorf("%d errors like '%s' occured in last %s", cnt, pattern, p)
|
||||
}
|
||||
|
||||
func (h *errorHandler) logPattern(i int) {
|
||||
cnt := atomic.SwapUint32(&h.patterns[i].count, 0)
|
||||
if cnt > 0 {
|
||||
h.cLogger(cnt, h.patterns[i].pattern.String(), h.patterns[i].period)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *errorHandler) inc(i int) bool {
|
||||
if atomic.LoadUint32(&h.stopFlag) > 0 {
|
||||
return false
|
||||
}
|
||||
if atomic.AddUint32(&h.patterns[i].count, 1) == 1 {
|
||||
ind := i
|
||||
t := time.AfterFunc(h.patterns[ind].period, func() {
|
||||
h.logPattern(ind)
|
||||
})
|
||||
h.patterns[ind].setTimer(t)
|
||||
if atomic.LoadUint32(&h.stopFlag) > 0 && t.Stop() {
|
||||
h.logPattern(ind)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *errorHandler) stop() {
|
||||
atomic.StoreUint32(&h.stopFlag, 1)
|
||||
for i := range h.patterns {
|
||||
t := h.patterns[i].timer()
|
||||
if t != nil && t.Stop() {
|
||||
h.logPattern(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (h errorHandler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
func (h *errorHandler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
rcode, err := plugin.NextOrFailure(h.Name(), h.Next, ctx, w, r)
|
||||
|
||||
if err != nil {
|
||||
strErr := err.Error()
|
||||
for i := range h.patterns {
|
||||
if h.patterns[i].pattern.MatchString(strErr) {
|
||||
if h.inc(i) {
|
||||
return rcode, err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
state := request.Request{W: w, Req: r}
|
||||
clog.Errorf("%d %s %s: %v", rcode, state.Name(), state.Type(), err)
|
||||
h.eLogger(rcode, state.Name(), state.Type(), strErr)
|
||||
}
|
||||
|
||||
return rcode, err
|
||||
}
|
||||
|
||||
func (h errorHandler) Name() string { return "errors" }
|
||||
// Name implements the plugin.Handler interface.
|
||||
func (h *errorHandler) Name() string { return "errors" }
|
||||
|
||||
Reference in New Issue
Block a user