Skip to content
Snippets Groups Projects
Commit aad7e9a3 authored by Manuel Kieweg's avatar Manuel Kieweg
Browse files

Merge branch '25-enhanced-logging' into 'develop'

Resolve "Enhanced Logging"

See merge request cocsn/gosdn!41
parents ccf264ba 06b89cc4
No related branches found
No related tags found
2 merge requests!41Resolve "Enhanced Logging",!18Develop
Pipeline #52507 passed
...@@ -3,7 +3,12 @@ package log ...@@ -3,7 +3,12 @@ package log
import ( import (
"fmt" "fmt"
"io" "io"
"log/syslog"
"os" "os"
"reflect"
"runtime"
"strconv"
"strings"
"sync" "sync"
"time" "time"
) )
...@@ -14,22 +19,47 @@ var once sync.Once ...@@ -14,22 +19,47 @@ var once sync.Once
// Logger is a wrapper for log.Logger and provides // Logger is a wrapper for log.Logger and provides
// methods to enable and disable logging. // methods to enable and disable logging.
type Logger struct { type Logger struct {
Out io.Writer DefaultWriter io.Writer
Loglevel Level LoglevelWriter map[Level]io.Writer
lock sync.Mutex toSyslog map[Level]bool
Loglevel Level
lock sync.Mutex
builder strings.Builder
}
func (l *Logger) buildMessage(level Level, syslog bool, args ...interface{}) {
if !syslog {
l.builder.WriteString(time.Now().Format(time.RFC3339))
}
l.builder.WriteRune('\t')
l.builder.WriteString(prefix(level))
l.builder.WriteRune('\t')
function, line := callers()
functionSplitted := strings.SplitAfter(function, "/")
function = functionSplitted[len(functionSplitted)-1]
l.builder.WriteString(function)
l.builder.WriteRune(':')
l.builder.WriteString(strconv.Itoa(line))
l.builder.WriteRune('\t')
l.builder.WriteString(fmt.Sprint(args...))
l.builder.WriteRune('\n')
} }
func get() *Logger { func get() *Logger {
once.Do(func() { once.Do(func() {
logger = &Logger{ logger = &Logger{
Out: os.Stdout, DefaultWriter: os.Stderr,
Loglevel: INFO, LoglevelWriter: make(map[Level]io.Writer),
lock: sync.Mutex{}, toSyslog: make(map[Level]bool),
Loglevel: INFO,
lock: sync.Mutex{},
} }
}) })
return logger return logger
} }
//Loglevel sets the verbosity of the logger
//Defaults to INFO
func Loglevel(level Level) { func Loglevel(level Level) {
l := get() l := get()
l.lock.Lock() l.lock.Lock()
...@@ -37,48 +67,101 @@ func Loglevel(level Level) { ...@@ -37,48 +67,101 @@ func Loglevel(level Level) {
l.Loglevel = level l.Loglevel = level
} }
//Output defines the output of the logger
//Defaults to os.Stderr
func Output(out io.Writer) { func Output(out io.Writer) {
l := get() l := get()
l.lock.Lock() l.lock.Lock()
defer l.lock.Unlock() defer l.lock.Unlock()
l.Out = out l.DefaultWriter = out
}
//LoglevelOutput defines a special output
//for a certain log level
func LoglevelOutput(level Level, out io.Writer) {
l := get()
l.lock.Lock()
defer l.lock.Unlock()
l.LoglevelWriter[level] = out
if reflect.TypeOf(out) == reflect.TypeOf(&syslog.Writer{}) {
l.toSyslog[level] = true
}
} }
//Debug passes the DEBUG flag and a
//message to the logger
func Debug(args ...interface{}) { func Debug(args ...interface{}) {
log(DEBUG, args...) log(DEBUG, args...)
} }
//Debug passes the DEBUG flag and a
//message to the logger
func Info(args ...interface{}) { func Info(args ...interface{}) {
log(INFO, args...) log(INFO, args...)
} }
//Warn passes the WARNING flag and a
//message to the logger
func Warn(args ...interface{}) { func Warn(args ...interface{}) {
log(WARNING, args...) log(WARNING, args...)
} }
//Error passes the ERROR flag and a
//message to the logger
func Error(args ...interface{}) { func Error(args ...interface{}) {
log(ERROR, args...) log(ERROR, args...)
} }
//Fatal passes the FATAL flag and a
//message to the logger and calls
//os.Exit(1)
func Fatal(args ...interface{}) { func Fatal(args ...interface{}) {
log(FATAL, args...) log(FATAL, args...)
os.Exit(1)
} }
//Panic passes the PANIC flag and a
//message to the logger
//Also calls builtin.panic()
func Panic(args ...interface{}) { func Panic(args ...interface{}) {
log(PANIC, args...) log(PANIC, args...)
panic(args)
} }
func log(level Level, args ...interface{}) { func log(level Level, args ...interface{}) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
l := get() l := get()
l.lock.Lock() l.lock.Lock()
defer l.lock.Unlock() defer l.lock.Unlock()
defer l.builder.Reset()
if level <= l.Loglevel { if level <= l.Loglevel {
msg := fmt.Sprint(args...) l.buildMessage(level, l.toSyslog[level], args...)
logMessage := time.Now().Format(time.RFC3339) + "\t" + prefix(level) + "\t" + msg + "\n" msg := []byte(l.builder.String())
l.Out.Write([]byte(logMessage)) writer, ok := l.LoglevelWriter[level]
var err error
if !ok {
_, err = l.DefaultWriter.Write(msg)
} else {
_, err = writer.Write(msg)
}
if err != nil {
panic(err)
}
} }
} }
func callers() (string, int) {
pc := make([]uintptr, 15)
n := runtime.Callers(5, pc)
frames := runtime.CallersFrames(pc[:n])
frame, _ := frames.Next()
return frame.Function, frame.Line
}
func prefix(level Level) string { func prefix(level Level) string {
switch level { switch level {
case PANIC: case PANIC:
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"code.fbi.h-da.de/cocsn/gosdn/log" "code.fbi.h-da.de/cocsn/gosdn/log"
"code.fbi.h-da.de/cocsn/gosdn/nucleus" "code.fbi.h-da.de/cocsn/gosdn/nucleus"
"flag" "flag"
"log/syslog"
) )
func main() { func main() {
...@@ -17,6 +18,16 @@ func main() { ...@@ -17,6 +18,16 @@ func main() {
cliSocket := *cliListenAddr + ":" + *cliListenPort cliSocket := *cliListenAddr + ":" + *cliListenPort
log.Loglevel(log.DEBUG) log.Loglevel(log.DEBUG)
syslogWriter, err := syslog.New(syslog.LOG_ALERT, "gosdn")
defer func() {
if err := syslogWriter.Close(); err != nil {
log.Fatal(err)
}
}()
if err != nil {
log.Fatal(err)
}
log.LoglevelOutput(log.INFO, syslogWriter)
// Setup a channel to communicate if goSDN should shutdown. // Setup a channel to communicate if goSDN should shutdown.
IsRunningChannel := make(chan bool) IsRunningChannel := make(chan bool)
......
...@@ -7,10 +7,7 @@ import ( ...@@ -7,10 +7,7 @@ import (
"time" "time"
) )
/* //StartAndRun is used to start the core of the controller and any auxiliary services.
* This function is used to start the core of the controller and any auxiliary services.
*/
func StartAndRun(socket, filename string, IsRunningChannel chan bool) { func StartAndRun(socket, filename string, IsRunningChannel chan bool) {
log.Info("This is the network superintendent...") log.Info("This is the network superintendent...")
log.Info("Starting my ducks") log.Info("Starting my ducks")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment