pkg/log: fix data race on d (#2698)

* pkg/log: fix data race on d

Wrap d in a mutex to prevent data race. This makes is slower, but this
is a debugging aid anyway. It's not used normally.

Signed-off-by: Miek Gieben <miek@miek.nl>

* Fix tests compilation

Signed-off-by: Miek Gieben <miek@miek.nl>

* Fix test compile

Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
Miek Gieben 2019-05-23 21:02:30 +01:00 committed by GitHub
parent 118b0c9408
commit a84413bd07
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 26 deletions

View file

@ -62,7 +62,7 @@ func NewServer(addr string, group []*Config) (*Server, error) {
for _, site := range group { for _, site := range group {
if site.Debug { if site.Debug {
s.debug = true s.debug = true
log.D = true log.D.Set()
} }
// set the config per zone // set the config per zone
s.zones[site.Zone] = site s.zones[site.Zone] = site

View file

@ -23,7 +23,7 @@ import (
// //
// msg will prefix the pcap dump. // msg will prefix the pcap dump.
func Hexdump(m *dns.Msg, v ...interface{}) { func Hexdump(m *dns.Msg, v ...interface{}) {
if !log.D { if !log.D.Value() {
return return
} }
@ -39,7 +39,7 @@ func Hexdump(m *dns.Msg, v ...interface{}) {
// Hexdumpf dumps a DNS message as Hexdump, but allows a format string. // Hexdumpf dumps a DNS message as Hexdump, but allows a format string.
func Hexdumpf(m *dns.Msg, format string, v ...interface{}) { func Hexdumpf(m *dns.Msg, format string, v ...interface{}) {
if !log.D { if !log.D.Value() {
return return
} }

View file

@ -17,10 +17,21 @@ func msg() *dns.Msg {
m.SetQuestion("example.local.", dns.TypeA) m.SetQuestion("example.local.", dns.TypeA)
m.SetEdns0(4096, true) m.SetEdns0(4096, true)
m.Id = 10 m.Id = 10
return m return m
} }
func TestNoDebug(t *testing.T) {
// Must come first, because set log.D.Set() which is impossible to undo.
var f bytes.Buffer
golog.SetOutput(&f)
str := "Hi There!"
Hexdumpf(msg(), "%s %d", str, 10)
if len(f.Bytes()) != 0 {
t.Errorf("Expected no output, got %d bytes", len(f.Bytes()))
}
}
func ExampleLogHexdump() { func ExampleLogHexdump() {
buf, _ := msg().Pack() buf, _ := msg().Pack()
h := hexdump(buf) h := hexdump(buf)
@ -36,7 +47,7 @@ func ExampleLogHexdump() {
func TestHexdump(t *testing.T) { func TestHexdump(t *testing.T) {
var f bytes.Buffer var f bytes.Buffer
golog.SetOutput(&f) golog.SetOutput(&f)
log.D = true log.D.Set()
str := "Hi There!" str := "Hi There!"
Hexdump(msg(), str) Hexdump(msg(), str)
@ -50,7 +61,7 @@ func TestHexdump(t *testing.T) {
func TestHexdumpf(t *testing.T) { func TestHexdumpf(t *testing.T) {
var f bytes.Buffer var f bytes.Buffer
golog.SetOutput(&f) golog.SetOutput(&f)
log.D = true log.D.Set()
str := "Hi There!" str := "Hi There!"
Hexdumpf(msg(), "%s %d", str, 10) Hexdumpf(msg(), "%s %d", str, 10)
@ -60,15 +71,3 @@ func TestHexdumpf(t *testing.T) {
t.Errorf("The string %s %d, is not contained in the logged output: %s", str, 10, logged) t.Errorf("The string %s %d, is not contained in the logged output: %s", str, 10, logged)
} }
} }
func TestNoDebug(t *testing.T) {
var f bytes.Buffer
golog.SetOutput(&f)
log.D = false
str := "Hi There!"
Hexdumpf(msg(), "%s %d", str, 10)
if len(f.Bytes()) != 0 {
t.Errorf("Expected no output, got %d bytes", len(f.Bytes()))
}
}

View file

@ -13,11 +13,33 @@ import (
"io/ioutil" "io/ioutil"
golog "log" golog "log"
"os" "os"
"sync"
"time" "time"
) )
// D controls whether we should output debug logs. If true, we do. // D controls whether we should output debug logs. If true, we do, once set
var D bool // it can not be unset.
var D = &d{}
type d struct {
on bool
sync.RWMutex
}
// Set sets d to true.
func (d *d) Set() {
d.Lock()
d.on = true
d.Unlock()
}
// Value return the boolean value of d.
func (d *d) Value() bool {
d.RLock()
b := d.on
d.RUnlock()
return b
}
// RFC3339Milli doesn't exist, invent it here. // RFC3339Milli doesn't exist, invent it here.
func clock() string { return time.Now().Format("2006-01-02T15:04:05.000Z07:00") } func clock() string { return time.Now().Format("2006-01-02T15:04:05.000Z07:00") }
@ -35,7 +57,7 @@ func log(level string, v ...interface{}) {
// Debug is equivalent to log.Print(), but prefixed with "[DEBUG] ". It only outputs something // Debug is equivalent to log.Print(), but prefixed with "[DEBUG] ". It only outputs something
// if D is true. // if D is true.
func Debug(v ...interface{}) { func Debug(v ...interface{}) {
if !D { if !D.Value() {
return return
} }
log(debug, v...) log(debug, v...)
@ -44,7 +66,7 @@ func Debug(v ...interface{}) {
// Debugf is equivalent to log.Printf(), but prefixed with "[DEBUG] ". It only outputs something // Debugf is equivalent to log.Printf(), but prefixed with "[DEBUG] ". It only outputs something
// if D is true. // if D is true.
func Debugf(format string, v ...interface{}) { func Debugf(format string, v ...interface{}) {
if !D { if !D.Value() {
return return
} }
logf(debug, format, v...) logf(debug, format, v...)

View file

@ -18,7 +18,7 @@ func TestDebug(t *testing.T) {
} }
f.Reset() f.Reset()
D = true D.Set()
Debug("debug") Debug("debug")
if x := f.String(); !strings.Contains(x, debug+"debug") { if x := f.String(); !strings.Contains(x, debug+"debug") {
t.Errorf("Expected debug log to be %s, got %s", debug+"debug", x) t.Errorf("Expected debug log to be %s, got %s", debug+"debug", x)
@ -29,7 +29,7 @@ func TestDebugx(t *testing.T) {
var f bytes.Buffer var f bytes.Buffer
golog.SetOutput(&f) golog.SetOutput(&f)
D = true D.Set()
Debugf("%s", "debug") Debugf("%s", "debug")
if x := f.String(); !strings.Contains(x, debug+"debug") { if x := f.String(); !strings.Contains(x, debug+"debug") {

View file

@ -24,7 +24,7 @@ func (p P) log(level string, v ...interface{}) {
// Debug logs as log.Debug. // Debug logs as log.Debug.
func (p P) Debug(v ...interface{}) { func (p P) Debug(v ...interface{}) {
if !D { if !D.Value() {
return return
} }
p.log(debug, v...) p.log(debug, v...)
@ -32,7 +32,7 @@ func (p P) Debug(v ...interface{}) {
// Debugf logs as log.Debugf. // Debugf logs as log.Debugf.
func (p P) Debugf(format string, v ...interface{}) { func (p P) Debugf(format string, v ...interface{}) {
if !D { if !D.Value() {
return return
} }
p.logf(debug, format, v...) p.logf(debug, format, v...)