mirror of
https://github.com/status-im/status-go.git
synced 2025-01-09 22:26:30 +00:00
eeca435064
Update vendor Integrate rendezvous into status node Add a test with failover using rendezvous Use multiple servers in client Use discovery V5 by default and test that node can be started with rendezvous discovet Fix linter Update rendezvous client to one with instrumented stream Address feedback Fix test with updated topic limits Apply several suggestions Change log to debug for request errors because we continue execution Remove web3js after rebase Update rendezvous package
280 lines
7.7 KiB
Go
280 lines
7.7 KiB
Go
// Copyright 2013, Örjan Persson. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package logging implements a logging infrastructure for Go. It supports
|
|
// different logging backends like syslog, file and memory. Multiple backends
|
|
// can be utilized with different log levels per backend and logger.
|
|
package logging
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
// Redactor is an interface for types that may contain sensitive information
|
|
// (like passwords), which shouldn't be printed to the log. The idea was found
|
|
// in relog as part of the vitness project.
|
|
type Redactor interface {
|
|
Redacted() interface{}
|
|
}
|
|
|
|
// Redact returns a string of * having the same length as s.
|
|
func Redact(s string) string {
|
|
return strings.Repeat("*", len(s))
|
|
}
|
|
|
|
var (
|
|
// Sequence number is incremented and utilized for all log records created.
|
|
sequenceNo uint64
|
|
|
|
// timeNow is a customizable for testing purposes.
|
|
timeNow = time.Now
|
|
)
|
|
|
|
// Record represents a log record and contains the timestamp when the record
|
|
// was created, an increasing id, filename and line and finally the actual
|
|
// formatted log line.
|
|
type Record struct {
|
|
Id uint64
|
|
Time time.Time
|
|
Module string
|
|
Level Level
|
|
|
|
// message is kept as a pointer to have shallow copies update this once
|
|
// needed.
|
|
message *string
|
|
args []interface{}
|
|
fmt string
|
|
formatter Formatter
|
|
formatted string
|
|
}
|
|
|
|
// Formatted returns the string-formatted version of a record.
|
|
func (r *Record) Formatted(calldepth int) string {
|
|
if r.formatted == "" {
|
|
var buf bytes.Buffer
|
|
r.formatter.Format(calldepth+1, r, &buf)
|
|
r.formatted = buf.String()
|
|
}
|
|
return r.formatted
|
|
}
|
|
|
|
// Message returns a string message for outputting. Redacts any record args
|
|
// that implement the Redactor interface
|
|
func (r *Record) Message() string {
|
|
if r.message == nil {
|
|
// Redact the arguments that implements the Redactor interface
|
|
for i, arg := range r.args {
|
|
if redactor, ok := arg.(Redactor); ok == true {
|
|
r.args[i] = redactor.Redacted()
|
|
}
|
|
}
|
|
msg := fmt.Sprintf(r.fmt, r.args...)
|
|
r.message = &msg
|
|
}
|
|
return *r.message
|
|
}
|
|
|
|
// Logger is a logging unit. It controls the flow of messages to a given
|
|
// (swappable) backend.
|
|
type Logger struct {
|
|
Module string
|
|
backend LeveledBackend
|
|
haveBackend bool
|
|
|
|
// ExtraCallDepth can be used to add additional call depth when getting the
|
|
// calling function. This is normally used when wrapping a logger.
|
|
ExtraCalldepth int
|
|
}
|
|
|
|
// SetBackend changes the backend of the logger.
|
|
func (l *Logger) SetBackend(backend LeveledBackend) {
|
|
l.backend = backend
|
|
l.haveBackend = true
|
|
}
|
|
|
|
// GetLogger creates and returns a Logger object based on the module name.
|
|
// TODO call NewLogger and remove MustGetLogger?
|
|
func GetLogger(module string) (*Logger, error) {
|
|
return &Logger{Module: module}, nil
|
|
}
|
|
|
|
// MustGetLogger is like GetLogger but panics if the logger can't be created.
|
|
// It simplifies safe initialization of a global logger for eg. a package.
|
|
func MustGetLogger(module string) *Logger {
|
|
logger, err := GetLogger(module)
|
|
if err != nil {
|
|
panic("logger: " + module + ": " + err.Error())
|
|
}
|
|
return logger
|
|
}
|
|
|
|
// Reset restores the internal state of the logging library.
|
|
func Reset() {
|
|
// TODO make a global Init() method to be less magic? or make it such that
|
|
// if there's no backends at all configured, we could use some tricks to
|
|
// automatically setup backends based if we have a TTY or not.
|
|
sequenceNo = 0
|
|
b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags))
|
|
b.SetLevel(DEBUG, "")
|
|
SetFormatter(DefaultFormatter)
|
|
timeNow = time.Now
|
|
}
|
|
|
|
// InitForTesting is a convenient method when using logging in a test. Once
|
|
// called, the time will be frozen to January 1, 1970 UTC.
|
|
func InitForTesting(level Level) *MemoryBackend {
|
|
Reset()
|
|
|
|
memoryBackend := NewMemoryBackend(10240)
|
|
|
|
leveledBackend := AddModuleLevel(memoryBackend)
|
|
leveledBackend.SetLevel(level, "")
|
|
SetBackend(leveledBackend)
|
|
|
|
timeNow = func() time.Time {
|
|
return time.Unix(0, 0).UTC()
|
|
}
|
|
return memoryBackend
|
|
}
|
|
|
|
// IsEnabledFor returns true if the logger is enabled for the given level.
|
|
func (l *Logger) IsEnabledFor(level Level) bool {
|
|
return defaultBackend.IsEnabledFor(level, l.Module)
|
|
}
|
|
|
|
func (l *Logger) log(lvl Level, format string, args ...interface{}) {
|
|
if !l.IsEnabledFor(lvl) {
|
|
return
|
|
}
|
|
|
|
// Create the logging record and pass it in to the backend
|
|
record := &Record{
|
|
Id: atomic.AddUint64(&sequenceNo, 1),
|
|
Time: timeNow(),
|
|
Module: l.Module,
|
|
Level: lvl,
|
|
fmt: format,
|
|
args: args,
|
|
}
|
|
|
|
// TODO use channels to fan out the records to all backends?
|
|
// TODO in case of errors, do something (tricky)
|
|
|
|
// calldepth=2 brings the stack up to the caller of the level
|
|
// methods, Info(), Fatal(), etc.
|
|
// ExtraCallDepth allows this to be extended further up the stack in case we
|
|
// are wrapping these methods, eg. to expose them package level
|
|
if l.haveBackend {
|
|
l.backend.Log(lvl, 2+l.ExtraCalldepth, record)
|
|
return
|
|
}
|
|
|
|
defaultBackend.Log(lvl, 2+l.ExtraCalldepth, record)
|
|
}
|
|
|
|
// Fatal is equivalent to l.Critical(fmt.Sprint()) followed by a call to os.Exit(1).
|
|
func (l *Logger) Fatal(args ...interface{}) {
|
|
s := fmt.Sprint(args...)
|
|
l.log(CRITICAL, "%s", s)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Fatalf is equivalent to l.Critical followed by a call to os.Exit(1).
|
|
func (l *Logger) Fatalf(format string, args ...interface{}) {
|
|
l.log(CRITICAL, format, args...)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Panic is equivalent to l.Critical(fmt.Sprint()) followed by a call to panic().
|
|
func (l *Logger) Panic(args ...interface{}) {
|
|
s := fmt.Sprint(args...)
|
|
l.log(CRITICAL, "%s", s)
|
|
panic(s)
|
|
}
|
|
|
|
// Panicf is equivalent to l.Critical followed by a call to panic().
|
|
func (l *Logger) Panicf(format string, args ...interface{}) {
|
|
s := fmt.Sprintf(format, args...)
|
|
l.log(CRITICAL, "%s", s)
|
|
panic(s)
|
|
}
|
|
|
|
// Critical logs a message using CRITICAL as log level. (fmt.Sprint())
|
|
func (l *Logger) Critical(args ...interface{}) {
|
|
l.log(CRITICAL, defaultArgsFormat(len(args)), args...)
|
|
}
|
|
|
|
// Criticalf logs a message using CRITICAL as log level.
|
|
func (l *Logger) Criticalf(format string, args ...interface{}) {
|
|
l.log(CRITICAL, format, args...)
|
|
}
|
|
|
|
// Error logs a message using ERROR as log level. (fmt.Sprint())
|
|
func (l *Logger) Error(args ...interface{}) {
|
|
l.log(ERROR, defaultArgsFormat(len(args)), args...)
|
|
}
|
|
|
|
// Errorf logs a message using ERROR as log level.
|
|
func (l *Logger) Errorf(format string, args ...interface{}) {
|
|
l.log(ERROR, format, args...)
|
|
}
|
|
|
|
// Warning logs a message using WARNING as log level.
|
|
func (l *Logger) Warning(args ...interface{}) {
|
|
l.log(WARNING, defaultArgsFormat(len(args)), args...)
|
|
}
|
|
|
|
// Warningf logs a message using WARNING as log level.
|
|
func (l *Logger) Warningf(format string, args ...interface{}) {
|
|
l.log(WARNING, format, args...)
|
|
}
|
|
|
|
// Notice logs a message using NOTICE as log level.
|
|
func (l *Logger) Notice(args ...interface{}) {
|
|
l.log(NOTICE, defaultArgsFormat(len(args)), args...)
|
|
}
|
|
|
|
// Noticef logs a message using NOTICE as log level.
|
|
func (l *Logger) Noticef(format string, args ...interface{}) {
|
|
l.log(NOTICE, format, args...)
|
|
}
|
|
|
|
// Info logs a message using INFO as log level.
|
|
func (l *Logger) Info(args ...interface{}) {
|
|
l.log(INFO, defaultArgsFormat(len(args)), args...)
|
|
}
|
|
|
|
// Infof logs a message using INFO as log level.
|
|
func (l *Logger) Infof(format string, args ...interface{}) {
|
|
l.log(INFO, format, args...)
|
|
}
|
|
|
|
// Debug logs a message using DEBUG as log level.
|
|
func (l *Logger) Debug(args ...interface{}) {
|
|
l.log(DEBUG, defaultArgsFormat(len(args)), args...)
|
|
}
|
|
|
|
// Debugf logs a message using DEBUG as log level.
|
|
func (l *Logger) Debugf(format string, args ...interface{}) {
|
|
l.log(DEBUG, format, args...)
|
|
}
|
|
|
|
func defaultArgsFormat(argc int) string {
|
|
f := strings.Repeat("%s ", argc)
|
|
if argc > 0 {
|
|
f = f[:len(f) - 1]
|
|
}
|
|
return f
|
|
}
|
|
|
|
func init() {
|
|
Reset()
|
|
}
|