Skip to content
This repository was archived by the owner on Dec 20, 2024. It is now read-only.

Commit 63f099d

Browse files
inoc603lowzj
authored andcommitted
refactor: new api for dflog and output log to console by default
Signed-off-by: inoc603 <[email protected]>
1 parent 0c4dd8a commit 63f099d

File tree

8 files changed

+162
-279
lines changed

8 files changed

+162
-279
lines changed

cmd/dfdaemon/app/init.go

Lines changed: 7 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,11 @@ package app
1919
import (
2020
"bytes"
2121
"fmt"
22-
"io/ioutil"
23-
"log"
2422
"os"
2523
"os/exec"
2624
"os/user"
2725
"path/filepath"
2826
"runtime"
29-
"syscall"
3027
"time"
3128

3229
"github.com/dragonflyoss/Dragonfly/dfdaemon/config"
@@ -80,70 +77,18 @@ func initLogger(cfg config.Properties) error {
8077
return errors.Wrap(err, "get current user")
8178
}
8279

83-
// Set the log level here so the following line will be output normally
84-
// to the console, before setting the log file.
85-
if cfg.Verbose {
86-
logrus.SetLevel(logrus.DebugLevel)
87-
}
8880
logFilePath := filepath.Join(current.HomeDir, ".small-dragonfly/logs/dfdaemon.log")
89-
logrus.Debugf("use log file %s", logFilePath)
90-
91-
if err := dflog.InitLog(cfg.Verbose, logFilePath, fmt.Sprintf("%d", os.Getpid())); err != nil {
92-
return errors.Wrap(err, "init log file")
93-
}
94-
95-
logFile, ok := (logrus.StandardLogger().Out).(*os.File)
96-
if !ok {
97-
return nil
98-
}
99-
go func(logFile *os.File) {
100-
logrus.Infof("rotate %s every 60 seconds", logFilePath)
101-
ticker := time.NewTicker(60 * time.Second)
102-
for range ticker.C {
103-
if err := rotateLog(logFile); err != nil {
104-
logrus.Errorf("failed to rotate log %s: %v", logFile.Name(), err)
105-
}
106-
}
107-
}(logFile)
108-
109-
return nil
110-
}
111-
112-
// rotateLog truncates the logs file by a certain amount bytes.
113-
func rotateLog(logFile *os.File) error {
114-
fStat, err := logFile.Stat()
115-
if err != nil {
116-
return err
117-
}
118-
logSizeLimit := int64(20 * 1024 * 1024)
11981

120-
if fStat.Size() <= logSizeLimit {
121-
return nil
82+
opts := []dflog.Option{
83+
dflog.WithLogFile(logFilePath),
84+
dflog.WithSign(fmt.Sprintf("%d", os.Getpid())),
85+
dflog.WithDebug(cfg.Verbose),
86+
dflog.WithConsole(),
12287
}
12388

124-
// if it exceeds the 20MB limitation
125-
log.SetOutput(ioutil.Discard)
126-
// make sure set the output of log back to logFile when error be raised.
127-
defer log.SetOutput(logFile)
128-
logFile.Sync()
129-
truncateSize := logSizeLimit/2 - 1
130-
mem, err := syscall.Mmap(int(logFile.Fd()), 0, int(fStat.Size()),
131-
syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
132-
if err != nil {
133-
return err
134-
}
135-
copy(mem[0:], mem[truncateSize:])
136-
if err := syscall.Munmap(mem); err != nil {
137-
return err
138-
}
139-
if err := logFile.Truncate(fStat.Size() - truncateSize); err != nil {
140-
return err
141-
}
142-
if _, err := logFile.Seek(truncateSize, 0); err != nil {
143-
return err
144-
}
89+
logrus.Debugf("use log file %s", logFilePath)
14590

146-
return nil
91+
return errors.Wrap(dflog.Init(logrus.StandardLogger(), opts...), "init log")
14792
}
14893

14994
// cleanLocalRepo checks the files at local periodically, and delete the file when

cmd/dfget/app/root.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,18 @@ func transParams() error {
174174
func initClientLog() error {
175175
logFilePath := path.Join(cfg.WorkHome, "logs", "dfclient.log")
176176

177-
dflog.InitLog(cfg.Verbose, logFilePath, cfg.Sign)
177+
opts := []dflog.Option{
178+
dflog.WithLogFile(logFilePath),
179+
dflog.WithSign(cfg.Sign),
180+
dflog.WithDebug(cfg.Verbose),
181+
}
178182

179183
// once cfg.Console is set, process should also output log to console
180184
if cfg.Console {
181-
dflog.InitConsoleLog(cfg.Verbose, cfg.Sign)
185+
opts = append(opts, dflog.WithConsole())
182186
}
183-
return nil
187+
188+
return dflog.Init(logrus.StandardLogger(), opts...)
184189
}
185190

186191
func initFlags() {

cmd/dfget/app/server.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/dragonflyoss/Dragonfly/pkg/dflog"
2525
"github.com/dragonflyoss/Dragonfly/pkg/printer"
2626

27+
"github.com/sirupsen/logrus"
2728
"github.com/spf13/cobra"
2829
)
2930

@@ -77,5 +78,17 @@ func runServer() error {
7778

7879
func initServerLog() error {
7980
logFilePath := path.Join(cfg.WorkHome, "logs", "dfserver.log")
80-
return dflog.InitLog(cfg.Verbose, logFilePath, cfg.Sign)
81+
82+
opts := []dflog.Option{
83+
dflog.WithLogFile(logFilePath),
84+
dflog.WithSign(cfg.Sign),
85+
dflog.WithDebug(cfg.Verbose),
86+
}
87+
88+
// once cfg.Console is set, process should also output log to console
89+
if cfg.Console {
90+
opts = append(opts, dflog.WithConsole())
91+
}
92+
93+
return dflog.Init(logrus.StandardLogger(), opts...)
8194
}

cmd/supernode/app/root.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,17 @@ func runSuperNode() error {
147147

148148
// initLog initializes log Level and log format of daemon.
149149
func initLog() error {
150-
logPath := path.Join(options.HomeDir, "logs", "app.log")
151-
err := dflog.InitLog(options.Debug, logPath, fmt.Sprintf("%d", os.Getpid()))
152-
if err != nil {
153-
logrus.Errorf("failed to initialize logs: %v", err)
150+
logFilePath := path.Join(options.HomeDir, "logs", "app.log")
151+
152+
opts := []dflog.Option{
153+
dflog.WithLogFile(logFilePath),
154+
dflog.WithSign(fmt.Sprintf("%d", os.Getpid())),
155+
dflog.WithDebug(options.Debug),
154156
}
155-
return err
157+
158+
logrus.Debugf("use log file %s", logFilePath)
159+
160+
return errors.Wrap(dflog.Init(logrus.StandardLogger(), opts...), "init log")
156161
}
157162

158163
// initConfig load configuration from config file.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ require (
4141
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect
4242
gopkg.in/gcfg.v1 v1.2.3
4343
gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528 // indirect
44+
gopkg.in/natefinch/lumberjack.v2 v2.0.0
4445
gopkg.in/warnings.v0 v0.1.2
4546
gopkg.in/yaml.v2 v2.2.2
4647
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs=
215215
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
216216
gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528 h1:/saqWwm73dLmuzbNhe92F0QsZ/KiFND+esHco2v1hiY=
217217
gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
218+
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
219+
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
218220
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
219221
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
220222
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=

pkg/dflog/log.go

Lines changed: 80 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -20,113 +20,114 @@ import (
2020
"bytes"
2121
"fmt"
2222
"os"
23-
"path"
24-
"path/filepath"
2523
"strings"
2624

25+
"github.com/pkg/errors"
2726
"github.com/sirupsen/logrus"
27+
"gopkg.in/natefinch/lumberjack.v2"
2828
)
2929

3030
// DefaultLogTimeFormat defines the timestamp format.
3131
const DefaultLogTimeFormat = "2006-01-02 15:04:05.000"
3232

33-
// InitLog initializes the file logger for process.
34-
// logfile is used to stored generated log in local filesystem.
35-
func InitLog(debug bool, logFilePath string, sign string) error {
36-
// set the log level
37-
logLevel := logrus.InfoLevel
38-
if debug {
39-
logLevel = logrus.DebugLevel
40-
}
33+
// Option is a functional configuration for the given logrus logger
34+
type Option func(l *logrus.Logger) error
4135

42-
// create and log file
43-
if err := os.MkdirAll(filepath.Dir(logFilePath), 0755); err != nil {
44-
return fmt.Errorf("failed to create log file %s: %v", logFilePath, err)
45-
}
46-
logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
47-
if err != nil {
48-
return err
36+
// WithDebug sets the log level to debug
37+
func WithDebug(debug bool) Option {
38+
return func(l *logrus.Logger) error {
39+
if debug {
40+
l.SetLevel(logrus.DebugLevel)
41+
}
42+
return nil
4943
}
50-
logFile.Seek(0, 2)
44+
}
5145

52-
// create formatter for default log Logger
53-
formatter := &DragonflyFormatter{
54-
TimestampFormat: DefaultLogTimeFormat,
55-
Sign: sign,
46+
func getLumberjack(l *logrus.Logger) *lumberjack.Logger {
47+
if logger, ok := l.Out.(*lumberjack.Logger); ok {
48+
return logger
5649
}
57-
58-
// set all details in log default logger
59-
logrus.SetLevel(logLevel)
60-
logrus.SetOutput(logFile)
61-
logrus.SetFormatter(formatter)
6250
return nil
6351
}
6452

65-
// InitConsoleLog initializes console logger for process.
66-
// console log will output the dfget client's log in console/terminal for
67-
// debugging usage.
68-
func InitConsoleLog(debug bool, sign string) {
69-
formatter := &DragonflyFormatter{
70-
TimestampFormat: DefaultLogTimeFormat,
71-
Sign: sign,
72-
}
53+
// WithLogFile sets the logger to output to the given file, with log rotation.
54+
// If the given file is empty, nothing will be done.
55+
func WithLogFile(f string) Option {
56+
return func(l *logrus.Logger) error {
57+
if f == "" {
58+
return nil
59+
}
7360

74-
logLevel := logrus.InfoLevel
75-
if debug {
76-
logLevel = logrus.DebugLevel
77-
}
61+
if logger := getLumberjack(l); logger == nil {
62+
l.SetOutput(&lumberjack.Logger{
63+
Filename: f,
64+
MaxSize: 20, // mb
65+
MaxBackups: 1,
66+
})
67+
} else {
68+
logger.Filename = f
69+
}
7870

79-
consoleLog := &logrus.Logger{
80-
Out: os.Stdout,
81-
Formatter: formatter,
82-
Hooks: make(logrus.LevelHooks),
83-
Level: logLevel,
71+
return nil
8472
}
85-
hook := &ConsoleHook{
86-
logger: consoleLog,
87-
levels: logrus.AllLevels,
88-
}
89-
logrus.AddHook(hook)
9073
}
9174

92-
// CreateLogger creates a Logger.
93-
func CreateLogger(logPath string, logName string, logLevel string, sign string) (*logrus.Logger, error) {
94-
// parse log level
95-
level, err := logrus.ParseLevel(logLevel)
96-
if err != nil {
97-
level = logrus.InfoLevel
75+
// WithMaxSizeMB sets the max size of log files in MB. If the logger is not configured
76+
// to use a log file, an error is returned.
77+
func WithMaxSizeMB(max uint) Option {
78+
return func(l *logrus.Logger) error {
79+
if logger := getLumberjack(l); logger != nil {
80+
logger.MaxSize = int(max)
81+
return nil
82+
}
83+
return errors.Errorf("lumberjack is not configured")
9884
}
85+
}
9986

100-
// create log file path
101-
logFilePath := path.Join(logPath, logName)
102-
if err := os.MkdirAll(filepath.Dir(logFilePath), 0755); err != nil {
103-
return nil, err
87+
// WithConsole add a hook to output logs to stdout
88+
func WithConsole() Option {
89+
return func(l *logrus.Logger) error {
90+
consoleLog := &logrus.Logger{
91+
Out: os.Stdout,
92+
Formatter: l.Formatter,
93+
Hooks: make(logrus.LevelHooks),
94+
Level: l.Level,
95+
}
96+
hook := &ConsoleHook{
97+
logger: consoleLog,
98+
levels: logrus.AllLevels,
99+
}
100+
l.AddHook(hook)
101+
return nil
104102
}
103+
}
105104

106-
// open log file
107-
logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
108-
if err != nil {
109-
return nil, err
105+
// WithSign sets the sign in formatter
106+
func WithSign(sign string) Option {
107+
return func(l *logrus.Logger) error {
108+
l.Formatter = &DragonflyFormatter{
109+
TimestampFormat: DefaultLogTimeFormat,
110+
Sign: sign,
111+
}
112+
return nil
110113
}
111-
112-
logFile.Seek(0, 2)
113-
Logger := logrus.New()
114-
Logger.Out = logFile
115-
Logger.Formatter = &DragonflyFormatter{TimestampFormat: DefaultLogTimeFormat, Sign: sign}
116-
Logger.Level = level
117-
return Logger, nil
118114
}
119115

120-
// AddConsoleLog will add a ConsoleLog into Logger's hooks.
121-
// It will output logs to console when Logger's outputting logs.
122-
func AddConsoleLog(Logger *logrus.Logger) {
123-
consoleLog := &logrus.Logger{
124-
Out: os.Stdout,
125-
Formatter: Logger.Formatter,
126-
Hooks: make(logrus.LevelHooks),
127-
Level: Logger.Level,
116+
// Init initializes the logger with given options. If no option is provided,
117+
// the logger's formatter will be set with an empty sign.
118+
func Init(l *logrus.Logger, opts ...Option) error {
119+
opts = append([]Option{
120+
WithSign(""),
121+
}, opts...)
122+
for _, opt := range opts {
123+
if err := opt(l); err != nil {
124+
return err
125+
}
128126
}
129-
Logger.Hooks.Add(&ConsoleHook{logger: consoleLog, levels: logrus.AllLevels})
127+
if logger, ok := l.Out.(*lumberjack.Logger); ok {
128+
return logger.Rotate()
129+
}
130+
return nil
130131
}
131132

132133
// ConsoleHook shows logs on console.
@@ -207,10 +208,3 @@ func (f *DragonflyFormatter) appendValue(b *bytes.Buffer, value interface{}, wit
207208
b.WriteByte(' ')
208209
}
209210
}
210-
211-
// ----------------------------------------------------------------------------
212-
213-
// IsDebug returns the log level is debug.
214-
func IsDebug(level logrus.Level) bool {
215-
return level >= logrus.DebugLevel
216-
}

0 commit comments

Comments
 (0)