Skip to content

Commit

Permalink
improved logging
Browse files Browse the repository at this point in the history
  • Loading branch information
pk910 committed Aug 3, 2023
1 parent 5e59a32 commit db4cb02
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ bin
temp
config.yaml
test-config.yaml
config-*.yaml
config-*.yaml
log-*
2 changes: 2 additions & 0 deletions cmd/explorer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ func main() {
logger.Fatalf("error reading config file: %v", err)
}
utils.Config = cfg
logWriter := utils.InitLogger()
defer logWriter.Dispose()
logger.WithFields(logger.Fields{
"config": *configPath,
//"version": version.Version,
Expand Down
7 changes: 7 additions & 0 deletions config/default.config.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@

logging:
#outputLevel: "info"
#outputStderr: false

#filePath: "explorer.log"
#fileLevel: "warn"

# Chain network configuration
chain:
name: "mainnet"
Expand Down
8 changes: 8 additions & 0 deletions types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ import "time"

// Config is a struct to hold the configuration data
type Config struct {
Logging struct {
OutputLevel string `yaml:"outputLevel" envconfig:"LOGGING_OUTPUT_LEVEL"`
OutputStderr bool `yaml:"outputStderr" envconfig:"LOGGING_OUTPUT_STDERR"`

FilePath string `yaml:"filePath" envconfig:"LOGGING_FILE_PATH"`
FileLevel string `yaml:"fileLevel" envconfig:"LOGGING_FILE_LEVEL"`
} `yaml:"logging"`

Server struct {
Port string `yaml:"port" envconfig:"FRONTEND_SERVER_PORT"`
Host string `yaml:"host" envconfig:"FRONTEND_SERVER_HOST"`
Expand Down
188 changes: 188 additions & 0 deletions utils/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,201 @@ package utils
import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"

logger "github.com/sirupsen/logrus"
)

type LogWriter struct {
logFile *os.File
}

func InitLogger() *LogWriter {
logger.SetOutput(ioutil.Discard) // Send all logs to nowhere by default
logWriter := &LogWriter{}
fmt.Printf("init logger\n")

outputLevel := getLogLevels(logger.InfoLevel)
if Config.Logging.OutputLevel != "" {
levelParts := strings.Split(Config.Logging.OutputLevel, "|")
if len(levelParts) > 1 {
outputLevel = []logger.Level{}
for _, level := range levelParts {
logLevel := parseLogLevel(level)
if logLevel != 9999 {
outputLevel = append(outputLevel, logLevel)
}
}
} else {
logLevel := parseLogLevel(levelParts[0])
if logLevel != 9999 {
outputLevel = getLogLevels(logLevel)
} else {
outputLevel = []logger.Level{}
}
}
}
if len(outputLevel) > 0 {
var writer io.Writer
if Config.Logging.OutputStderr {
writer = os.Stderr
} else {
writer = os.Stdout
}
logger.AddHook(&LogWriterHook{
Writer: writer,
LogLevels: outputLevel,
})
}

if Config.Logging.FilePath != "" {
fileLevel := getLogLevels(logger.InfoLevel)
if Config.Logging.FileLevel != "" {
levelParts := strings.Split(Config.Logging.FileLevel, "|")
if len(levelParts) > 1 {
fileLevel = []logger.Level{}
for _, level := range levelParts {
logLevel := parseLogLevel(level)
if logLevel != 9999 {
fileLevel = append(fileLevel, logLevel)
}
}
} else {
logLevel := parseLogLevel(levelParts[0])
if logLevel != 9999 {
fileLevel = getLogLevels(logLevel)
} else {
fileLevel = []logger.Level{}
}
}
}

fmt.Printf("logging to file: %v (%v)\n", Config.Logging.FilePath, fileLevel)
f, err := os.OpenFile(Config.Logging.FilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
fmt.Println("Failed to create logfile" + Config.Logging.FilePath)
panic(err)
}
logWriter.logFile = f
logger.AddHook(&LogWriterHook{ // Send info and debug logs to stdout
Writer: f,
LogLevels: fileLevel,
})
}

return logWriter
}

func (logWriter *LogWriter) Dispose() {
if logWriter.logFile != nil {
logWriter.logFile.Close()
logWriter.logFile = nil
}
}

func getLogLevels(level logger.Level) []logger.Level {
if level == logger.TraceLevel {
return []logger.Level{
logger.PanicLevel,
logger.FatalLevel,
logger.ErrorLevel,
logger.WarnLevel,
logger.InfoLevel,
logger.DebugLevel,
logger.TraceLevel,
}
} else if level == logger.DebugLevel {
return []logger.Level{
logger.PanicLevel,
logger.FatalLevel,
logger.ErrorLevel,
logger.WarnLevel,
logger.InfoLevel,
logger.DebugLevel,
}
} else if level == logger.InfoLevel {
return []logger.Level{
logger.PanicLevel,
logger.FatalLevel,
logger.ErrorLevel,
logger.WarnLevel,
logger.InfoLevel,
}
} else if level == logger.WarnLevel {
return []logger.Level{
logger.PanicLevel,
logger.FatalLevel,
logger.ErrorLevel,
logger.WarnLevel,
}
} else if level == logger.ErrorLevel {
return []logger.Level{
logger.PanicLevel,
logger.FatalLevel,
logger.ErrorLevel,
}
} else if level == logger.FatalLevel {
return []logger.Level{
logger.PanicLevel,
logger.FatalLevel,
}
} else if level == logger.PanicLevel {
return []logger.Level{
logger.PanicLevel,
}
} else {
return []logger.Level{}
}
}

func parseLogLevel(level string) logger.Level {
switch level {
case "trace":
return logger.TraceLevel
case "debug":
return logger.DebugLevel
case "info":
return logger.InfoLevel
case "warn":
return logger.WarnLevel
case "error":
return logger.ErrorLevel
case "fatal":
return logger.FatalLevel
case "panic":
return logger.PanicLevel
case "none":
return 9999
}
return 0
}

// WriterHook is a hook that writes logs of specified LogLevels to specified Writer
type LogWriterHook struct {
Writer io.Writer
LogLevels []logger.Level
}

// Fire will be called when some logging function is called with current hook
// It will format log entry to string and write it to appropriate writer
func (hook *LogWriterHook) Fire(entry *logger.Entry) error {
line, err := entry.String()
if err != nil {
return err
}
_, err = hook.Writer.Write([]byte(line))
return err
}

func (hook *LogWriterHook) Levels() []logger.Level {
return hook.LogLevels
}

// LogFatal logs a fatal error with callstack info that skips callerSkip many levels with arbitrarily many additional infos.
// callerSkip equal to 0 gives you info directly where LogFatal is called.
func LogFatal(err error, errorMsg interface{}, callerSkip int, additionalInfos ...map[string]interface{}) {
Expand Down

0 comments on commit db4cb02

Please sign in to comment.