mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-30 17:53:21 -04:00 
			
		
		
		
	plugin/errors: remove panic/recover (#1777)
Remove panic/recover and also use pkg/log to print the error. This brings some consistency into the logging. Fixes #1776
This commit is contained in:
		| @@ -3,77 +3,27 @@ package errors | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" |  | ||||||
| 	"log" |  | ||||||
| 	"runtime" |  | ||||||
| 	"strings" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/coredns/coredns/plugin" | 	"github.com/coredns/coredns/plugin" | ||||||
|  | 	clog "github.com/coredns/coredns/plugin/pkg/log" | ||||||
| 	"github.com/coredns/coredns/request" | 	"github.com/coredns/coredns/request" | ||||||
|  |  | ||||||
| 	"github.com/miekg/dns" | 	"github.com/miekg/dns" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // errorHandler handles DNS errors (and errors from other plugin). | // errorHandler handles DNS errors (and errors from other plugin). | ||||||
| type errorHandler struct { | type errorHandler struct{ Next plugin.Handler } | ||||||
| 	Next    plugin.Handler |  | ||||||
| 	LogFile string |  | ||||||
| 	Log     *log.Logger |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ServeDNS implements the plugin.Handler interface. | // 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) { | ||||||
| 	defer h.recovery(ctx, w, r) |  | ||||||
|  |  | ||||||
| 	rcode, err := plugin.NextOrFailure(h.Name(), h.Next, ctx, w, r) | 	rcode, err := plugin.NextOrFailure(h.Name(), h.Next, ctx, w, r) | ||||||
|  |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		state := request.Request{W: w, Req: r} | 		state := request.Request{W: w, Req: r} | ||||||
| 		errMsg := fmt.Sprintf("%s [ERROR %d %s %s] %v", time.Now().Format(timeFormat), rcode, state.Name(), state.Type(), err) | 		clog.Errorf("%d %s %s: %v", rcode, state.Name(), state.Type(), err) | ||||||
|  |  | ||||||
| 		h.Log.Println(errMsg) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return rcode, err | 	return rcode, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (h errorHandler) Name() string { return "errors" } | func (h errorHandler) Name() string { return "errors" } | ||||||
|  |  | ||||||
| func (h errorHandler) recovery(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) { |  | ||||||
| 	rec := recover() |  | ||||||
| 	if rec == nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Obtain source of panic |  | ||||||
| 	// From: https://gist.github.com/swdunlop/9629168 |  | ||||||
| 	var name, file string // function name, file name |  | ||||||
| 	var line int |  | ||||||
| 	var pc [16]uintptr |  | ||||||
| 	n := runtime.Callers(3, pc[:]) |  | ||||||
| 	for _, pc := range pc[:n] { |  | ||||||
| 		fn := runtime.FuncForPC(pc) |  | ||||||
| 		if fn == nil { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		file, line = fn.FileLine(pc) |  | ||||||
| 		name = fn.Name() |  | ||||||
| 		if !strings.HasPrefix(name, "runtime.") { |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Trim file path |  | ||||||
| 	delim := "/coredns/" |  | ||||||
| 	pkgPathPos := strings.Index(file, delim) |  | ||||||
| 	if pkgPathPos > -1 && len(file) > pkgPathPos+len(delim) { |  | ||||||
| 		file = file[pkgPathPos+len(delim):] |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	panicMsg := fmt.Sprintf("%s [PANIC %s %s] %s:%d - %v", time.Now().Format(timeFormat), r.Question[0].Name, dns.Type(r.Question[0].Qtype), file, line, rec) |  | ||||||
| 	// Currently we don't use the function name, since file:line is more conventional |  | ||||||
| 	h.Log.Printf(panicMsg) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const timeFormat = "02/Jan/2006:15:04:05 -0700" |  | ||||||
|   | |||||||
| @@ -18,7 +18,8 @@ import ( | |||||||
|  |  | ||||||
| func TestErrors(t *testing.T) { | func TestErrors(t *testing.T) { | ||||||
| 	buf := bytes.Buffer{} | 	buf := bytes.Buffer{} | ||||||
| 	em := errorHandler{Log: log.New(&buf, "", 0)} | 	log.SetOutput(&buf) | ||||||
|  | 	em := errorHandler{} | ||||||
|  |  | ||||||
| 	testErr := errors.New("test error") | 	testErr := errors.New("test error") | ||||||
| 	tests := []struct { | 	tests := []struct { | ||||||
| @@ -36,7 +37,7 @@ func TestErrors(t *testing.T) { | |||||||
| 		{ | 		{ | ||||||
| 			next:         genErrorHandler(dns.RcodeNotAuth, testErr), | 			next:         genErrorHandler(dns.RcodeNotAuth, testErr), | ||||||
| 			expectedCode: dns.RcodeNotAuth, | 			expectedCode: dns.RcodeNotAuth, | ||||||
| 			expectedLog:  fmt.Sprintf("[ERROR %d %s] %v\n", dns.RcodeNotAuth, "example.org. A", testErr), | 			expectedLog:  fmt.Sprintf("[ERROR] %d %s: %v\n", dns.RcodeNotAuth, "example.org. A", testErr), | ||||||
| 			expectedErr:  testErr, | 			expectedErr:  testErr, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -2,8 +2,6 @@ package errors | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log" |  | ||||||
| 	"os" |  | ||||||
|  |  | ||||||
| 	"github.com/coredns/coredns/core/dnsserver" | 	"github.com/coredns/coredns/core/dnsserver" | ||||||
| 	"github.com/coredns/coredns/plugin" | 	"github.com/coredns/coredns/plugin" | ||||||
| @@ -24,8 +22,6 @@ func setup(c *caddy.Controller) error { | |||||||
| 		return plugin.Error("errors", err) | 		return plugin.Error("errors", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	handler.Log = log.New(os.Stdout, "", 0) |  | ||||||
|  |  | ||||||
| 	dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler { | 	dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler { | ||||||
| 		handler.Next = next | 		handler.Next = next | ||||||
| 		return handler | 		return handler | ||||||
| @@ -47,12 +43,10 @@ func errorsParse(c *caddy.Controller) (errorHandler, error) { | |||||||
| 		args := c.RemainingArgs() | 		args := c.RemainingArgs() | ||||||
| 		switch len(args) { | 		switch len(args) { | ||||||
| 		case 0: | 		case 0: | ||||||
| 			handler.LogFile = "stdout" |  | ||||||
| 		case 1: | 		case 1: | ||||||
| 			if args[0] != "stdout" { | 			if args[0] != "stdout" { | ||||||
| 				return handler, fmt.Errorf("invalid log file: %s", args[0]) | 				return handler, fmt.Errorf("invalid log file: %s", args[0]) | ||||||
| 			} | 			} | ||||||
| 			handler.LogFile = args[0] |  | ||||||
| 		default: | 		default: | ||||||
| 			return handler, c.ArgErr() | 			return handler, c.ArgErr() | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -10,29 +10,24 @@ func TestErrorsParse(t *testing.T) { | |||||||
| 	tests := []struct { | 	tests := []struct { | ||||||
| 		inputErrorsRules string | 		inputErrorsRules string | ||||||
| 		shouldErr        bool | 		shouldErr        bool | ||||||
| 		expectedErrorHandler errorHandler |  | ||||||
| 	}{ | 	}{ | ||||||
| 		{`errors`, false, errorHandler{LogFile: "stdout"}}, | 		{`errors`, false}, | ||||||
| 		{`errors stdout`, false, errorHandler{LogFile: "stdout"}}, | 		{`errors stdout`, false}, | ||||||
| 		{`errors errors.txt`, true, errorHandler{LogFile: ""}}, | 		{`errors errors.txt`, true}, | ||||||
| 		{`errors visible`, true, errorHandler{LogFile: ""}}, | 		{`errors visible`, true}, | ||||||
| 		{`errors { log visible }`, true, errorHandler{LogFile: "stdout"}}, | 		{`errors { log visible }`, true}, | ||||||
| 		{`errors | 		{`errors | ||||||
| 		errors `, true, errorHandler{LogFile: "stdout"}}, | 		errors `, true}, | ||||||
| 		{`errors a b`, true, errorHandler{LogFile: ""}}, | 		{`errors a b`, true}, | ||||||
| 	} | 	} | ||||||
| 	for i, test := range tests { | 	for i, test := range tests { | ||||||
| 		c := caddy.NewTestController("dns", test.inputErrorsRules) | 		c := caddy.NewTestController("dns", test.inputErrorsRules) | ||||||
| 		actualErrorsRule, err := errorsParse(c) | 		_, err := errorsParse(c) | ||||||
|  |  | ||||||
| 		if err == nil && test.shouldErr { | 		if err == nil && test.shouldErr { | ||||||
| 			t.Errorf("Test %d didn't error, but it should have", i) | 			t.Errorf("Test %d didn't error, but it should have", i) | ||||||
| 		} else if err != nil && !test.shouldErr { | 		} else if err != nil && !test.shouldErr { | ||||||
| 			t.Errorf("Test %d errored, but it shouldn't have; got '%v'", i, err) | 			t.Errorf("Test %d errored, but it shouldn't have; got '%v'", i, err) | ||||||
| 		} | 		} | ||||||
| 		if actualErrorsRule.LogFile != test.expectedErrorHandler.LogFile { |  | ||||||
| 			t.Errorf("Test %d expected LogFile to be %s, but got %s", |  | ||||||
| 				i, test.expectedErrorHandler.LogFile, actualErrorsRule.LogFile) |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user