-
Notifications
You must be signed in to change notification settings - Fork 0
/
log.go
162 lines (143 loc) · 4.75 KB
/
log.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// log.go
//
// Copyright (C) 2023-2024 Holger de Carne
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
// Package log provides functionality for easy usage of the [github.com/rs/zerolog] logging framework.
package log
import (
"io"
"log"
"sync"
"time"
"github.com/hdecarne-github/go-log/console"
"github.com/hdecarne-github/go-log/file"
"github.com/hdecarne-github/go-log/syslog"
"github.com/rs/zerolog"
)
var defaultLogger = newDefaultLogger(console.NewDefaultWriter())
var defaultLevel = zerolog.InfoLevel
var defaultTimeFieldFormat = time.RFC3339
var rootLogger = defaultLogger
var rootLoggerMutex sync.RWMutex
func newDefaultLogger(w io.Writer) *zerolog.Logger {
return NewLogger(w, true)
}
// NewLogger creates a new [github.com/rs/zerolog.Logger] for the given options.
func NewLogger(w io.Writer, timestamp bool) *zerolog.Logger {
logger := zerolog.New(w)
if timestamp {
logger = logger.With().Timestamp().Logger()
}
return &logger
}
// RootLogger gets the current root logger.
func RootLogger() *zerolog.Logger {
rootLoggerMutex.RLock()
defer rootLoggerMutex.RUnlock()
return rootLogger
}
// ResetRootLogger resets the root logger to it's default.
func ResetRootLogger() *zerolog.Logger {
return SetRootLogger(defaultLogger, defaultLevel, defaultTimeFieldFormat)
}
// SetRootLogger sets a new root logger as well as log level and time field format.
func SetRootLogger(logger *zerolog.Logger, level zerolog.Level, timeFieldFormat string) *zerolog.Logger {
rootLoggerMutex.Lock()
defer rootLoggerMutex.Unlock()
if rootLogger != logger {
previousRootLogger := rootLogger
rootLogger = logger
if previousRootLogger == defaultLogger {
rootLogger.Info().Msg("root logger set")
} else {
rootLogger.Info().Msg("root logger re-set")
}
}
log.SetFlags(0)
log.SetOutput(rootLogger)
setLevel(level)
setTimeFieldFormat(timeFieldFormat)
return rootLogger
}
// Config provides a plugable interface for runtime logging configuration.
type Config interface {
// Logger creates the [github.com/rs/zerolog.Logger]
Logger() *zerolog.Logger
// Level gets the global log level to use.
Level() zerolog.Level
// TimeFieldFormat gets the time field format to use.
TimeFieldFormat() string
}
// SetRootLoggerFromConfig sets a new root logger as well as log level and time field format using a [github.com/hdecarne-github/go-log/Config] interface.
func SetRootLoggerFromConfig(config Config) *zerolog.Logger {
return SetRootLogger(config.Logger(), config.Level(), config.TimeFieldFormat())
}
// SetLevel sets the log level.
func SetLevel(level zerolog.Level) {
rootLoggerMutex.Lock()
defer rootLoggerMutex.Unlock()
setLevel(level)
}
func setLevel(level zerolog.Level) {
previousLevel := zerolog.GlobalLevel()
if previousLevel != level {
zerolog.SetGlobalLevel(level)
rootLogger.Info().Msgf("adjusting log level '%s' -> '%s'", previousLevel, level)
}
}
// SetTimeFieldFormat sets the time field format.
func SetTimeFieldFormat(timeFieldFormat string) {
rootLoggerMutex.Lock()
defer rootLoggerMutex.Unlock()
setTimeFieldFormat(timeFieldFormat)
}
func setTimeFieldFormat(timeFieldFormat string) {
previousTimeFieldFormat := zerolog.TimeFieldFormat
if previousTimeFieldFormat != timeFieldFormat {
zerolog.TimeFieldFormat = timeFieldFormat
rootLogger.Info().Msgf("adjusting time field format '%s' -> '%s'", previousTimeFieldFormat, timeFieldFormat)
}
}
// YAMLConfig supports a YAML file based logging configuration.
type YAMLConfig struct {
LevelOption string `yaml:"level"`
TimestampOption bool `yaml:"timestamp"`
TimeFieldFormatOption string `yaml:"timeFieldFormat"`
Console console.YAMLConsoleConfig `yaml:"console"`
File file.YAMLFileConfig `yaml:"file"`
Syslog syslog.YAMLSyslogConfig `yaml:"syslog"`
}
func (config *YAMLConfig) Logger() *zerolog.Logger {
writers := make([]io.Writer, 0)
if config.Console.EnabledOption {
writers = append(writers, config.Console.NewWriter())
}
if config.File.EnabledOption {
writers = append(writers, config.File.NewWriter())
}
if config.Syslog.EnabledOption {
writers = append(writers, config.Syslog.NewWriter())
}
var logger *zerolog.Logger
switch len(writers) {
case 0:
logger = defaultLogger
case 1:
logger = NewLogger(writers[0], config.TimestampOption)
default:
logger = NewLogger(zerolog.MultiLevelWriter(writers...), config.TimestampOption)
}
return logger
}
func (config *YAMLConfig) Level() zerolog.Level {
level, err := zerolog.ParseLevel(config.LevelOption)
if err != nil {
return zerolog.WarnLevel
}
return level
}
func (config *YAMLConfig) TimeFieldFormat() string {
return config.TimeFieldFormatOption
}