diff --git a/awl.go b/awl.go index 3f3242a..68c770d 100644 --- a/awl.go +++ b/awl.go @@ -3,9 +3,13 @@ package main import ( "fmt" "os" + + "git.froth.zone/sam/awl/logawl" ) func main() { + logger := logawl.New() + logger.Println("Test PLEASE WORK") app := prepareCLI() err := app.Run(os.Args) if err != nil { diff --git a/cli.go b/cli.go index 76945a4..f59b880 100644 --- a/cli.go +++ b/cli.go @@ -186,7 +186,7 @@ func parseArgs(args []string) (util.Answers, error) { // TODO: Actually find where windows stuffs its dns resolvers resp.Answers.Server = "8.8.4.4" } else { - resp.Answers.Server = resolv.Servers[rand.Intn(len(resolv.Servers)-1)] + resp.Answers.Server = resolv.Servers[rand.Intn(len(resolv.Servers))] } } diff --git a/logawl/logawl.go b/logawl/logawl.go new file mode 100644 index 0000000..888d777 --- /dev/null +++ b/logawl/logawl.go @@ -0,0 +1,44 @@ +package logawl + +import "fmt" + +type Lvl int + +type Level struct { + lvl int + Prefix string +} + +func (l *Level) GetLevel(i int) (string, error) { + switch i { + case int(FatalLevel): + return "FATAL ", nil + case int(ErrorLevel): + return "ERROR ", nil + case int(InfoLevel): + return "INFO ", nil + case int(DebugLevel): + return "DEBUG ", nil + } + return "", fmt.Errorf("Invalid log level choice") +} + +var AllLevels = []Lvl{ + FatalLevel, + ErrorLevel, + InfoLevel, + DebugLevel, +} + +const ( + // Fatal logs (will call exit(1)) + FatalLevel Lvl = iota + + // Error logs + ErrorLevel + + // What is going on level + InfoLevel + // Verbose log level. + DebugLevel +) diff --git a/logawl/logger.go b/logawl/logger.go new file mode 100644 index 0000000..b0917e3 --- /dev/null +++ b/logawl/logger.go @@ -0,0 +1,113 @@ +package logawl + +import ( + "fmt" + "io" + "os" + "sync" + "sync/atomic" + "time" +) + +type Logger struct { + Mu sync.Mutex + Level Lvl + Prefix string + Out io.Writer + buf []byte + isDiscard int32 +} + +// 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, + //TODO: Make cli.go change this value when calling logawl.New() + 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(v ...any) { + if atomic.LoadInt32(&l.isDiscard) != 0 { + return + } + switch l.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 + case 2: + l.Printer(2, fmt.Sprintln(v...)) //Info level + case 3: + l.Printer(3, fmt.Sprintln(v...)) //Debug level + } + +} + +// Formats the log header as such YYYY/MM/DD HH:MM:SS (local time) +func (l *Logger) formatHeader(buf *[]byte, t time.Time, level int, line int) { + var lv Level + if logLvl, err := lv.GetLevel(level); err != nil { + fmt.Printf("Invalid log level %s. Error: %v", logLvl, err) + os.Exit(1) + } else { + *buf = append(*buf, logLvl...) + year, month, day := t.Date() + 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, ' ') + } + +} + +// Printer prints the formatted message directly to stdErr +func (l *Logger) Printer(level int, 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, level, line) + 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:]...) +}