arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/log/log.go
log/log.goRaw
  1package log
  2
  3import (
  4	"fmt"
  5	"strings"
  6	"time"
  7
  8	"github.com/hermeznetwork/tracerr"
  9	"go.uber.org/zap"
 10	"go.uber.org/zap/zapcore"
 11)
 12
 13var log *zap.SugaredLogger
 14
 15func init() {
 16	// default level: debug
 17	Init("debug", []string{"stdout"})
 18}
 19
 20// Init the logger with defined level. outputs defines the outputs where the
 21// logs will be sent. By default outputs contains "stdout", which prints the
 22// logs at the output of the process. To add a log file as output, the path
 23// should be added at the outputs array. To avoid printing the logs but storing
 24// them on a file, can use []string{"pathtofile.log"}
 25func Init(levelStr string, outputs []string) {
 26	var level zap.AtomicLevel
 27	err := level.UnmarshalText([]byte(levelStr))
 28	if err != nil {
 29		panic(fmt.Errorf("Error on setting log level: %s", err))
 30	}
 31
 32	cfg := zap.Config{
 33		Level:            level,
 34		Encoding:         "console",
 35		OutputPaths:      outputs,
 36		ErrorOutputPaths: []string{"stderr"},
 37		EncoderConfig: zapcore.EncoderConfig{
 38			MessageKey: "message",
 39
 40			LevelKey:    "level",
 41			EncodeLevel: zapcore.CapitalColorLevelEncoder,
 42
 43			TimeKey: "timestamp",
 44			EncodeTime: func(ts time.Time, encoder zapcore.PrimitiveArrayEncoder) {
 45				encoder.AppendString(ts.Local().Format(time.RFC3339))
 46			},
 47			EncodeDuration: zapcore.SecondsDurationEncoder,
 48
 49			CallerKey:    "caller",
 50			EncodeCaller: zapcore.ShortCallerEncoder,
 51
 52			// StacktraceKey: "stacktrace",
 53			StacktraceKey: "",
 54			LineEnding:    zapcore.DefaultLineEnding,
 55		},
 56	}
 57
 58	logger, err := cfg.Build()
 59	if err != nil {
 60		panic(err)
 61	}
 62	//nolint:errcheck
 63	defer logger.Sync()
 64	withOptions := logger.WithOptions(zap.AddCallerSkip(1))
 65	log = withOptions.Sugar()
 66}
 67
 68func sprintStackTrace(st []tracerr.Frame) string {
 69	builder := strings.Builder{}
 70	// Skip deepest frame because it belongs to the go runtime and we don't
 71	// care about it.
 72	if len(st) > 0 {
 73		st = st[:len(st)-1]
 74	}
 75	for _, f := range st {
 76		builder.WriteString(fmt.Sprintf("\n%s:%d %s()", f.Path, f.Line, f.Func))
 77	}
 78	builder.WriteString("\n")
 79	return builder.String()
 80}
 81
 82// appendStackTraceMaybeArgs will append the stacktrace to the args if one of them
 83// is a tracerr.Error
 84func appendStackTraceMaybeArgs(args []interface{}) []interface{} {
 85	for i := range args {
 86		if err, ok := args[i].(tracerr.Error); ok {
 87			st := err.StackTrace()
 88			return append(args, sprintStackTrace(st))
 89		}
 90	}
 91	return args
 92}
 93
 94// Debug calls log.Debug
 95func Debug(args ...interface{}) {
 96	log.Debug(args...)
 97}
 98
 99// Info calls log.Info
100func Info(args ...interface{}) {
101	log.Info(args...)
102}
103
104// Warn calls log.Warn
105func Warn(args ...interface{}) {
106	args = appendStackTraceMaybeArgs(args)
107	log.Warn(args...)
108}
109
110// Error calls log.Error
111func Error(args ...interface{}) {
112	args = appendStackTraceMaybeArgs(args)
113	log.Error(args...)
114}
115
116// Fatal calls log.Fatal
117func Fatal(args ...interface{}) {
118	args = appendStackTraceMaybeArgs(args)
119	log.Fatal(args...)
120}
121
122// Debugf calls log.Debugf
123func Debugf(template string, args ...interface{}) {
124	log.Debugf(template, args...)
125}
126
127// Infof calls log.Infof
128func Infof(template string, args ...interface{}) {
129	log.Infof(template, args...)
130}
131
132// Warnf calls log.Warnf
133func Warnf(template string, args ...interface{}) {
134	log.Warnf(template, args...)
135}
136
137// Fatalf calls log.Warnf
138func Fatalf(template string, args ...interface{}) {
139	log.Fatalf(template, args...)
140}
141
142// Errorf calls log.Errorf and stores the error message into the ErrorFile
143func Errorf(template string, args ...interface{}) {
144	log.Errorf(template, args...)
145}
146
147// appendStackTraceMaybeKV will append the stacktrace to the KV if one of them
148// is a tracerr.Error
149func appendStackTraceMaybeKV(msg string, kv []interface{}) string {
150	for i := range kv {
151		if i%2 == 0 {
152			continue
153		}
154		if err, ok := kv[i].(tracerr.Error); ok {
155			st := err.StackTrace()
156			return fmt.Sprintf("%v: %v%v\n", msg, err, sprintStackTrace(st))
157		}
158	}
159	return msg
160}
161
162// Debugw calls log.Debugw
163func Debugw(template string, kv ...interface{}) {
164	log.Debugw(template, kv...)
165}
166
167// Infow calls log.Infow
168func Infow(template string, kv ...interface{}) {
169	log.Infow(template, kv...)
170}
171
172// Warnw calls log.Warnw
173func Warnw(template string, kv ...interface{}) {
174	template = appendStackTraceMaybeKV(template, kv)
175	log.Warnw(template, kv...)
176}
177
178// Errorw calls log.Errorw
179func Errorw(template string, kv ...interface{}) {
180	template = appendStackTraceMaybeKV(template, kv)
181	log.Errorw(template, kv...)
182}
183
184// Fatalw calls log.Fatalw
185func Fatalw(template string, kv ...interface{}) {
186	template = appendStackTraceMaybeKV(template, kv)
187	log.Fatalw(template, kv...)
188}