// Copyright (C) 2022 NHR@FAU, University Erlangen-Nuremberg. // All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package log import ( "fmt" "io" "log" "os" "time" ) // Provides a simple way of logging with different levels. // Time/Date are not logged because systemd adds // them for us (Default, can be changed by flag '--logdate true'). // // Uses these prefixes: https://www.freedesktop.org/software/systemd/man/sd-daemon.html var logDateTime bool var logLevel string var ( DebugWriter io.Writer = os.Stderr NoteWriter io.Writer = os.Stderr InfoWriter io.Writer = os.Stderr WarnWriter io.Writer = os.Stderr ErrWriter io.Writer = os.Stderr CritWriter io.Writer = os.Stderr ) var ( DebugPrefix string = "<7>[DEBUG] " InfoPrefix string = "<6>[INFO] " NotePrefix string = "<5>[NOTICE] " WarnPrefix string = "<4>[WARNING] " ErrPrefix string = "<3>[ERROR] " CritPrefix string = "<2>[CRITICAL] " ) var ( // No Time/Date DebugLog *log.Logger = log.New(DebugWriter, DebugPrefix, 0) InfoLog *log.Logger = log.New(InfoWriter, InfoPrefix, 0) NoteLog *log.Logger = log.New(NoteWriter, NotePrefix, log.Lshortfile) WarnLog *log.Logger = log.New(WarnWriter, WarnPrefix, log.Lshortfile) ErrLog *log.Logger = log.New(ErrWriter, ErrPrefix, log.Llongfile) CritLog *log.Logger = log.New(CritWriter, CritPrefix, log.Llongfile) // Log Time/Date DebugTimeLog *log.Logger = log.New(DebugWriter, DebugPrefix, log.LstdFlags) InfoTimeLog *log.Logger = log.New(InfoWriter, InfoPrefix, log.LstdFlags) NoteTimeLog *log.Logger = log.New(NoteWriter, NotePrefix, log.LstdFlags|log.Lshortfile) WarnTimeLog *log.Logger = log.New(WarnWriter, WarnPrefix, log.LstdFlags|log.Lshortfile) ErrTimeLog *log.Logger = log.New(ErrWriter, ErrPrefix, log.LstdFlags|log.Llongfile) CritTimeLog *log.Logger = log.New(CritWriter, CritPrefix, log.LstdFlags|log.Llongfile) ) /* CONFIG */ func SetLogLevel(lvl string) { // fmt.Printf("pkg/log: Set LOGLEVEL -> %s\n", lvl) switch lvl { case "crit": ErrWriter = io.Discard fallthrough case "err", "fatal": WarnWriter = io.Discard fallthrough case "warn": InfoWriter = io.Discard fallthrough case "notice": NoteWriter = io.Discard fallthrough case "info": DebugWriter = io.Discard break case "debug": // Nothing to do... break default: fmt.Printf("pkg/log: Flag 'loglevel' has invalid value %#v\npkg/log: Will use default loglevel 'debug'\n", lvl) SetLogLevel("debug") } } func SetLogDateTime(logdate bool) { //fmt.Printf("pkg/log: Set DATEBOOL -> %v\n", logdate) logDateTime = logdate } /* PRINT */ // Private helper func printStr(v ...interface{}) string { return fmt.Sprint(v...) } // Uses Info() -> If errorpath required at some point: // Will need own writer with 'Output(2, out)' to correctly render path func Print(v ...interface{}) { Info(v...) } func Debug(v ...interface{}) { if DebugWriter != io.Discard { out := printStr(v...) if logDateTime { DebugTimeLog.Output(2, out) } else { DebugLog.Output(2, out) } } } func Info(v ...interface{}) { if InfoWriter != io.Discard { out := printStr(v...) if logDateTime { InfoTimeLog.Output(2, out) } else { InfoLog.Output(2, out) } } } func Note(v ...interface{}) { if NoteWriter != io.Discard { out := printStr(v...) if logDateTime { NoteTimeLog.Output(2, out) } else { NoteLog.Output(2, out) } } } func Warn(v ...interface{}) { if WarnWriter != io.Discard { out := printStr(v...) if logDateTime { WarnTimeLog.Output(2, out) } else { WarnLog.Output(2, out) } } } func Error(v ...interface{}) { if ErrWriter != io.Discard { out := printStr(v...) if logDateTime { ErrTimeLog.Output(2, out) } else { ErrLog.Output(2, out) } } } // Writes panic stacktrace, but keeps application alive func Panic(v ...interface{}) { if ErrWriter != io.Discard { out := printStr(v...) if logDateTime { ErrTimeLog.Output(2, out) } else { ErrLog.Output(2, out) } } panic("Panic triggered ...") } func Crit(v ...interface{}) { if CritWriter != io.Discard { out := printStr(v...) if logDateTime { CritTimeLog.Output(2, out) } else { CritLog.Output(2, out) } } } // Writes critical log, stops application func Fatal(v ...interface{}) { if CritWriter != io.Discard { out := printStr(v...) if logDateTime { CritTimeLog.Output(2, out) } else { CritLog.Output(2, out) } } os.Exit(1) } /* PRINT FORMAT*/ // Private helper func printfStr(format string, v ...interface{}) string { return fmt.Sprintf(format, v...) } // Uses Infof() -> If errorpath required at some point: // Will need own writer with 'Output(2, out)' to correctly render path func Printf(format string, v ...interface{}) { Infof(format, v...) } func Debugf(format string, v ...interface{}) { if DebugWriter != io.Discard { out := printfStr(format, v...) if logDateTime { DebugTimeLog.Output(2, out) } else { DebugLog.Output(2, out) } } } func Infof(format string, v ...interface{}) { if InfoWriter != io.Discard { out := printfStr(format, v...) if logDateTime { InfoTimeLog.Output(2, out) } else { InfoLog.Output(2, out) } } } func Notef(format string, v ...interface{}) { if NoteWriter != io.Discard { out := printfStr(format, v...) if logDateTime { NoteTimeLog.Output(2, out) } else { NoteLog.Output(2, out) } } } func Warnf(format string, v ...interface{}) { if WarnWriter != io.Discard { out := printfStr(format, v...) if logDateTime { WarnTimeLog.Output(2, out) } else { WarnLog.Output(2, out) } } } func Errorf(format string, v ...interface{}) { if ErrWriter != io.Discard { out := printfStr(format, v...) if logDateTime { ErrTimeLog.Output(2, out) } else { ErrLog.Output(2, out) } } } // Writes panic stacktrace, but keeps application alive func Panicf(format string, v ...interface{}) { if ErrWriter != io.Discard { out := printfStr(format, v...) if logDateTime { ErrTimeLog.Output(2, out) } else { ErrLog.Output(2, out) } } panic("Panic triggered ...") } func Critf(format string, v ...interface{}) { if CritWriter != io.Discard { out := printfStr(format, v...) if logDateTime { CritTimeLog.Output(2, out) } else { CritLog.Output(2, out) } } } // Writes crit log, stops application func Fatalf(format string, v ...interface{}) { if CritWriter != io.Discard { out := printfStr(format, v...) if logDateTime { CritTimeLog.Output(2, out) } else { CritLog.Output(2, out) } } os.Exit(1) } /* SPECIAL */ func Finfof(w io.Writer, format string, v ...interface{}) { if w != io.Discard { if logDateTime { currentTime := time.Now() fmt.Fprintf(InfoWriter, currentTime.String()+InfoPrefix+format+"\n", v...) } else { fmt.Fprintf(InfoWriter, InfoPrefix+format+"\n", v...) } } }