gopkg.in/dedis/onet.v2@v2.0.0-20181115163211-c8f3724038a7/log/loggers.go (about)

     1  package log
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  
     7  	"github.com/daviddengcn/go-colortext"
     8  )
     9  
    10  // LoggerInfo is a structure that should be used when creating a logger.
    11  // It contains parameters about how to log (with time, colors, ...) and
    12  // embeds the Logger interface, which should define how the logger should log.
    13  type LoggerInfo struct {
    14  	// These are information-debugging levels that can be turned on or off.
    15  	// Every logging greater than 'debugLvl' will be discarded . So you can
    16  	// Log at different levels and easily turn on or off the amount of logging
    17  	// generated by adjusting the 'debugLvl' variable.
    18  	DebugLvl int
    19  	// If 'showTime' is true, it will print the time for each line displayed
    20  	// by the logger.
    21  	ShowTime bool
    22  	// If 'useColors' is true, logs will be colored (defaults to monochrome
    23  	// output). It also controls padding, since colorful output is higly
    24  	// correlated with humans who like their log lines padded.
    25  	UseColors bool
    26  	// If 'padding' is true, it will nicely pad the line that is written.
    27  	Padding bool
    28  }
    29  
    30  // Logger is the interface that specifies how loggers
    31  // will receive and display messages.
    32  type Logger interface {
    33  	Log(level int, msg string)
    34  	Close()
    35  	GetLoggerInfo() *LoggerInfo
    36  }
    37  
    38  const (
    39  	// DefaultStdDebugLvl is the default debug level for the standard logger
    40  	DefaultStdDebugLvl = 1
    41  	// DefaultStdShowTime is the default value for 'showTime' for the standard logger
    42  	DefaultStdShowTime = false
    43  	// DefaultStdUseColors is the default value for 'useColors' for the standard logger
    44  	DefaultStdUseColors = false
    45  	// DefaultStdPadding is the default value for 'padding' for the standard logger
    46  	DefaultStdPadding = true
    47  )
    48  
    49  var (
    50  	// concurrent access is protected by debugMut
    51  	loggers        = make(map[int]Logger)
    52  	loggersCounter int
    53  )
    54  
    55  // RegisterLogger will register a callback that will receive a copy of every
    56  // message, fully formatted. It returns the key assigned to the logger (used
    57  // to unregister the logger).
    58  func RegisterLogger(l Logger) int {
    59  	debugMut.Lock()
    60  	defer debugMut.Unlock()
    61  	key := loggersCounter
    62  	loggers[key] = l
    63  	loggersCounter++
    64  	return key
    65  }
    66  
    67  // UnregisterLogger takes the key it was assigned and returned by
    68  // 'RegisterLogger', closes the corresponding Logger and removes it from the
    69  // loggers.
    70  func UnregisterLogger(key int) {
    71  	debugMut.Lock()
    72  	defer debugMut.Unlock()
    73  	if l, ok := loggers[key]; ok {
    74  		l.Close()
    75  		delete(loggers, key)
    76  	}
    77  }
    78  
    79  type fileLogger struct {
    80  	lInfo *LoggerInfo
    81  	file  *os.File
    82  }
    83  
    84  func (fl *fileLogger) Log(level int, msg string) {
    85  	if _, err := fl.file.WriteString(msg); err != nil {
    86  		panic(err)
    87  	}
    88  }
    89  
    90  func (fl *fileLogger) Close() {
    91  	fl.file.Close()
    92  }
    93  
    94  func (fl *fileLogger) GetLoggerInfo() *LoggerInfo {
    95  	return fl.lInfo
    96  }
    97  
    98  // NewFileLogger creates a logger that writes into the file with
    99  // the given path and is using the given LoggerInfo.
   100  // It returns the logger.
   101  func NewFileLogger(lInfo *LoggerInfo, path string) (Logger, error) {
   102  	// Override file if it already exists.
   103  	file, err := os.Create(path)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	return &fileLogger{
   108  		lInfo: lInfo,
   109  		file:  file,
   110  	}, nil
   111  }
   112  
   113  type stdLogger struct {
   114  	lInfo *LoggerInfo
   115  }
   116  
   117  func (sl *stdLogger) Log(lvl int, msg string) {
   118  	if sl.lInfo.UseColors {
   119  		bright := lvl < 0
   120  		lvlAbs := lvl
   121  		if bright {
   122  			lvlAbs *= -1
   123  		}
   124  
   125  		switch lvl {
   126  		case lvlPrint:
   127  			ct.Foreground(ct.White, true)
   128  		case lvlInfo:
   129  			ct.Foreground(ct.White, true)
   130  		case lvlWarning:
   131  			ct.Foreground(ct.Green, true)
   132  		case lvlError:
   133  			ct.Foreground(ct.Red, false)
   134  		case lvlFatal:
   135  			ct.Foreground(ct.Red, true)
   136  		case lvlPanic:
   137  			ct.Foreground(ct.Red, true)
   138  		default:
   139  			if lvl != 0 {
   140  				if lvlAbs <= 5 {
   141  					colors := []ct.Color{ct.Yellow, ct.Cyan, ct.Green, ct.Blue, ct.Cyan}
   142  					ct.Foreground(colors[lvlAbs-1], bright)
   143  				}
   144  			}
   145  		}
   146  	}
   147  
   148  	if lvl < lvlInfo {
   149  		fmt.Fprint(stdErr, msg)
   150  	} else {
   151  		fmt.Fprint(stdOut, msg)
   152  	}
   153  
   154  	if sl.lInfo.UseColors {
   155  		ct.ResetColor()
   156  	}
   157  }
   158  
   159  func (sl *stdLogger) Close() {}
   160  
   161  func (sl *stdLogger) GetLoggerInfo() *LoggerInfo {
   162  	return sl.lInfo
   163  }
   164  
   165  // Not public + not taking a LoggerInfo as argument because we don't want
   166  // multiple stdLoggers.
   167  func newStdLogger() (Logger, error) {
   168  	lInfo := &LoggerInfo{
   169  		DebugLvl:  DefaultStdDebugLvl,
   170  		UseColors: DefaultStdUseColors,
   171  		ShowTime:  DefaultStdShowTime,
   172  		Padding:   DefaultStdPadding,
   173  	}
   174  	return &stdLogger{lInfo: lInfo}, nil
   175  }