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>
This commit is contained in:
parent
5fab5a08a7
commit
98a14b1bf8
5 changed files with 246 additions and 3 deletions
5
cli.go
5
cli.go
|
@ -133,6 +133,11 @@ func prepareCLI() *cli.App {
|
|||
Aliases: []string{"x"},
|
||||
Usage: "do a reverse lookup",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "debug",
|
||||
Usage: "enable debug logging",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
Action: doQuery,
|
||||
}
|
||||
|
|
30
logawl/doc.go
Normal file
30
logawl/doc.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
LogAwl is a package for custom logging needs
|
||||
|
||||
LogAwl extends the standard log library with support for log levels
|
||||
This is _different_ from the syslog package in the standard library because you do not define a file
|
||||
because awl is a cli utility it writes directly to std err.
|
||||
*/
|
||||
// Use the New() function to init logawl
|
||||
//
|
||||
// logger := logawl.New()
|
||||
//
|
||||
// You can call specific logging levels from your new logger using
|
||||
//
|
||||
// logger.Debug("Message to log")
|
||||
// logger.Fatal("Message to log")
|
||||
// logger.Info("Message to log")
|
||||
// logger.Error("Message to log")
|
||||
//
|
||||
// You may also set the log level on the fly with
|
||||
//
|
||||
// Logger.SetLevel(3)
|
||||
// This allows you to change the default level (Info) and prevent log messages from being posted at higher verbosity levels
|
||||
//for example if
|
||||
// Logger.SetLevel(3)
|
||||
// is not called and you call
|
||||
// Logger.Debug()
|
||||
// this runs through
|
||||
// IsLevel(level)
|
||||
// to verify if the debug log should be sent to std.Err or not based on the current expected log level
|
||||
package logawl
|
72
logawl/logawl.go
Normal file
72
logawl/logawl.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package logawl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Level int32
|
||||
type Logger struct {
|
||||
Mu sync.Mutex
|
||||
Level Level
|
||||
Prefix string
|
||||
Out io.Writer
|
||||
buf []byte
|
||||
isDiscard int32
|
||||
}
|
||||
|
||||
// Stores whatever input value is in mem address of l.level
|
||||
func (l *Logger) SetLevel(level Level) {
|
||||
atomic.StoreInt32((*int32)(&l.Level), int32(level))
|
||||
}
|
||||
|
||||
// Mostly nothing
|
||||
func (l *Logger) GetLevel() Level {
|
||||
return l.level()
|
||||
}
|
||||
|
||||
// Retrieves whatever was stored in mem address of l.level
|
||||
func (l *Logger) level() Level {
|
||||
return Level(atomic.LoadInt32((*int32)(&l.Level)))
|
||||
}
|
||||
|
||||
// Unmarshalls the int value of level for writing the header
|
||||
func (l *Logger) UnMarshalLevel(lv Level) (string, error) {
|
||||
switch lv {
|
||||
case 0:
|
||||
return "FATAL ", nil
|
||||
case 1:
|
||||
return "ERROR ", nil
|
||||
case 2:
|
||||
return "INFO ", nil
|
||||
case 3:
|
||||
return "DEBUG ", nil
|
||||
}
|
||||
return "", fmt.Errorf("Invalid log level choice")
|
||||
}
|
||||
|
||||
func (l *Logger) IsLevel(level Level) bool {
|
||||
return l.level() >= level
|
||||
}
|
||||
|
||||
var AllLevels = []Level{
|
||||
FatalLevel,
|
||||
ErrorLevel,
|
||||
InfoLevel,
|
||||
DebugLevel,
|
||||
}
|
||||
|
||||
const (
|
||||
// Fatal logs (will call exit(1))
|
||||
FatalLevel Level = iota
|
||||
|
||||
// Error logs
|
||||
ErrorLevel
|
||||
|
||||
// What is going on level
|
||||
InfoLevel
|
||||
// Verbose log level.
|
||||
DebugLevel
|
||||
)
|
130
logawl/logger.go
Normal file
130
logawl/logger.go
Normal file
|
@ -0,0 +1,130 @@
|
|||
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...)
|
||||
}
|
12
query.go
12
query.go
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"git.froth.zone/sam/awl/logawl"
|
||||
"git.froth.zone/sam/awl/query"
|
||||
"git.froth.zone/sam/awl/util"
|
||||
"github.com/miekg/dns"
|
||||
|
@ -19,15 +20,20 @@ func doQuery(c *cli.Context) error {
|
|||
err error
|
||||
resp util.Response
|
||||
isHTTPS bool
|
||||
Logger = logawl.New() //init logger
|
||||
)
|
||||
|
||||
resp.Answers, err = parseArgs(c.Args().Slice())
|
||||
if err != nil {
|
||||
Logger.Error("Unable to parse args")
|
||||
return err
|
||||
}
|
||||
|
||||
port := c.Int("port")
|
||||
if c.Bool("debug") {
|
||||
Logger.SetLevel(3)
|
||||
}
|
||||
|
||||
Logger.Debug("Starting awl")
|
||||
// If port is not set, set it
|
||||
if port == 0 {
|
||||
if c.Bool("tls") || c.Bool("quic") {
|
||||
|
@ -67,8 +73,6 @@ func doQuery(c *cli.Context) error {
|
|||
|
||||
msg.SetQuestion(resp.Answers.Name, resp.Answers.Request)
|
||||
|
||||
// TODO: maybe not make this a gross chunk of if statements? who knows
|
||||
|
||||
// Make this authoritative (does this do anything?)
|
||||
if c.Bool("aa") {
|
||||
msg.Authoritative = true
|
||||
|
@ -79,6 +83,7 @@ func doQuery(c *cli.Context) error {
|
|||
}
|
||||
// Set the zero flag if requested (does nothing)
|
||||
if c.Bool("z") {
|
||||
Logger.Debug("Setting message to zero")
|
||||
msg.Zero = true
|
||||
}
|
||||
// Disable DNSSEC validation
|
||||
|
@ -95,6 +100,7 @@ func doQuery(c *cli.Context) error {
|
|||
}
|
||||
// Set DNSSEC if requested
|
||||
if c.Bool("dnssec") {
|
||||
Logger.Debug("Using DNSSEC")
|
||||
msg.SetEdns0(1232, true)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue