awl/logawl/logger.go
grumbulon 98a14b1bf8 Merge logawl package into master (#10)
This PR is to bring in the new logging package for awl, I wanted to do some refinements before I opened this to upstream

logawl works in the following ways

1. It prints logs directly to std.err
1. The default log level is Info (this can be changed multiple ways)
1. It supports four log levels Error, Fatal, Info, Debug
1. It differs from the syslog package in the stdlib wherin it default to std.err you do not _need_ to define an out file (syslog for example)
1. I added a "debug" flag so now we can go through and define verbose logging through the app
5.5 I made it so we can call `Logger.debug("message")` anywhere in the query file but unless the debug flag is set to true it will not print a message (it is working as intended finally).

Co-authored-by: grumbulon <grumbulon@dismail.de>
Reviewed-on: sam/awl#10
Co-authored-by: grumbulon <grumbulon@grumbulon.xyz>
Co-committed-by: grumbulon <grumbulon@grumbulon.xyz>
2022-06-29 22:57:03 +00:00

130 lines
3.2 KiB
Go

package logawl
import (
"fmt"
"os"
"sync/atomic"
"time"
)
// Calling New instantiates Logger
//
// Level can be changed to one of the other log levels (FatalLevel, ErrorLevel, InfoLevel, DebugLevel)
func New() *Logger {
return &Logger{
Out: os.Stderr,
Level: InfoLevel, //Default value is InfoLevel
}
}
// Takes any and prints it out to Logger -> Out (io.Writer (default is std.Err))
func (l *Logger) Println(level Level, v ...any) {
if atomic.LoadInt32(&l.isDiscard) != 0 {
return
}
//If verbose is not set --debug etc print _nothing_
if l.IsLevel(level) {
switch level { //Goes through log levels and does stuff based on them (Fatal os.Exit...etc)
case 0:
l.Printer(0, fmt.Sprintln(v...)) //Fatal level
os.Exit(1)
case 1:
l.Printer(1, fmt.Sprintln(v...)) //Error level
os.Exit(2)
case 2:
l.Printer(2, fmt.Sprintln(v...)) //Info level
case 3:
l.Printer(3, fmt.Sprintln(v...)) //Debug level
default:
break
}
}
}
// Formats the log header as such <LogLevel> YYYY/MM/DD HH:MM:SS (local time) <the message to log>
func (l *Logger) formatHeader(buf *[]byte, t time.Time, line int, level Level) {
if lvl, err := l.UnMarshalLevel(level); err == nil {
// This is ugly but functional
// maybe there can be an append func or something in the future
*buf = append(*buf, lvl...)
year, month, day := t.Date()
*buf = append(*buf, '[')
formatter(buf, year, 4)
*buf = append(*buf, '/')
formatter(buf, int(month), 2)
*buf = append(*buf, '/')
formatter(buf, day, 2)
*buf = append(*buf, ' ')
hour, min, sec := t.Clock()
formatter(buf, hour, 2)
*buf = append(*buf, ':')
formatter(buf, min, 2)
*buf = append(*buf, ':')
formatter(buf, sec, 2)
*buf = append(*buf, ']')
*buf = append(*buf, ':')
*buf = append(*buf, ' ')
} else {
fmt.Printf("Unable to unmarshal log level: %v", err)
os.Exit(2) //Fucking kill him
}
}
// Printer prints the formatted message directly to stdErr
func (l *Logger) Printer(level Level, s string) error {
now := time.Now()
var line int
l.Mu.Lock()
defer l.Mu.Unlock()
l.buf = l.buf[:0]
l.formatHeader(&l.buf, now, line, level)
l.buf = append(l.buf, s...)
if len(s) == 0 || s[len(s)-1] != '\n' {
l.buf = append(l.buf, '\n')
}
_, err := l.Out.Write(l.buf)
return err
}
// Some line formatting stuff from Golang log stdlib file
//
// Please view https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/log/log.go;drc=41e1d9075e428c2fc32d966b3752a3029b620e2c;l=96
//
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
func formatter(buf *[]byte, i int, wid int) {
// Assemble decimal in reverse order.
var b [20]byte
bp := len(b) - 1
for i >= 10 || wid > 1 {
wid--
q := i / 10
b[bp] = byte('0' + i - q*10)
bp--
i = q
}
// i < 10
b[bp] = byte('0' + i)
*buf = append(*buf, b[bp:]...)
}
// Call print directly with Debug level
func (l *Logger) Debug(v ...any) {
l.Println(DebugLevel, v...)
}
// Call print directly with Info level
func (l *Logger) Info(v ...any) {
l.Println(InfoLevel, v...)
}
// Call print directly with Error level
func (l *Logger) Error(v ...any) {
l.Println(ErrorLevel, v...)
}
// Call print directly with Fatal level
func (l *Logger) Fatal(v ...any) {
l.Println(FatalLevel, v...)
}