package logtr import ( "encoding/json" "errors" "fmt" "io" "os" "strings" "sync" "time" ) type Level int const ( VERBOSE = Level(7) DEBUG = Level(8) INFO = Level(9) ERROR = Level(10) SOS = Level(15) ) type SOSer interface { Send(string) error } func (l Level) MarshalJSON() ([]byte, error) { return json.Marshal(l.String()) } func (l *Level) UnmarshalJSON(b []byte) error { var s string if err := json.Unmarshal(b, &s); err != nil { return err } s = strings.TrimSpace(s) s = strings.ToUpper(s) if len(s) > 3 { s = s[:3] } for i := 0; i < int(SOS)+5; i++ { l2 := Level(i) if l2.String() == s { *l = l2 return nil } } return errors.New("unknown log level: " + s) } var logger io.Writer = os.Stderr var loggerPath string = "" var lock = &sync.Mutex{} var level Level = INFO var ansoser SOSer = nil func SetLogpath(p string) { lock.Lock() defer lock.Unlock() if p == loggerPath { return } f, err := os.OpenFile(p, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { panic(err) } logger = f loggerPath = p } func SetSOSer(another SOSer) { lock.Lock() defer lock.Unlock() ansoser = another } func SetLevel(l Level) { lock.Lock() defer lock.Unlock() level = l } func logf(l Level, format string, args []interface{}) { format = fmt.Sprintf("%v: %v: %s\n", time.Now().Format("01-02T15:04:05"), l.String(), strings.TrimSpace(format)) cLevel := level cAnsoser := ansoser if l >= cLevel { fmt.Fprintf(os.Stderr, format, args...) } fmt.Fprintf(logger, format, args...) if l == SOS && cAnsoser != nil { if err := cAnsoser.Send(fmt.Sprintf(format, args...)); err != nil { Errorf("failed to SOS: %v", err) } } } func SOSf(format string, args ...interface{}) { logf(SOS, format, args) } func Infof(format string, args ...interface{}) { logf(INFO, format, args) } func Printf(format string, args ...interface{}) { Infof(format, args...) } func Debugf(format string, args ...interface{}) { logf(DEBUG, format, args) } func Verbosef(format string, args ...interface{}) { logf(VERBOSE, format, args) } func Errorf(format string, args ...interface{}) { logf(ERROR, format, args) } func (l Level) String() string { switch l { case ERROR: return "ERR" case INFO: return "INF" case DEBUG: return "DEB" case VERBOSE: return "VER" case SOS: return "SOS" default: return "?" } }