| 
									
										
										
										
											2021-11-13 12:29:08 +01:00
										 |  |  | package logger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"sync/atomic" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"codeberg.org/gruf/go-bytes" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Logger struct { | 
					
						
							|  |  |  | 	// Hooks defines a list of hooks which are called before an entry | 
					
						
							|  |  |  | 	// is written. This should NOT be modified while the Logger is in use | 
					
						
							|  |  |  | 	Hooks []Hook | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Level is the current log LEVEL, entries at level below the | 
					
						
							|  |  |  | 	// currently set level will not be output. This should NOT | 
					
						
							|  |  |  | 	// be modified while the Logger is in use | 
					
						
							|  |  |  | 	Level LEVEL | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Timestamp defines whether to automatically append timestamps | 
					
						
							|  |  |  | 	// to entries written via Logger convience methods and specifically | 
					
						
							|  |  |  | 	// Entry.TimestampIf(). This should NOT be modified while Logger in use | 
					
						
							|  |  |  | 	Timestamp bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Format is the log entry LogFormat to use. This should NOT | 
					
						
							|  |  |  | 	// be modified while the Logger is in use | 
					
						
							|  |  |  | 	Format LogFormat | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// BufferSize is the Entry buffer size to use when allocating | 
					
						
							|  |  |  | 	// new Entry objects. This should be modified atomically | 
					
						
							|  |  |  | 	BufSize int64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Output is the log's output writer. This should NOT be | 
					
						
							|  |  |  | 	// modified while the Logger is in use | 
					
						
							|  |  |  | 	Output io.Writer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// entry pool | 
					
						
							|  |  |  | 	pool sync.Pool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // New returns a new Logger instance with defaults | 
					
						
							|  |  |  | func New(out io.Writer) *Logger { | 
					
						
							| 
									
										
										
										
											2021-11-27 15:26:58 +01:00
										 |  |  | 	return NewWith(0 /* all */, true, DefaultTextFormat, 512, out) | 
					
						
							| 
									
										
										
										
											2021-11-13 12:29:08 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewWith returns a new Logger instance with supplied configuration | 
					
						
							|  |  |  | func NewWith(lvl LEVEL, timestamp bool, fmt LogFormat, bufsize int64, out io.Writer) *Logger { | 
					
						
							|  |  |  | 	// Create new logger object | 
					
						
							|  |  |  | 	log := &Logger{ | 
					
						
							|  |  |  | 		Level:     lvl, | 
					
						
							|  |  |  | 		Timestamp: timestamp, | 
					
						
							|  |  |  | 		Format:    fmt, | 
					
						
							|  |  |  | 		BufSize:   bufsize, | 
					
						
							|  |  |  | 		Output:    out, | 
					
						
							|  |  |  | 		pool:      sync.Pool{}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Ensure clock running | 
					
						
							|  |  |  | 	startClock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set-up logger Entry pool | 
					
						
							|  |  |  | 	log.pool.New = func() interface{} { | 
					
						
							|  |  |  | 		return &Entry{ | 
					
						
							|  |  |  | 			lvl: unset, | 
					
						
							|  |  |  | 			buf: &bytes.Buffer{B: make([]byte, 0, atomic.LoadInt64(&log.BufSize))}, | 
					
						
							|  |  |  | 			log: log, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return log | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Entry returns a new Entry from the Logger's pool with background context | 
					
						
							|  |  |  | func (l *Logger) Entry() *Entry { | 
					
						
							|  |  |  | 	return l.pool.Get().(*Entry).WithContext(context.Background()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Debug prints the provided arguments with the debug prefix | 
					
						
							|  |  |  | func (l *Logger) Debug(a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(DEBUG).Hooks().Msg(a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Debugf prints the provided format string and arguments with the debug prefix | 
					
						
							|  |  |  | func (l *Logger) Debugf(s string, a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(DEBUG).Hooks().Msgf(s, a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Info prints the provided arguments with the info prefix | 
					
						
							|  |  |  | func (l *Logger) Info(a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(INFO).Hooks().Msg(a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Infof prints the provided format string and arguments with the info prefix | 
					
						
							|  |  |  | func (l *Logger) Infof(s string, a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(INFO).Hooks().Msgf(s, a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Warn prints the provided arguments with the warn prefix | 
					
						
							|  |  |  | func (l *Logger) Warn(a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(WARN).Hooks().Msg(a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Warnf prints the provided format string and arguments with the warn prefix | 
					
						
							|  |  |  | func (l *Logger) Warnf(s string, a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(WARN).Hooks().Msgf(s, a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Error prints the provided arguments with the error prefix | 
					
						
							|  |  |  | func (l *Logger) Error(a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(ERROR).Hooks().Msg(a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Errorf prints the provided format string and arguments with the error prefix | 
					
						
							|  |  |  | func (l *Logger) Errorf(s string, a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(ERROR).Hooks().Msgf(s, a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Fatal prints provided arguments with the fatal prefix before exiting the program | 
					
						
							|  |  |  | // with os.Exit(1) | 
					
						
							|  |  |  | func (l *Logger) Fatal(a ...interface{}) { | 
					
						
							|  |  |  | 	defer os.Exit(1) | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(FATAL).Hooks().Msg(a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Fatalf prints provided the provided format string and arguments with the fatal prefix | 
					
						
							|  |  |  | // before exiting the program with os.Exit(1) | 
					
						
							|  |  |  | func (l *Logger) Fatalf(s string, a ...interface{}) { | 
					
						
							|  |  |  | 	defer os.Exit(1) | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Level(FATAL).Hooks().Msgf(s, a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Log prints the provided arguments with the supplied log level | 
					
						
							|  |  |  | func (l *Logger) Log(lvl LEVEL, a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Hooks().Msg(a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Logf prints the provided format string and arguments with the supplied log level | 
					
						
							|  |  |  | func (l *Logger) Logf(lvl LEVEL, s string, a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().TimestampIf().Hooks().Msgf(s, a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Print simply prints provided arguments | 
					
						
							|  |  |  | func (l *Logger) Print(a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().Hooks().Msg(a...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Printf simply prints provided the provided format string and arguments | 
					
						
							|  |  |  | func (l *Logger) Printf(s string, a ...interface{}) { | 
					
						
							|  |  |  | 	l.Entry().Hooks().Msgf(s, a...) | 
					
						
							|  |  |  | } |