ntfy/log/log.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

207 lines
4.8 KiB
Go
Raw Normal View History

2022-05-30 14:14:14 +12:00
package log
import (
2023-02-06 17:34:27 +13:00
"io"
2022-05-30 14:14:14 +12:00
"log"
2023-02-06 17:34:27 +13:00
"os"
"strings"
2022-06-02 08:57:35 +12:00
"sync"
2023-02-06 17:34:27 +13:00
"time"
)
2023-02-06 17:53:24 +13:00
// Defaults for package level variables
var (
2023-02-06 17:34:27 +13:00
DefaultLevel = InfoLevel
DefaultFormat = TextFormat
DefaultOutput = &peekLogWriter{os.Stderr}
2022-05-30 14:14:14 +12:00
)
2023-02-04 16:21:50 +13:00
var (
2023-02-06 17:53:24 +13:00
level = DefaultLevel
format = DefaultFormat
overrides = make(map[string][]*levelOverride)
2023-02-06 17:53:24 +13:00
output io.Writer = DefaultOutput
filename = ""
2023-02-10 13:45:02 +13:00
mu = &sync.RWMutex{}
2023-02-06 17:34:27 +13:00
)
// init sets the default log output (including log.SetOutput)
//
// This has to be explicitly called, because DefaultOutput is a peekLogWriter,
// which wraps os.Stderr.
func init() {
SetOutput(DefaultOutput)
}
2023-02-04 16:21:50 +13:00
// Fatal prints the given message, and exits the program
func Fatal(message string, v ...any) {
newEvent().Fatal(message, v...)
2022-05-30 14:14:14 +12:00
}
2023-02-04 16:21:50 +13:00
// Error prints the given message, if the current log level is ERROR or lower
func Error(message string, v ...any) {
newEvent().Error(message, v...)
}
2022-05-30 14:14:14 +12:00
2023-02-04 16:21:50 +13:00
// Warn prints the given message, if the current log level is WARN or lower
func Warn(message string, v ...any) {
newEvent().Warn(message, v...)
}
// Info prints the given message, if the current log level is INFO or lower
func Info(message string, v ...any) {
newEvent().Info(message, v...)
2022-06-02 15:24:44 +12:00
}
// Debug prints the given message, if the current log level is DEBUG or lower
2022-10-02 09:31:48 +13:00
func Debug(message string, v ...any) {
2023-02-04 16:21:50 +13:00
newEvent().Debug(message, v...)
2022-05-30 14:14:14 +12:00
}
2023-02-04 16:21:50 +13:00
// Trace prints the given message, if the current log level is TRACE
func Trace(message string, v ...any) {
newEvent().Trace(message, v...)
2022-05-30 14:14:14 +12:00
}
2023-02-06 17:34:27 +13:00
// With creates a new log event and adds the fields of the given Contexter structs
func With(contexts ...Contexter) *Event {
return newEvent().With(contexts...)
2022-05-30 14:14:14 +12:00
}
2023-02-06 17:34:27 +13:00
// Field creates a new log event and adds a custom field and value to it
2023-02-04 16:21:50 +13:00
func Field(key string, value any) *Event {
return newEvent().Field(key, value)
2022-05-30 14:14:14 +12:00
}
2023-02-06 17:34:27 +13:00
// Fields creates a new log event and adds a map of fields to it
func Fields(fields Context) *Event {
2023-02-04 16:21:50 +13:00
return newEvent().Fields(fields)
}
2023-02-06 17:34:27 +13:00
// Tag creates a new log event and adds a "tag" field to it
2023-02-04 16:21:50 +13:00
func Tag(tag string) *Event {
return newEvent().Tag(tag)
2022-05-30 14:14:14 +12:00
}
2023-02-06 17:34:27 +13:00
// Time creates a new log event and sets the time field
func Time(time time.Time) *Event {
return newEvent().Time(time)
}
2023-02-10 09:24:12 +13:00
// Timing runs f and records the time if took to execute it in "time_taken_ms"
func Timing(f func()) *Event {
return newEvent().Timing(f)
}
2022-06-02 08:57:35 +12:00
// CurrentLevel returns the current log level
func CurrentLevel() Level {
2023-02-10 13:45:02 +13:00
mu.RLock()
defer mu.RUnlock()
2022-06-02 08:57:35 +12:00
return level
}
// SetLevel sets a new log level
2022-05-30 14:14:14 +12:00
func SetLevel(newLevel Level) {
2022-06-02 08:57:35 +12:00
mu.Lock()
defer mu.Unlock()
2022-05-30 14:14:14 +12:00
level = newLevel
}
2023-02-04 16:21:50 +13:00
// SetLevelOverride adds a log override for the given field
2023-02-09 16:57:10 +13:00
func SetLevelOverride(field string, value string, level Level) {
2023-02-04 16:21:50 +13:00
mu.Lock()
defer mu.Unlock()
if _, ok := overrides[field]; !ok {
overrides[field] = make([]*levelOverride, 0)
}
overrides[field] = append(overrides[field], &levelOverride{value: value, level: level})
}
2023-02-06 17:34:27 +13:00
// ResetLevelOverrides removes all log level overrides
func ResetLevelOverrides() {
2023-02-04 16:21:50 +13:00
mu.Lock()
defer mu.Unlock()
overrides = make(map[string][]*levelOverride)
2023-02-04 16:21:50 +13:00
}
2023-02-10 13:45:02 +13:00
// CurrentFormat returns the current log format
2023-02-04 16:21:50 +13:00
func CurrentFormat() Format {
2023-02-10 13:45:02 +13:00
mu.RLock()
defer mu.RUnlock()
2023-02-04 16:21:50 +13:00
return format
}
// SetFormat sets a new log format
func SetFormat(newFormat Format) {
mu.Lock()
defer mu.Unlock()
format = newFormat
if newFormat == JSONFormat {
DisableDates()
2022-05-30 14:14:14 +12:00
}
}
2023-02-06 17:34:27 +13:00
// SetOutput sets the log output writer
func SetOutput(w io.Writer) {
mu.Lock()
defer mu.Unlock()
output = &peekLogWriter{w}
if f, ok := w.(*os.File); ok {
filename = f.Name()
} else {
filename = ""
}
log.SetOutput(output)
2023-02-06 17:34:27 +13:00
}
// File returns the log file, if any, or an empty string otherwise
func File() string {
2023-02-10 13:45:02 +13:00
mu.RLock()
defer mu.RUnlock()
return filename
2023-02-06 17:34:27 +13:00
}
// IsFile returns true if the output is a non-default file
func IsFile() bool {
2023-02-10 13:45:02 +13:00
mu.RLock()
defer mu.RUnlock()
return filename != ""
2023-02-06 17:34:27 +13:00
}
2023-02-04 16:21:50 +13:00
// DisableDates disables the date/time prefix
func DisableDates() {
log.SetFlags(0)
}
2022-06-02 15:24:44 +12:00
// Loggable returns true if the given log level is lower or equal to the current log level
func Loggable(l Level) bool {
return CurrentLevel() <= l
}
// IsTrace returns true if the current log level is TraceLevel
func IsTrace() bool {
return Loggable(TraceLevel)
}
// IsDebug returns true if the current log level is DebugLevel or below
func IsDebug() bool {
return Loggable(DebugLevel)
}
// peekLogWriter is an io.Writer which will peek at the rendered log event,
// and ensure that the rendered output is valid JSON. This is a hack!
type peekLogWriter struct {
w io.Writer
}
func (w *peekLogWriter) Write(p []byte) (n int, err error) {
if len(p) == 0 || p[0] == '{' || CurrentFormat() == TextFormat {
return w.w.Write(p)
}
m := newEvent().Tag(tagStdLog).Render(InfoLevel, strings.TrimSpace(string(p)))
if m == "" {
return 0, nil
}
return w.w.Write([]byte(m + "\n"))
}