2019-08-26 11:54:38 +03:00
package querylog
2018-12-05 14:03:41 +03:00
import (
"bytes"
"encoding/json"
"os"
"time"
2019-02-25 16:44:22 +03:00
"github.com/AdguardTeam/golibs/log"
2018-12-05 14:03:41 +03:00
)
2019-02-11 14:22:36 +03:00
// flushLogBuffer flushes the current buffer to file and resets the current buffer
2019-05-15 13:11:36 +03:00
func ( l * queryLog ) flushLogBuffer ( fullFlush bool ) error {
l . fileFlushLock . Lock ( )
defer l . fileFlushLock . Unlock ( )
2019-02-10 20:47:43 +03:00
// flush remainder to file
2019-09-27 18:58:57 +03:00
l . bufferLock . Lock ( )
2019-11-08 12:31:50 +03:00
needFlush := len ( l . buffer ) >= int ( l . conf . MemSize )
2019-05-15 13:11:36 +03:00
if ! needFlush && ! fullFlush {
2019-09-27 18:58:57 +03:00
l . bufferLock . Unlock ( )
2019-05-15 13:11:36 +03:00
return nil
}
2019-09-27 18:58:57 +03:00
flushBuffer := l . buffer
l . buffer = nil
2019-05-15 13:11:36 +03:00
l . flushPending = false
2019-09-27 18:58:57 +03:00
l . bufferLock . Unlock ( )
2019-02-10 20:47:43 +03:00
err := l . flushToFile ( flushBuffer )
if err != nil {
2019-02-25 16:44:22 +03:00
log . Error ( "Saving querylog to file failed: %s" , err )
2019-02-10 20:47:43 +03:00
return err
}
return nil
}
// flushToFile saves the specified log entries to the query log file
func ( l * queryLog ) flushToFile ( buffer [ ] * logEntry ) error {
2018-12-05 14:03:41 +03:00
if len ( buffer ) == 0 {
2019-05-08 10:43:47 +03:00
log . Debug ( "querylog: there's nothing to write to a file" )
2018-12-05 14:03:41 +03:00
return nil
}
start := time . Now ( )
var b bytes . Buffer
e := json . NewEncoder ( & b )
for _ , entry := range buffer {
err := e . Encode ( entry )
if err != nil {
2019-02-25 16:44:22 +03:00
log . Error ( "Failed to marshal entry: %s" , err )
2018-12-05 14:03:41 +03:00
return err
}
}
elapsed := time . Since ( start )
2019-02-25 16:44:22 +03:00
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 ) ) )
2018-12-05 14:03:41 +03:00
2019-10-24 14:19:13 +03:00
var err error
2018-12-05 14:03:41 +03:00
var zb bytes . Buffer
2019-02-10 20:47:43 +03:00
filename := l . logFile
2020-02-20 21:12:51 +03:00
zb = b
2018-12-05 14:03:41 +03:00
2019-09-27 18:58:57 +03:00
l . fileWriteLock . Lock ( )
defer l . fileWriteLock . Unlock ( )
2018-12-05 14:03:41 +03:00
f , err := os . OpenFile ( filename , os . O_WRONLY | os . O_CREATE | os . O_APPEND , 0644 )
if err != nil {
2019-02-25 16:44:22 +03:00
log . Error ( "failed to create file \"%s\": %s" , filename , err )
2018-12-05 14:03:41 +03:00
return err
}
defer f . Close ( )
n , err := f . Write ( zb . Bytes ( ) )
if err != nil {
2019-02-25 16:44:22 +03:00
log . Error ( "Couldn't write to file: %s" , err )
2018-12-05 14:03:41 +03:00
return err
}
2019-02-25 16:44:22 +03:00
log . Debug ( "ok \"%s\": %v bytes written" , filename , n )
2018-12-05 14:03:41 +03:00
return nil
}
2019-09-27 18:58:57 +03:00
func ( l * queryLog ) rotate ( ) error {
2019-02-10 20:47:43 +03:00
from := l . logFile
to := l . logFile + ".1"
2018-12-05 14:03:41 +03:00
if _ , err := os . Stat ( from ) ; os . IsNotExist ( err ) {
// do nothing, file doesn't exist
return nil
}
err := os . Rename ( from , to )
if err != nil {
2019-02-25 16:44:22 +03:00
log . Error ( "Failed to rename querylog: %s" , err )
2018-12-05 14:03:41 +03:00
return err
}
2019-02-25 16:44:22 +03:00
log . Debug ( "Rotated from %s to %s successfully" , from , to )
2018-12-05 14:03:41 +03:00
return nil
}
2019-09-27 18:58:57 +03:00
func ( l * queryLog ) periodicRotate ( ) {
for range time . Tick ( time . Duration ( l . conf . Interval ) * 24 * time . Hour ) {
err := l . rotate ( )
2018-12-05 14:03:41 +03:00
if err != nil {
2019-02-25 16:44:22 +03:00
log . Error ( "Failed to rotate querylog: %s" , err )
2018-12-05 14:03:41 +03:00
// do nothing, continue rotating
}
}
}