FILE / ScuroNeko/SNekLog
logger.go
Исходный файл и его история в репозитории.
- rename package to sneklog and move module to /v2 - replace text output flags with writer formatters - remove external color dependencies - update migration notes and coverage
184 lines
4.5 KiB
Go
184 lines
4.5 KiB
Go
package sneklog
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
type replacer struct {
|
|
old string
|
|
new string
|
|
}
|
|
|
|
func (r replacer) replace(s string) string {
|
|
return strings.ReplaceAll(s, r.old, r.new)
|
|
}
|
|
|
|
// Logger routes log records to one or more configured writers.
|
|
type Logger struct {
|
|
prefix string
|
|
level LogLevel
|
|
writers []LoggerWriter
|
|
replacers []replacer
|
|
|
|
jsonPretty bool
|
|
}
|
|
|
|
// LogLevel describes a logging severity.
|
|
type LogLevel struct {
|
|
n uint8
|
|
t string
|
|
fg FgColor
|
|
bg BgColor
|
|
}
|
|
|
|
// GetName returns the lowercase textual representation of the level.
|
|
func (l *LogLevel) GetName() string { return l.t }
|
|
func (l *LogLevel) GetFgColor() FgColor { return l.fg }
|
|
func (l *LogLevel) SetFgColor(color FgColor) *LogLevel {
|
|
l.fg = color
|
|
return l
|
|
}
|
|
func (l *LogLevel) GetBgColor() BgColor { return l.bg }
|
|
func (l *LogLevel) SetBgColor(color BgColor) *LogLevel {
|
|
l.bg = color
|
|
return l
|
|
}
|
|
|
|
// MethodTraceback describes a single stack frame attached to a log entry.
|
|
type MethodTraceback struct {
|
|
Method string `json:"method"`
|
|
Filename string `json:"filename"`
|
|
Line int `json:"line"`
|
|
Signature string `json:"signature"`
|
|
FullPath string `json:"fullPath"`
|
|
}
|
|
|
|
// Predefined log levels.
|
|
var (
|
|
INFO = LogLevel{n: 0, t: "info", fg: FgWhite}
|
|
WARN = LogLevel{n: 1, t: "warn", fg: FgHiYellow}
|
|
ERROR = LogLevel{n: 2, t: "error", fg: FgHiRed}
|
|
FATAL = LogLevel{n: 3, t: "fatal", fg: FgRed}
|
|
DEBUG = LogLevel{n: 4, t: "debug", fg: FgGreen}
|
|
)
|
|
|
|
// CreateLogger creates a logger with default settings.
|
|
func CreateLogger() *Logger {
|
|
return &Logger{
|
|
prefix: "LOG",
|
|
level: FATAL,
|
|
}
|
|
}
|
|
|
|
// Prefix sets the record prefix and returns the logger for chaining.
|
|
func (l *Logger) Prefix(prefix string) *Logger {
|
|
l.prefix = prefix
|
|
return l
|
|
}
|
|
|
|
// Level sets the maximum enabled level and returns the logger for chaining.
|
|
func (l *Logger) Level(level LogLevel) *Logger {
|
|
l.level = level
|
|
return l
|
|
}
|
|
|
|
// JsonPretty enables indented JSON output for JSON writers.
|
|
func (l *Logger) JsonPretty(b bool) *Logger {
|
|
l.jsonPretty = b
|
|
return l
|
|
}
|
|
|
|
// AddWriters appends multiple writers to the logger.
|
|
func (l *Logger) AddWriters(writers ...LoggerWriter) *Logger {
|
|
l.writers = append(l.writers, writers...)
|
|
return l
|
|
}
|
|
|
|
// AddWriter appends a single writer to the logger.
|
|
func (l *Logger) AddWriter(writer LoggerWriter) *Logger {
|
|
l.writers = append(l.writers, writer)
|
|
return l
|
|
}
|
|
|
|
// AddReplacer appends a message replacer and returns the logger for chaining.
|
|
//
|
|
// Replacement rules are applied before records are passed to writers. Empty old
|
|
// values are ignored because replacing an empty string would insert the
|
|
// replacement between every UTF-8 sequence.
|
|
func (l *Logger) AddReplacer(old, new string) *Logger {
|
|
if old == "" {
|
|
return l
|
|
}
|
|
r := replacer{old: old, new: new}
|
|
l.replacers = append(l.replacers, r)
|
|
return l
|
|
}
|
|
|
|
// Close closes all owned writers and returns a joined error, if any.
|
|
func (l *Logger) Close() error {
|
|
var errs []error
|
|
for _, writer := range l.writers {
|
|
if writer == nil {
|
|
continue
|
|
}
|
|
err := writer.Close()
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
l.writers = nil
|
|
return errors.Join(errs...)
|
|
}
|
|
|
|
// CreateTextWriter wraps an external writer with the logger text settings.
|
|
func (l *Logger) CreateTextWriter(w io.Writer) *LoggerTextWriter {
|
|
return CreateTextWriter(w)
|
|
}
|
|
|
|
// CreateTextStdoutWriter creates a non-owning text writer for os.Stdout.
|
|
func (l *Logger) CreateTextStdoutWriter() *LoggerTextWriter {
|
|
return CreateTextStdoutWriter()
|
|
}
|
|
|
|
// CreateTextFileWriter creates an owning text writer for a file.
|
|
func (l *Logger) CreateTextFileWriter(filename string) (*LoggerTextWriter, error) {
|
|
return CreateTextFileWriter(filename)
|
|
}
|
|
|
|
// CreateJsonWriter wraps an external writer with the logger JSON settings.
|
|
func (l *Logger) CreateJsonWriter(w io.Writer) *LoggerJsonWriter {
|
|
return CreateJsonWriter(w, l.jsonPretty)
|
|
}
|
|
|
|
// CreateJsonStdoutWriter creates a non-owning JSON writer for os.Stdout.
|
|
func (l *Logger) CreateJsonStdoutWriter() *LoggerJsonWriter {
|
|
return CreateJsonStdoutWriter(l.jsonPretty)
|
|
}
|
|
|
|
// CreateJsonFileWriter creates an owning JSON writer for a file.
|
|
func (l *Logger) CreateJsonFileWriter(filename string) (*LoggerJsonWriter, error) {
|
|
return CreateJsonFileWriter(filename, l.jsonPretty)
|
|
}
|
|
|
|
func (l *Logger) replace(s string) string {
|
|
out := s
|
|
for _, repl := range l.replacers {
|
|
out = repl.replace(out)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (l *Logger) replaceAll(messages ...any) []any {
|
|
if len(l.replacers) == 0 {
|
|
return messages
|
|
}
|
|
out := make([]any, len(messages))
|
|
for i, msg := range messages {
|
|
out[i] = l.replace(fmt.Sprint(msg))
|
|
}
|
|
return out
|
|
}
|