/* * Copyright 2026 Oleg Borodin * * This work is published and licensed under a Creative Commons * Attribution-NonCommercial-NoDerivatives 4.0 International License. * * Distribution of this work is permitted, but commercial use and * modifications are strictly prohibited. */ package logger import ( "bytes" "fmt" "io" "os" "sync" "time" ) var ( mtx sync.Mutex output io.WriteCloser = os.Stderr ) type Logger struct { subject string writer io.WriteCloser mtx *sync.Mutex } func NewLogger(subj string) *Logger { return &Logger{ subject: subj, writer: output, mtx: &mtx, } } func xxxNewLogger() *Logger { return &Logger{ writer: output, mtx: &mtx, } } func SetWriter(newOut io.WriteCloser) { mtx.Lock() output = newOut mtx.Unlock() } func (logg *Logger) SetWriter(newOut io.WriteCloser) { mtx.Lock() logg.writer = newOut var newMtx sync.Mutex logg.mtx = &newMtx mtx.Unlock() } func (logg *Logger) Debugf(message string, args ...any) { logg.printf("debug", message, args...) } func (logg *Logger) Infof(message string, args ...any) { logg.printf("info", message, args...) } func (logg *Logger) Warningf(message string, args ...any) { logg.printf("warning", message, args...) } func (logg *Logger) Errorf(message string, args ...any) { logg.printf("error", message, args...) } func (logg *Logger) printf(level, message string, args ...any) { timestamp := time.Now().Format(time.RFC3339) buffer := bytes.NewBuffer([]byte{}) if logg.subject != "" { fmt.Fprintf(buffer, "%s %s.%s: ", timestamp, logg.subject, level) } else { fmt.Fprintf(buffer, "%s %s: ", timestamp, level) } fmt.Fprintf(buffer, message, args...) fmt.Fprintf(buffer, "\n") logg.mtx.Lock() fmt.Fprint(output, buffer.String()) logg.mtx.Unlock() }