logger.go 3.2 KB
/*
Handle the applications logging needs/

Authors:
Georg Hopp <georg@steffers.org>

Changes:
2018-10-02 [Georg Hopp] File created.

Copyright © 2018 Georg Hopp

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package logger

import (
	"encoding/json"
	"fmt"
	"os"
	"time"
)

type Severity int

const (
	DEBUG Severity = iota
	INFO
	WARNING
	ERROR
	FATAL
)

var (
	SevStrings = [...]string{
		"DEBUG",
		"INFO",
		"WARNING",
		"ERROR",
		"FATAL",
	}
)

type Logger struct {
	logLevel Severity
	name     string
}

var Default = GetLogger(INFO, "default")

func GetLogger(sev Severity, name string) *Logger {
	logger := Logger{sev, name}
	return &logger
}

func SevStringToSeverity(sevStr string) (sev Severity) {
	switch sevStr {
	case SevStrings[DEBUG]:
		sev = DEBUG
	case SevStrings[INFO]:
		sev = INFO
	case SevStrings[WARNING]:
		sev = WARNING
	case SevStrings[FATAL]:
		sev = FATAL
	case SevStrings[ERROR]:
		fallthrough
	default:
		sev = ERROR
	}
	return
}

func SeverityToSevString(sev Severity) string {
	return SevStrings[sev]
}

func (logger *Logger) SetLevel(level Severity) {
	logger.logLevel = level
}

func (logger *Logger) logToJson(
	sev Severity, format string, args ...interface{}) string {

	message, err := json.Marshal(
		logMessage{
			time.Now().UTC().Format(time.RFC3339),
			logger.name,
			sev,
			fmt.Sprintf(format, args...),
		})
	if err != nil {
		// TODO Making it fatal if no logging can be done is
		// kind of drastic
		os.Exit(1)
	}
	return string(message[:])
}

func (logger *Logger) log(sev Severity, format string, args ...interface{}) {

	var output *os.File

	if sev >= ERROR {
		output = os.Stderr
	} else {
		output = os.Stdout
	}

	if sev >= logger.logLevel {
		fmt.Fprintln(output, logger.logToJson(sev, format, args...))
	}
}

func (logger *Logger) Debug(format string, args ...interface{}) {
	logger.log(DEBUG, format, args...)
}

func (logger *Logger) Info(format string, args ...interface{}) {
	logger.log(INFO, format, args...)
}

func (logger *Logger) Warning(format string, args ...interface{}) {
	logger.log(WARNING, format, args...)
}

func (logger *Logger) Error(format string, args ...interface{}) {
	logger.log(ERROR, format, args...)
}

func (logger *Logger) Panic(format string, args ...interface{}) {
	logger.log(FATAL, format, args...)
	panic(fmt.Sprintf(format, args...))
}

func (logger *Logger) LogError(
	err error, format string, args ...interface{}) {

	if err != nil {
		logger.Error("%s: %s", fmt.Sprintf(format, args...), err)
	}
}

func (logger *Logger) FailOnError(
	err error, format string, args ...interface{}) {

	if err != nil {
		logger.Panic("%s: %s", fmt.Sprintf(format, args...), err)
	}
}

// vim: ts=4 sts=4 sw=4 noet tw=72: