codeberg.org/gruf/go-log@v1.0.6-0.20231202001801-031c3d3d089b/log.go (about)

     1  package log
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"log"
     7  	"sync/atomic"
     8  	_ "unsafe"
     9  
    10  	"codeberg.org/gruf/go-byteutil"
    11  	"codeberg.org/gruf/go-kv"
    12  )
    13  
    14  // stdflags are the log flags we use as a base for all Logger instances.
    15  const stdflags = log.Ldate | log.Ltime
    16  
    17  // Logger wraps the stdlib log.Logger to provided levelled logging.
    18  type Logger struct {
    19  	log *log.Logger // underlying standard lib logger
    20  	lvl uint32      // currently set log level
    21  	min uint8       // minimum call depth (used by global logger)
    22  }
    23  
    24  // New returns a new instance of Logger writing to given output. A
    25  // minimum call depth may be specified to skip caller frames in caller info.
    26  func New(w io.Writer, min uint8) *Logger {
    27  	return NewFrom(log.New(w, "", stdflags), 1)
    28  }
    29  
    30  // NewFrom returns a new instance of Logger wrapping the provided standard library
    31  // logger. A minimum call depth may be specified to skip caller frames in caller info.
    32  func NewFrom(log *log.Logger, min uint8) *Logger {
    33  	return &Logger{
    34  		log: log,
    35  		lvl: uint32(ALL),
    36  		min: min,
    37  	}
    38  }
    39  
    40  func (l *Logger) Debug(a ...interface{}) {
    41  	l.Log(2, DEBUG, a...)
    42  }
    43  
    44  func (l *Logger) Debugf(s string, a ...interface{}) {
    45  	l.Logf(2, DEBUG, s, a...)
    46  }
    47  
    48  func (l *Logger) DebugFields(fields ...kv.Field) {
    49  	l.LogFields(2, DEBUG, fields...)
    50  }
    51  
    52  func (l *Logger) Info(a ...interface{}) {
    53  	l.Log(2, INFO, a...)
    54  }
    55  
    56  func (l *Logger) Infof(s string, a ...interface{}) {
    57  	l.Logf(2, INFO, s, a...)
    58  }
    59  
    60  func (l *Logger) InfoFields(fields ...kv.Field) {
    61  	l.LogFields(2, INFO, fields...)
    62  }
    63  
    64  func (l *Logger) Warn(a ...interface{}) {
    65  	l.Log(2, WARN, a...)
    66  }
    67  
    68  func (l *Logger) Warnf(s string, a ...interface{}) {
    69  	l.Logf(2, WARN, s, a...)
    70  }
    71  
    72  func (l *Logger) WarnFields(fields ...kv.Field) {
    73  	l.LogFields(2, WARN, fields...)
    74  }
    75  
    76  func (l *Logger) Error(a ...interface{}) {
    77  	l.Log(2, ERROR, a...)
    78  }
    79  
    80  func (l *Logger) Errorf(s string, a ...interface{}) {
    81  	l.Logf(2, ERROR, s, a...)
    82  }
    83  
    84  func (l *Logger) ErrorFields(fields ...kv.Field) {
    85  	l.LogFields(2, ERROR, fields...)
    86  }
    87  
    88  func (l *Logger) Panic(a ...interface{}) {
    89  	str := fmt.Sprint(a...)
    90  	l.Log(2, PANIC, str)
    91  	panic(str)
    92  }
    93  
    94  func (l *Logger) Panicf(s string, a ...interface{}) {
    95  	str := fmt.Sprintf(s, a...)
    96  	l.Log(2, PANIC, str)
    97  	panic(str)
    98  }
    99  
   100  func (l *Logger) PanicFields(fields ...kv.Field) {
   101  	str := kv.Fields(fields).String()
   102  	l.Log(2, PANIC, str)
   103  	panic(str)
   104  }
   105  
   106  // Log calls underlying stdlib log.Logger.Output() to print to the logger with level. Arguments are handled in the manner of fmt.Print.
   107  func (l *Logger) Log(calldepth int, lvl LEVEL, a ...interface{}) {
   108  	if lvl > l.Level() {
   109  		return // no output
   110  	}
   111  	log_output(l.log, 0, int(l.min)+calldepth+1, func(b []byte) []byte {
   112  		b = append(b, "["+levels[lvl]+"] "...)
   113  		b = fmt.Append(b, a...)
   114  		return b
   115  	})
   116  }
   117  
   118  // Logf calls underlying stdlib log.Logger.Output() to print to the logger with level. Arguments are handled in the manner of fmt.Printf.
   119  func (l *Logger) Logf(calldepth int, lvl LEVEL, s string, a ...interface{}) {
   120  	if lvl > l.Level() {
   121  		return // no output
   122  	}
   123  	log_output(l.log, 0, int(l.min)+calldepth+1, func(b []byte) []byte {
   124  		b = append(b, "["+levels[lvl]+"] "...)
   125  		b = fmt.Appendf(b, s, a...)
   126  		return b
   127  	})
   128  }
   129  
   130  // Logf calls underlying stdlib log.Logger.Output() to print to the logger with level. Arguments formatted using fv.Fields{}.String().
   131  func (l *Logger) LogFields(calldepth int, lvl LEVEL, fields ...kv.Field) {
   132  	if lvl > l.Level() {
   133  		return // no output
   134  	}
   135  	log_output(l.log, 0, int(l.min)+calldepth+1, func(b []byte) []byte {
   136  		buf := byteutil.Buffer{B: b}
   137  		buf.B = append(buf.B, "["+levels[lvl]+"] "...)
   138  		kv.Fields(fields).AppendFormat(&buf, false)
   139  		return buf.B
   140  	})
   141  }
   142  
   143  // Print calls underlying stdlib log.Logger.Output() to print to the logger. Arguments are handled in the manner of fmt.Print.
   144  func (l *Logger) Print(a ...interface{}) {
   145  	log_output(l.log, 0, int(l.min)+2, func(b []byte) []byte {
   146  		return fmt.Append(b, a...)
   147  	})
   148  }
   149  
   150  // Printf calls underlying stdlib log.Logger.Output() to print to the logger. Arguments are handled in the manner of fmt.Printf.
   151  func (l *Logger) Printf(s string, a ...interface{}) {
   152  	log_output(l.log, 0, int(l.min)+2, func(b []byte) []byte {
   153  		return fmt.Appendf(b, s, a...)
   154  	})
   155  }
   156  
   157  // PrintFields calls underlying stdlib log.Logger.Output() to print to the logger. Arguments formatted using fv.Fields{}.String().
   158  func (l *Logger) PrintFields(fields ...kv.Field) {
   159  	log_output(l.log, 0, int(l.min)+2, func(b []byte) []byte {
   160  		buf := byteutil.Buffer{B: b}
   161  		kv.Fields(fields).AppendFormat(&buf, false)
   162  		return buf.B
   163  	})
   164  }
   165  
   166  // Level returns the minimum logging level for the logger.
   167  func (l *Logger) Level() LEVEL {
   168  	return LEVEL(atomic.LoadUint32(&l.lvl))
   169  }
   170  
   171  // SetLevel sets the minimum logging level for the logger.
   172  func (l *Logger) SetLevel(lvl LEVEL) {
   173  	atomic.StoreUint32(&l.lvl, uint32(lvl))
   174  }
   175  
   176  // IncludeCaller returns whether 'IncludeCaller' is enabled.
   177  func (l *Logger) IncludeCaller() bool {
   178  	return l.log.Flags()&log.Llongfile != 0
   179  }
   180  
   181  // SetIncludeCaller enables/disbables logging with added caller information.
   182  func (l *Logger) SetIncludeCaller(enabled bool) {
   183  	flags := stdflags
   184  	if enabled {
   185  		flags |= log.Llongfile
   186  	}
   187  	l.log.SetFlags(flags)
   188  }
   189  
   190  // SetOutput sets the output destination for the logger.
   191  func (l *Logger) SetOutput(out io.Writer) {
   192  	l.log.SetOutput(out)
   193  }
   194  
   195  // Logger returns the underlying stdlib log.Logger.
   196  func (l *Logger) Logger() *log.Logger {
   197  	return l.log
   198  }
   199  
   200  //go:linkname log_output log.(*Logger).output
   201  func log_output(l *log.Logger, pc uintptr, calldepth int, appendOutput func([]byte) []byte) error