mirror of
https://github.com/coredns/coredns.git
synced 2025-10-27 16:24:19 -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user