158 lines
3.9 KiB
Go
158 lines
3.9 KiB
Go
package logger
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
// provided for testing
|
|
var osExit = os.Exit
|
|
|
|
type LogOutput interface {
|
|
WriteLogLine([]byte)
|
|
}
|
|
|
|
// OutputManager is used to sync data of Output
|
|
type OutputManager interface {
|
|
Append([]byte, LogOutput)
|
|
Shutdown()
|
|
}
|
|
|
|
// Service is the logging service that is either a group or single log writer
|
|
type Service interface {
|
|
Error(message string)
|
|
Info(message string)
|
|
Debug(message string)
|
|
Fatal(message string)
|
|
|
|
Errorf(format string, args ...interface{})
|
|
Infof(format string, args ...interface{})
|
|
Debugf(format string, args ...interface{})
|
|
Fatalf(format string, args ...interface{})
|
|
|
|
Add(writer io.Writer, formatter Formatter, levels ...Level)
|
|
}
|
|
|
|
type sourceGroup struct {
|
|
writer io.Writer
|
|
formatter Formatter
|
|
levelsSupported []Level
|
|
}
|
|
|
|
func (s *sourceGroup) WriteLogLine(data []byte) {
|
|
_, _ = s.writer.Write(data)
|
|
}
|
|
|
|
func (s *sourceGroup) supportsLevel(l Level) bool {
|
|
for _, level := range s.levelsSupported {
|
|
if l == level {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// OutputWriter is the standard logging implementation
|
|
type OutputWriter struct {
|
|
groups []*sourceGroup
|
|
syncWriter OutputManager
|
|
minLevel Level
|
|
}
|
|
|
|
// NewOutputWriter creates a new logger
|
|
func NewOutputWriter(syncWriter OutputManager) *OutputWriter {
|
|
return &OutputWriter{
|
|
syncWriter: syncWriter,
|
|
groups: nil,
|
|
minLevel: FatalLevel,
|
|
}
|
|
}
|
|
|
|
// Add a writer and formatter to output to
|
|
func (s *OutputWriter) Add(writer io.Writer, formatter Formatter, levels ...Level) {
|
|
s.groups = append(s.groups, &sourceGroup{writer: writer, formatter: formatter, levelsSupported: levels})
|
|
|
|
// track most verbose (lowest) level we need to output
|
|
for _, level := range levels {
|
|
if level < s.minLevel {
|
|
s.minLevel = level
|
|
}
|
|
}
|
|
}
|
|
|
|
// Error writes an error to the logging sources
|
|
func (s *OutputWriter) Error(message string) {
|
|
if s.minLevel <= ErrorLevel {
|
|
s.output(ErrorLevel, message)
|
|
}
|
|
}
|
|
|
|
// Info writes an info string to the logging sources
|
|
func (s *OutputWriter) Info(message string) {
|
|
if s.minLevel <= InfoLevel {
|
|
s.output(InfoLevel, message)
|
|
}
|
|
}
|
|
|
|
// Debug writes a debug string to the logging sources
|
|
func (s *OutputWriter) Debug(message string) {
|
|
if s.minLevel <= DebugLevel {
|
|
s.output(DebugLevel, message)
|
|
}
|
|
}
|
|
|
|
// Fatal writes a error string to the logging sources and runs does an os.exit()
|
|
func (s *OutputWriter) Fatal(message string) {
|
|
s.output(FatalLevel, message)
|
|
s.syncWriter.Shutdown() // waits for the pending logging to finish
|
|
osExit(1)
|
|
}
|
|
|
|
// Errorf writes a formatted error to the logging sources
|
|
func (s *OutputWriter) Errorf(format string, args ...interface{}) {
|
|
if s.minLevel <= ErrorLevel {
|
|
s.output(ErrorLevel, fmt.Sprintf(format, args...))
|
|
}
|
|
}
|
|
|
|
// Infof writes a formatted info statement to the logging sources
|
|
func (s *OutputWriter) Infof(format string, args ...interface{}) {
|
|
if s.minLevel <= InfoLevel {
|
|
s.output(InfoLevel, fmt.Sprintf(format, args...))
|
|
}
|
|
}
|
|
|
|
// Debugf writes a formatted debug statement to the logging sources
|
|
func (s *OutputWriter) Debugf(format string, args ...interface{}) {
|
|
if s.minLevel <= DebugLevel {
|
|
s.output(DebugLevel, fmt.Sprintf(format, args...))
|
|
}
|
|
}
|
|
|
|
// Fatalf writes a writes a formatted error statement and runs does an os.exit()
|
|
func (s *OutputWriter) Fatalf(format string, args ...interface{}) {
|
|
s.output(FatalLevel, fmt.Sprintf(format, args...))
|
|
s.syncWriter.Shutdown() // waits for the pending logging to finish
|
|
osExit(1)
|
|
}
|
|
|
|
// output does the actual write to the sync manager
|
|
func (s *OutputWriter) output(l Level, content string) {
|
|
now := time.Now()
|
|
for _, group := range s.groups {
|
|
if group.supportsLevel(l) {
|
|
logLine := fmt.Sprintf("%s%s\n", group.formatter.Timestamp(l, now),
|
|
group.formatter.Content(l, content))
|
|
s.syncWriter.Append([]byte(logLine), group)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write implements io.Writer to support SetOutput of the log package
|
|
func (s *OutputWriter) Write(p []byte) (n int, err error) {
|
|
s.Info(string(p))
|
|
return len(p), nil
|
|
}
|