e113b276e7
Merge in DNS/adguard-home from 2504-querylog-ivl to master
Updates #2504.
Squashed commit of the following:
commit 5d15a6f735cd195fc81c8af909b56fbc7db1fe21
Merge: 8cd5c30d 97073d0d
Author: Eugene Burkov <e.burkov@adguard.com>
Date: Thu Jul 1 18:45:10 2021 +0300
Merge branch 'master' into 2504-querylog-ivl
commit 8cd5c30de6f72d4b12162dbc9e3d90132795fe94
Author: Eugene Burkov <e.burkov@adguard.com>
Date: Thu Jul 1 18:35:50 2021 +0300
client: fix fmt
commit e95d462c31d886bacec0735acc567fec7c962149
Author: Eugene Burkov <e.burkov@adguard.com>
Date: Thu Jul 1 17:58:06 2021 +0300
home: imp code
commit 48737b249c52a997a4f34dac45fbaf699477b007
Author: Eugene Burkov <e.burkov@adguard.com>
Date: Thu Jul 1 17:23:18 2021 +0300
home: imp duration
commit 44f5dc3d3ada5120d74caa24cace9a253b8f15d3
Author: Eugene Burkov <e.burkov@adguard.com>
Date: Thu Jul 1 16:55:31 2021 +0300
home: imp code, docs
commit bb2826521b7e5d248ce2ab686528219c312b8ba2
Author: Eugene Burkov <e.burkov@adguard.com>
Date: Thu Jul 1 16:11:40 2021 +0300
all: imp code, docs
commit d688aed1f340807a8bac8807c263956b0fc16f5b
Author: Eugene Burkov <e.burkov@adguard.com>
Date: Thu Jul 1 13:49:42 2021 +0300
all: change querylog interval setting format
156 lines
3.2 KiB
Go
156 lines
3.2 KiB
Go
package querylog
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/golibs/errors"
|
|
"github.com/AdguardTeam/golibs/log"
|
|
)
|
|
|
|
// flushLogBuffer flushes the current buffer to file and resets the current buffer
|
|
func (l *queryLog) flushLogBuffer(fullFlush bool) error {
|
|
if !l.conf.FileEnabled {
|
|
return nil
|
|
}
|
|
|
|
l.fileFlushLock.Lock()
|
|
defer l.fileFlushLock.Unlock()
|
|
|
|
// flush remainder to file
|
|
l.bufferLock.Lock()
|
|
needFlush := len(l.buffer) >= int(l.conf.MemSize)
|
|
if !needFlush && !fullFlush {
|
|
l.bufferLock.Unlock()
|
|
return nil
|
|
}
|
|
flushBuffer := l.buffer
|
|
l.buffer = nil
|
|
l.flushPending = false
|
|
l.bufferLock.Unlock()
|
|
err := l.flushToFile(flushBuffer)
|
|
if err != nil {
|
|
log.Error("Saving querylog to file failed: %s", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// flushToFile saves the specified log entries to the query log file
|
|
func (l *queryLog) flushToFile(buffer []*logEntry) (err error) {
|
|
if len(buffer) == 0 {
|
|
log.Debug("querylog: there's nothing to write to a file")
|
|
return nil
|
|
}
|
|
start := time.Now()
|
|
|
|
var b bytes.Buffer
|
|
e := json.NewEncoder(&b)
|
|
for _, entry := range buffer {
|
|
err = e.Encode(entry)
|
|
if err != nil {
|
|
log.Error("Failed to marshal entry: %s", err)
|
|
|
|
return err
|
|
}
|
|
}
|
|
|
|
elapsed := time.Since(start)
|
|
log.Debug("%d elements serialized via json in %v: %d kB, %v/entry, %v/entry", len(buffer), elapsed, b.Len()/1024, float64(b.Len())/float64(len(buffer)), elapsed/time.Duration(len(buffer)))
|
|
|
|
var zb bytes.Buffer
|
|
filename := l.logFile
|
|
zb = b
|
|
|
|
l.fileWriteLock.Lock()
|
|
defer l.fileWriteLock.Unlock()
|
|
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
|
|
if err != nil {
|
|
log.Error("failed to create file \"%s\": %s", filename, err)
|
|
return err
|
|
}
|
|
defer func() { err = errors.WithDeferred(err, f.Close()) }()
|
|
|
|
n, err := f.Write(zb.Bytes())
|
|
if err != nil {
|
|
log.Error("Couldn't write to file: %s", err)
|
|
return err
|
|
}
|
|
|
|
log.Debug("querylog: ok \"%s\": %v bytes written", filename, n)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (l *queryLog) rotate() error {
|
|
from := l.logFile
|
|
to := l.logFile + ".1"
|
|
|
|
err := os.Rename(from, to)
|
|
if err != nil {
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return nil
|
|
}
|
|
|
|
log.Error("querylog: failed to rename file: %s", err)
|
|
|
|
return err
|
|
}
|
|
|
|
log.Debug("querylog: renamed %s -> %s", from, to)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (l *queryLog) readFileFirstTimeValue() (first time.Time, err error) {
|
|
var f *os.File
|
|
f, err = os.Open(l.logFile)
|
|
if err != nil {
|
|
return time.Time{}, err
|
|
}
|
|
|
|
defer func() { err = errors.WithDeferred(err, f.Close()) }()
|
|
|
|
buf := make([]byte, 512)
|
|
var r int
|
|
r, err = f.Read(buf)
|
|
if err != nil {
|
|
return time.Time{}, err
|
|
}
|
|
|
|
val := readJSONValue(string(buf[:r]), `"T":"`)
|
|
t, err := time.Parse(time.RFC3339Nano, val)
|
|
if err != nil {
|
|
return time.Time{}, err
|
|
}
|
|
|
|
log.Debug("querylog: the oldest log entry: %s", val)
|
|
|
|
return t, nil
|
|
}
|
|
|
|
func (l *queryLog) periodicRotate() {
|
|
defer log.OnPanic("querylog: rotating")
|
|
|
|
var err error
|
|
for {
|
|
var oldest time.Time
|
|
oldest, err = l.readFileFirstTimeValue()
|
|
if err != nil {
|
|
log.Debug("%s", err)
|
|
}
|
|
|
|
if oldest.Add(l.conf.RotationIvl).After(time.Now()) {
|
|
err = l.rotate()
|
|
if err != nil {
|
|
log.Debug("%s", err)
|
|
}
|
|
}
|
|
|
|
// What?
|
|
time.Sleep(24 * time.Hour)
|
|
}
|
|
}
|