Merge: dns query log: robust file flushing mechanism #708

* commit 'd5f6dd1a46446ebb440811691a6ee8ce2443320d':
  - dns query log: robust file flushing mechanism
  * improve logging
This commit is contained in:
Simon Zolin 2019-05-15 14:08:01 +03:00
commit 7bb40bca0f
4 changed files with 23 additions and 13 deletions

1
app.go
View File

@ -372,6 +372,7 @@ func cleanupAlways() {
if len(pidFileName) != 0 { if len(pidFileName) != 0 {
os.Remove(pidFileName) os.Remove(pidFileName)
} }
log.Info("Stopped")
} }
// command-line arguments // command-line arguments

View File

@ -236,7 +236,7 @@ func (s *Server) stopInternal() error {
} }
// flush remainder to file // flush remainder to file
return s.queryLog.flushLogBuffer() return s.queryLog.flushLogBuffer(true)
} }
// IsRunning returns true if the DNS server is running // IsRunning returns true if the DNS server is running

View File

@ -30,6 +30,8 @@ type queryLog struct {
logBufferLock sync.RWMutex logBufferLock sync.RWMutex
logBuffer []*logEntry logBuffer []*logEntry
fileFlushLock sync.Mutex // synchronize a file-flushing goroutine and main thread
flushPending bool // don't start another goroutine while the previous one is still running
queryLogCache []*logEntry queryLogCache []*logEntry
queryLogLock sync.RWMutex queryLogLock sync.RWMutex
@ -91,13 +93,15 @@ func (l *queryLog) logRequest(question *dns.Msg, answer *dns.Msg, result *dnsfil
IP: ip, IP: ip,
Upstream: upstream, Upstream: upstream,
} }
var flushBuffer []*logEntry
l.logBufferLock.Lock() l.logBufferLock.Lock()
l.logBuffer = append(l.logBuffer, &entry) l.logBuffer = append(l.logBuffer, &entry)
if len(l.logBuffer) >= logBufferCap { needFlush := false
flushBuffer = l.logBuffer if !l.flushPending {
l.logBuffer = nil needFlush = len(l.logBuffer) >= logBufferCap
if needFlush {
l.flushPending = true
}
} }
l.logBufferLock.Unlock() l.logBufferLock.Unlock()
l.queryLogLock.Lock() l.queryLogLock.Lock()
@ -116,15 +120,10 @@ func (l *queryLog) logRequest(question *dns.Msg, answer *dns.Msg, result *dnsfil
} }
// if buffer needs to be flushed to disk, do it now // if buffer needs to be flushed to disk, do it now
if len(flushBuffer) > 0 { if needFlush {
// write to file // write to file
// do it in separate goroutine -- we are stalling DNS response this whole time // do it in separate goroutine -- we are stalling DNS response this whole time
go func() { go l.flushLogBuffer(false)
err := l.flushToFile(flushBuffer)
if err != nil {
log.Printf("Failed to flush the query log: %s", err)
}
}()
} }
return &entry return &entry

View File

@ -20,11 +20,20 @@ var (
const enableGzip = false const enableGzip = false
// flushLogBuffer flushes the current buffer to file and resets the current buffer // flushLogBuffer flushes the current buffer to file and resets the current buffer
func (l *queryLog) flushLogBuffer() error { func (l *queryLog) flushLogBuffer(fullFlush bool) error {
l.fileFlushLock.Lock()
defer l.fileFlushLock.Unlock()
// flush remainder to file // flush remainder to file
l.logBufferLock.Lock() l.logBufferLock.Lock()
needFlush := len(l.logBuffer) >= logBufferCap
if !needFlush && !fullFlush {
l.logBufferLock.Unlock()
return nil
}
flushBuffer := l.logBuffer flushBuffer := l.logBuffer
l.logBuffer = nil l.logBuffer = nil
l.flushPending = false
l.logBufferLock.Unlock() l.logBufferLock.Unlock()
err := l.flushToFile(flushBuffer) err := l.flushToFile(flushBuffer)
if err != nil { if err != nil {
@ -37,6 +46,7 @@ func (l *queryLog) flushLogBuffer() error {
// flushToFile saves the specified log entries to the query log file // flushToFile saves the specified log entries to the query log file
func (l *queryLog) flushToFile(buffer []*logEntry) error { func (l *queryLog) flushToFile(buffer []*logEntry) error {
if len(buffer) == 0 { if len(buffer) == 0 {
log.Debug("querylog: there's nothing to write to a file")
return nil return nil
} }
start := time.Now() start := time.Now()