package sneklog import ( "errors" "fmt" "io" "strings" ) // 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"` } // Logger routes log records to one or more configured writers. type Logger struct { prefix string level LogLevel writers []LoggerWriter replacers []replacer jsonPretty bool } // CreateLogger creates a logger with default settings. // Deprecated: use NewLogger. This method will be removed in v3. func CreateLogger() *Logger { return &Logger{ prefix: "LOG", level: FATAL, } } // NewLogger creates a logger with default settings. func NewLogger() *Logger { return &Logger{ prefix: "LOG", level: FATAL, } } // Prefix sets the record prefix and returns the logger for chaining. // Deprecated: use SetName. This method will be removed in v3. func (l *Logger) Prefix(prefix string) *Logger { l.prefix = prefix return l } // SetName sets the record prefix and returns the logger for chaining. func (l *Logger) SetName(name string) *Logger { l.prefix = name return l } // Level sets the maximum enabled level and returns the logger for chaining. // Deprecated: use SetLevel. This method will be removed in v3. func (l *Logger) Level(level LogLevel) *Logger { l.level = level return l } // SetLevel sets the maximum enabled level and returns the logger for chaining. func (l *Logger) SetLevel(level LogLevel) *Logger { l.level = level return l } // JsonPretty enables or disables indented JSON output for JSON writers created by the logger. // Deprecated: use SetJSONPretty. This method will be removed in v3. func (l *Logger) JsonPretty(b bool) *Logger { l.jsonPretty = b return l } // SetJSONPretty enables or disables indented output for JSON writers created by the logger. func (l *Logger) SetJSONPretty(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. // Deprecated: use AddWriters. This method will be removed in v3. 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) } type replacer struct { old string new string } func (r replacer) replace(s string) string { return strings.ReplaceAll(s, r.old, r.new) } 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 }