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:
Miek Gieben
2018-05-10 03:04:46 +01:00
committed by Yong Tang
parent 5e7c399117
commit 874a998697
4 changed files with 16 additions and 76 deletions

View File

@@ -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"

View File

@@ -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,
}, },
} }

View File

@@ -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()
} }

View File

@@ -8,31 +8,26 @@ import (
func TestErrorsParse(t *testing.T) { 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)
}
} }
} }