FILE / ScuroNeko/SNekLog

logger.go

Исходный файл и его история в репозитории.
FILE b4c9203a79c7b26588dd42f773ce2a8f598494f1
Files
SNekLog/logger.go
T
ScuroNeko d534f92d48 (refactor): prepare breaking v2 API
- 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
2026-04-24 15:43:14 +03:00

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
}