178 lines
4.3 KiB
Go
178 lines
4.3 KiB
Go
package log
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
|
|
tracer "github.com/ipfs/go-log/tracer"
|
|
lwriter "github.com/ipfs/go-log/writer"
|
|
|
|
colorable "github.com/mattn/go-colorable"
|
|
opentrace "github.com/opentracing/opentracing-go"
|
|
logging "github.com/whyrusleeping/go-logging"
|
|
)
|
|
|
|
func init() {
|
|
SetupLogging()
|
|
}
|
|
|
|
var ansiGray = "\033[0;37m"
|
|
var ansiBlue = "\033[0;34m"
|
|
|
|
// LogFormats defines formats for logging (i.e. "color")
|
|
var LogFormats = map[string]string{
|
|
"nocolor": "%{time:2006-01-02 15:04:05.000000} %{level} %{module} %{shortfile}: %{message}",
|
|
"color": ansiGray + "%{time:15:04:05.000} %{color}%{level:5.5s} " + ansiBlue +
|
|
"%{module:10.10s}: %{color:reset}%{message} " + ansiGray + "%{shortfile}%{color:reset}",
|
|
}
|
|
|
|
var defaultLogFormat = "color"
|
|
|
|
// Logging environment variables
|
|
const (
|
|
// TODO these env names should be more general, IPFS is not the only project to
|
|
// use go-log
|
|
envLogging = "IPFS_LOGGING"
|
|
envLoggingFmt = "IPFS_LOGGING_FMT"
|
|
|
|
envLoggingFile = "GOLOG_FILE" // /path/to/file
|
|
envTracingFile = "GOLOG_TRACING_FILE" // /path/to/file
|
|
)
|
|
|
|
// ErrNoSuchLogger is returned when the util pkg is asked for a non existant logger
|
|
var ErrNoSuchLogger = errors.New("Error: No such logger")
|
|
|
|
// loggers is the set of loggers in the system
|
|
var loggerMutex sync.RWMutex
|
|
var loggers = map[string]*logging.Logger{}
|
|
|
|
// SetupLogging will initialize the logger backend and set the flags.
|
|
// TODO calling this in `init` pushes all configuration to env variables
|
|
// - move it out of `init`? then we need to change all the code (js-ipfs, go-ipfs) to call this explicitly
|
|
// - have it look for a config file? need to define what that is
|
|
func SetupLogging() {
|
|
|
|
// colorful or plain
|
|
lfmt := LogFormats[os.Getenv(envLoggingFmt)]
|
|
if lfmt == "" {
|
|
lfmt = LogFormats[defaultLogFormat]
|
|
}
|
|
|
|
// check if we log to a file
|
|
var lgbe []logging.Backend
|
|
if logfp := os.Getenv(envLoggingFile); len(logfp) > 0 {
|
|
f, err := os.Create(logfp)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "ERROR go-log: %s: failed to set logging file backend\n", err)
|
|
} else {
|
|
lgbe = append(lgbe, logging.NewLogBackend(f, "", 0))
|
|
}
|
|
}
|
|
|
|
// logs written to stderr
|
|
lgbe = append(lgbe, logging.NewLogBackend(colorable.NewColorableStderr(), "", 0))
|
|
|
|
// set the backend(s)
|
|
logging.SetBackend(lgbe...)
|
|
logging.SetFormatter(logging.MustStringFormatter(lfmt))
|
|
|
|
lvl := logging.ERROR
|
|
|
|
if logenv := os.Getenv(envLogging); logenv != "" {
|
|
var err error
|
|
lvl, err = logging.LogLevel(logenv)
|
|
if err != nil {
|
|
fmt.Println("error setting log levels", err)
|
|
}
|
|
}
|
|
|
|
// TracerPlugins are instantiated after this, so use loggable tracer
|
|
// by default, if a TracerPlugin is added it will override this
|
|
lgblRecorder := tracer.NewLoggableRecorder()
|
|
lgblTracer := tracer.New(lgblRecorder)
|
|
opentrace.SetGlobalTracer(lgblTracer)
|
|
|
|
SetAllLoggers(lvl)
|
|
|
|
if tracingfp := os.Getenv(envTracingFile); len(tracingfp) > 0 {
|
|
f, err := os.Create(tracingfp)
|
|
if err != nil {
|
|
log.Error("failed to create tracing file: %s", tracingfp)
|
|
} else {
|
|
lwriter.WriterGroup.AddWriter(f)
|
|
}
|
|
}
|
|
}
|
|
|
|
// SetDebugLogging calls SetAllLoggers with logging.DEBUG
|
|
func SetDebugLogging() {
|
|
SetAllLoggers(logging.DEBUG)
|
|
}
|
|
|
|
// SetAllLoggers changes the logging.Level of all loggers to lvl
|
|
func SetAllLoggers(lvl logging.Level) {
|
|
logging.SetLevel(lvl, "")
|
|
|
|
loggerMutex.RLock()
|
|
defer loggerMutex.RUnlock()
|
|
|
|
for n := range loggers {
|
|
logging.SetLevel(lvl, n)
|
|
}
|
|
}
|
|
|
|
// SetLogLevel changes the log level of a specific subsystem
|
|
// name=="*" changes all subsystems
|
|
func SetLogLevel(name, level string) error {
|
|
lvl, err := logging.LogLevel(level)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// wildcard, change all
|
|
if name == "*" {
|
|
SetAllLoggers(lvl)
|
|
return nil
|
|
}
|
|
|
|
loggerMutex.RLock()
|
|
defer loggerMutex.RUnlock()
|
|
|
|
// Check if we have a logger by that name
|
|
if _, ok := loggers[name]; !ok {
|
|
return ErrNoSuchLogger
|
|
}
|
|
|
|
logging.SetLevel(lvl, name)
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetSubsystems returns a slice containing the
|
|
// names of the current loggers
|
|
func GetSubsystems() []string {
|
|
loggerMutex.RLock()
|
|
defer loggerMutex.RUnlock()
|
|
subs := make([]string, 0, len(loggers))
|
|
|
|
for k := range loggers {
|
|
subs = append(subs, k)
|
|
}
|
|
return subs
|
|
}
|
|
|
|
func getLogger(name string) *logging.Logger {
|
|
loggerMutex.Lock()
|
|
defer loggerMutex.Unlock()
|
|
|
|
log := loggers[name]
|
|
if log == nil {
|
|
log = logging.MustGetLogger(name)
|
|
loggers[name] = log
|
|
}
|
|
|
|
return log
|
|
}
|