view pkg/log/log.go @ 5711:2dd155cc95ec revive-cleanup

Fix all revive issue (w/o machine generated stuff).
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 20 Feb 2024 22:22:57 +0100
parents 1222b777f51f
children 6270951dda28
line wrap: on
line source

// This is Free Software under GNU Affero General Public License v >= 3.0
// without warranty, see README.md and license for details.
//
// SPDX-License-Identifier: AGPL-3.0-or-later
// License-Filename: LICENSES/AGPL-3.0.txt
//
// Copyright (C) 2021 by via donau
//   – Österreichische Wasserstraßen-Gesellschaft mbH
// Software engineering by Intevation GmbH
//
// Author(s):
//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>

// Package log is a leveled logger used in the gemma server.
package log

import (
	"fmt"
	lg "log"
	"os"
	"strings"
	"sync"
	"sync/atomic"
)

// Level is an enumeration symbolizing a log level.
type Level uint32

const (
	// TraceLogLevel is the TRACE log level.
	TraceLogLevel = Level(iota)
	// DebugLogLevel is the DEBUG log level.
	DebugLogLevel
	// InfoLogLevel is the INFO log level.
	InfoLogLevel
	// WarnLogLevel is the WARN log level.
	WarnLogLevel
	// ErrorLogLevel is the ERROR log level.
	ErrorLogLevel
	// FatalLogLevel is the FATAL log level.
	FatalLogLevel
)

var (
	logLevel  = uint32(InfoLogLevel)
	logFileMu sync.Mutex
	logFile   *os.File
)

func init() {
	lg.SetFlags(lg.LstdFlags | lg.Lshortfile)
}

const callDepth = 2

// SetupLog redirects the log output to a given file.
// The file is opened in append mode with the given
// permisssions. A previously opened log file will
// be closed.
func SetupLog(filename string, perm os.FileMode) error {
	f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, perm)
	if err != nil {
		return err
	}
	logFileMu.Lock()
	defer logFileMu.Unlock()
	if logFile != nil {
		logFile.Close()
	}
	logFile = f
	lg.SetOutput(logFile)
	return nil
}

// ShutdownLog closes an open log file (if there is any in use)
// and redirects the output to stderr.
func ShutdownLog() {
	logFileMu.Lock()
	defer logFileMu.Unlock()
	if logFile != nil {
		logFile.Close()
		logFile = nil
	}
	lg.SetOutput(os.Stderr)
}

// ParseLogLevel converts a strings representation
// of a log level to the reprective log level.
// If the log level is unknown InfoLogLevel is
// returned.
func ParseLogLevel(s string) Level {
	switch strings.ToLower(s) {
	case "trace":
		return TraceLogLevel
	case "debug":
		return DebugLogLevel
	case "info":
		return InfoLogLevel
	case "warn":
		return WarnLogLevel
	case "error":
		return ErrorLogLevel
	case "fatal":
		return FatalLogLevel
	default:
		return InfoLogLevel
	}
}

// String implements the fmt.Stringer interface.
func (level Level) String() string {
	switch level {
	case TraceLogLevel:
		return "trace"
	case DebugLogLevel:
		return "debug"
	case InfoLogLevel:
		return "info"
	case WarnLogLevel:
		return "warn"
	case ErrorLogLevel:
		return "error"
	case FatalLogLevel:
		return "fatal"
	default:
		return "unknown"
	}
}

// GetLogLevel returns the currently active log level.
func GetLogLevel() Level {
	return Level(atomic.LoadUint32(&logLevel))
}

// SetLogLevel sets the log level to be active.
func SetLogLevel(level Level) {
	atomic.StoreUint32(&logLevel, uint32(level))
}

// Tracef formats a log message as a TRACE output.
func Tracef(f string, args ...interface{}) {
	if TraceLogLevel >= GetLogLevel() {
		s := fmt.Sprintf(f, args...)
		lg.Output(callDepth, "[TRACE] "+s)
	}
}

// Traceln line prints a log message as a TRACE output.
func Traceln(s string) {
	if TraceLogLevel >= GetLogLevel() {
		lg.Output(callDepth, "[TRACE] "+s)
	}
}

// Debugf formats a log message as a DEBUG output.
func Debugf(f string, args ...interface{}) {
	if DebugLogLevel >= GetLogLevel() {
		s := fmt.Sprintf(f, args...)
		lg.Output(callDepth, "[DEBUG] "+s)
	}
}

// Debugln line prints a log message as a DEBUG output.
func Debugln(s string) {
	if DebugLogLevel >= GetLogLevel() {
		lg.Output(callDepth, "[DEBUG] "+s)
	}
}

// Infof formats a log message as a INFO output.
func Infof(f string, args ...interface{}) {
	if InfoLogLevel >= GetLogLevel() {
		s := fmt.Sprintf(f, args...)
		lg.Output(callDepth, "[INFO] "+s)
	}
}

// Infoln line prints a log message as a INFO output.
func Infoln(s string) {
	if InfoLogLevel >= GetLogLevel() {
		lg.Output(callDepth, "[INFO] "+s)
	}
}

// Warnf formats a log message as a WARN output.
func Warnf(f string, args ...interface{}) {
	if WarnLogLevel >= GetLogLevel() {
		s := fmt.Sprintf(f, args...)
		lg.Output(callDepth, "[WARN] "+s)
	}
}

// Warnln line prints a log message as a WARN output.
func Warnln(s string) {
	if WarnLogLevel >= GetLogLevel() {
		lg.Output(callDepth, "[WARN] "+s)
	}
}

// Errorf formats a log message as an ERROR output.
func Errorf(f string, args ...interface{}) {
	if ErrorLogLevel >= GetLogLevel() {
		s := fmt.Sprintf(f, args...)
		lg.Output(callDepth, "[ERROR] "+s)
	}
}

// Errorln line prints a log message as an ERROR output.
func Errorln(s string) {
	if ErrorLogLevel >= GetLogLevel() {
		lg.Output(callDepth, "[ERROR] "+s)
	}
}

// Fatalf formats a log message as a FATAL output
// and terminates the programs with an error code (1).
func Fatalf(f string, args ...interface{}) {
	if FatalLogLevel >= GetLogLevel() {
		s := fmt.Sprintf(f, args...)
		lg.Output(callDepth, "[FATAL] "+s)
		os.Exit(1)
	}
}

// Fatalln line prints a log message as a FATAL output
// and terminates the programs with an error code (1).
func Fatalln(s string) {
	if FatalLogLevel >= GetLogLevel() {
		lg.Output(callDepth, "[FATAL] "+s)
		os.Exit(1)
	}
}

// Panicf formats a log message as a PANIC output
// and throws a panic.
func Panicf(f string, args ...interface{}) {
	s := fmt.Sprintf(f, args...)
	lg.Output(callDepth, "[PANIC] "+s)
	panic(s)
}

// Panicln line prints a log message as a PANIC output
// and throws a panic.
func Panicln(s string) {
	lg.Output(callDepth, "[PANIC] "+s)
	panic(s)
}