mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 10:13:14 -04: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
						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