Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

log: added option to rotate logs based on number of hours with a maximum of 24 #1735

Merged
merged 3 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 25 additions & 15 deletions log/async_file_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,43 @@ import (
"time"
)

type HourTicker struct {
type TimeTicker struct {
stop chan struct{}
C <-chan time.Time
}

func NewHourTicker() *HourTicker {
ht := &HourTicker{
// NewTimeTicker notifies on a daily basis if dailyRotate is true, otherwise on an hourly basis
func NewTimeTicker(dailyRotate bool) *TimeTicker {
ch := make(chan time.Time)
ht := TimeTicker{
bnb-alexlucaci marked this conversation as resolved.
Show resolved Hide resolved
stop: make(chan struct{}),
C: ch,
}
ht.C = ht.Ticker()
return ht

ht.startTicker(ch, dailyRotate)

return &ht
}

func (ht *HourTicker) Stop() {
func (ht *TimeTicker) Stop() {
ht.stop <- struct{}{}
}

func (ht *HourTicker) Ticker() <-chan time.Time {
ch := make(chan time.Time)
func (ht *TimeTicker) startTicker(ch chan time.Time, dailyRotate bool) {
go func() {
day := time.Now().Day()
hour := time.Now().Hour()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case t := <-ticker.C:
if dailyRotate && t.Day() != day {
ch <- t
day = t.Day()
continue
}

if t.Hour() != hour {
ch <- t
hour = t.Hour()
Expand All @@ -45,7 +56,6 @@ func (ht *HourTicker) Ticker() <-chan time.Time {
}
}
}()
return ch
}

type AsyncFileWriter struct {
Expand All @@ -56,20 +66,20 @@ type AsyncFileWriter struct {
started int32
buf chan []byte
stop chan struct{}
hourTicker *HourTicker
timeTicker *TimeTicker
}

func NewAsyncFileWriter(filePath string, bufSize int64) *AsyncFileWriter {
func NewAsyncFileWriter(filePath string, maxBytesSize int64, dailyRotate bool) *AsyncFileWriter {
absFilePath, err := filepath.Abs(filePath)
if err != nil {
panic(fmt.Sprintf("get file path of logger error. filePath=%s, err=%s", filePath, err))
}

return &AsyncFileWriter{
filePath: absFilePath,
buf: make(chan []byte, bufSize),
buf: make(chan []byte, maxBytesSize),
stop: make(chan struct{}),
hourTicker: NewHourTicker(),
timeTicker: NewTimeTicker(dailyRotate),
}
}

Expand Down Expand Up @@ -159,7 +169,7 @@ func (w *AsyncFileWriter) SyncWrite(msg []byte) {

func (w *AsyncFileWriter) rotateFile() {
select {
case <-w.hourTicker.C:
case <-w.timeTicker.C:
if err := w.flushAndClose(); err != nil {
fmt.Fprintf(os.Stderr, "flush and close file error. err=%s", err)
}
Expand All @@ -174,7 +184,7 @@ func (w *AsyncFileWriter) Stop() {
w.stop <- struct{}{}
w.wg.Wait()

w.hourTicker.Stop()
w.timeTicker.Stop()
}

func (w *AsyncFileWriter) Write(msg []byte) (n int, err error) {
Expand Down
27 changes: 22 additions & 5 deletions log/async_file_writer_test.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
package log

import (
"io/ioutil"
"os"
"strings"
"testing"
)

func TestWriter(t *testing.T) {
w := NewAsyncFileWriter("./hello.log", 100)
func TestWriterHourly(t *testing.T) {
w := NewAsyncFileWriter("./hello.log", 100, false)
w.Start()
w.Write([]byte("hello\n"))
w.Write([]byte("world\n"))
w.Stop()
files, _ := ioutil.ReadDir("./")
files, _ := os.ReadDir("./")
Mister-EA marked this conversation as resolved.
Show resolved Hide resolved
for _, f := range files {
fn := f.Name()
if strings.HasPrefix(fn, "hello") {
t.Log(fn)
content, _ := ioutil.ReadFile(fn)
content, _ := os.ReadFile(fn)
t.Log(content)
os.Remove(fn)
}
}
}

func TestWriterDaily(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think these tests cases test if the ticker logic is correct - they only check that something was written to the log file. Can you think of a way to test the rotation logic? (I am thinking a more generic implementation with a variable rotation interval also has advantages in terms of ease of testing this logic).

w := NewAsyncFileWriter("./hello.log", 100, true)
w.Start()
w.Write([]byte("hello\n"))
w.Write([]byte("world\n"))
w.Stop()
files, _ := os.ReadDir("./")
for _, f := range files {
fn := f.Name()
if strings.HasPrefix(fn, "hello") {
t.Log(fn)
content, _ := os.ReadFile(fn)
t.Log(content)
os.Remove(fn)
}
Expand Down
4 changes: 2 additions & 2 deletions log/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ func FileHandler(path string, fmtr Format) (Handler, error) {
// RotatingFileHandler returns a handler which writes log records to file chunks
// at the given path. When a file's size reaches the limit, the handler creates
// a new file named after the timestamp of the first log record it will contain.
func RotatingFileHandler(filePath string, limit uint, formatter Format) (Handler, error) {
func RotatingFileHandler(filePath string, limit uint, formatter Format, dailyRotate bool) (Handler, error) {
if _, err := os.Stat(path.Dir(filePath)); os.IsNotExist(err) {
err := os.MkdirAll(path.Dir(filePath), 0755)
if err != nil {
return nil, fmt.Errorf("could not create directory %s, %v", path.Dir(filePath), err)
}
}
fileWriter := NewAsyncFileWriter(filePath, int64(limit))
fileWriter := NewAsyncFileWriter(filePath, int64(limit), dailyRotate)
fileWriter.Start()
return StreamHandler(fileWriter, formatter), nil
}
Expand Down
8 changes: 2 additions & 6 deletions log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,12 +244,8 @@ func (c Ctx) toArray() []interface{} {
return arr
}

func NewFileLvlHandler(logPath string, maxBytesSize uint, level string) Handler {
rfh, err := RotatingFileHandler(
logPath,
maxBytesSize,
LogfmtFormat(),
)
func NewFileLvlHandler(logPath string, maxBytesSize uint, level string, dailyRotate bool) Handler {
rfh, err := RotatingFileHandler(logPath, maxBytesSize, LogfmtFormat(), dailyRotate)
if err != nil {
panic(err)
}
Expand Down
1 change: 1 addition & 0 deletions node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ type LogConfig struct {
FilePath *string `toml:",omitempty"`
MaxBytesSize *uint `toml:",omitempty"`
Level *string `toml:",omitempty"`
DailyRotate bool `toml:",omitempty"`

// TermTimeFormat is the time format used for console logging.
TermTimeFormat *string `toml:",omitempty"`
Expand Down
3 changes: 2 additions & 1 deletion node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ func New(conf *Config) (*Node, error) {
} else {
logFilePath = path.Join(*conf.LogConfig.FileRoot, *conf.LogConfig.FilePath)
}
log.Root().SetHandler(log.NewFileLvlHandler(logFilePath, *conf.LogConfig.MaxBytesSize, *conf.LogConfig.Level))

log.Root().SetHandler(log.NewFileLvlHandler(logFilePath, *conf.LogConfig.MaxBytesSize, *conf.LogConfig.Level, conf.LogConfig.DailyRotate))
}
}
if conf.Logger == nil {
Expand Down
2 changes: 1 addition & 1 deletion signer/fourbyte/4byte.go
Original file line number Diff line number Diff line change
Expand Up @@ -43203,7 +43203,7 @@ var __4byteJson = []byte(`{
"4b3ec03a": "TEAM_ACCOUNT()",
"4b3f3987": "_updateLock(uint256,address)",
"4b419b5f": "setcardPrice(uint256,uint256)",
"4b41c74a": "Ticker()",
"4b41c74a": "startTicker()",
bnb-alexlucaci marked this conversation as resolved.
Show resolved Hide resolved
"4b41cb60": "withdrawPreSigned(address,uint256,address,uint256,uint256,address,uint8,bytes32,bytes32)",
"4b41eb4a": "ZyryanovKubSU2018()",
"4b41f4df": "transferableTime()",
Expand Down