// Copyright 2020 Kentaro Hibino. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE file.

// Package log exports logging related types and functions.
package log import ( stdlog ) // Base supports logging at various log levels. type Base interface { // Debug logs a message at Debug level. Debug(args ...interface{}) // Info logs a message at Info level. Info(args ...interface{}) // Warn logs a message at Warning level. Warn(args ...interface{}) // Error logs a message at Error level. Error(args ...interface{}) // Fatal logs a message at Fatal level // and process will exit with status set to 1. Fatal(args ...interface{}) } // baseLogger is a wrapper object around log.Logger from the standard library. // It supports logging at various log levels. type baseLogger struct { *stdlog.Logger } // Debug logs a message at Debug level. func ( *baseLogger) ( ...interface{}) { .prefixPrint("DEBUG: ", ...) } // Info logs a message at Info level. func ( *baseLogger) ( ...interface{}) { .prefixPrint("INFO: ", ...) } // Warn logs a message at Warning level. func ( *baseLogger) ( ...interface{}) { .prefixPrint("WARN: ", ...) } // Error logs a message at Error level. func ( *baseLogger) ( ...interface{}) { .prefixPrint("ERROR: ", ...) } // Fatal logs a message at Fatal level // and process will exit with status set to 1. func ( *baseLogger) ( ...interface{}) { .prefixPrint("FATAL: ", ...) os.Exit(1) } func ( *baseLogger) ( string, ...interface{}) { = append([]interface{}{}, ...) .Print(...) } // newBase creates and returns a new instance of baseLogger. func newBase( io.Writer) *baseLogger { := fmt.Sprintf("asynq: pid=%d ", os.Getpid()) return &baseLogger{ stdlog.New(, , stdlog.Ldate|stdlog.Ltime|stdlog.Lmicroseconds|stdlog.LUTC), } } // NewLogger creates and returns a new instance of Logger. // Log level is set to DebugLevel by default. func ( Base) *Logger { if == nil { = newBase(os.Stderr) } return &Logger{base: , level: DebugLevel} } // Logger logs message to io.Writer at various log levels. type Logger struct { base Base mu sync.Mutex // Minimum log level for this logger. // Message with level lower than this level won't be outputted. level Level } // Level represents a log level. type Level int32 const ( // DebugLevel is the lowest level of logging. // Debug logs are intended for debugging and development purposes. DebugLevel Level = iota // InfoLevel is used for general informational log messages. InfoLevel // WarnLevel is used for undesired but relatively expected events, // which may indicate a problem. WarnLevel // ErrorLevel is used for undesired and unexpected events that // the program can recover from. ErrorLevel // FatalLevel is used for undesired and unexpected events that // the program cannot recover from. FatalLevel ) // String is part of the fmt.Stringer interface. // // Used for testing and debugging purposes. func ( Level) () string { switch { case DebugLevel: return "debug" case InfoLevel: return "info" case WarnLevel: return "warning" case ErrorLevel: return "error" case FatalLevel: return "fatal" default: return "unknown" } } // canLogAt reports whether logger can log at level v. func ( *Logger) ( Level) bool { .mu.Lock() defer .mu.Unlock() return >= .level } func ( *Logger) ( ...interface{}) { if !.canLogAt(DebugLevel) { return } .base.Debug(...) } func ( *Logger) ( ...interface{}) { if !.canLogAt(InfoLevel) { return } .base.Info(...) } func ( *Logger) ( ...interface{}) { if !.canLogAt(WarnLevel) { return } .base.Warn(...) } func ( *Logger) ( ...interface{}) { if !.canLogAt(ErrorLevel) { return } .base.Error(...) } func ( *Logger) ( ...interface{}) { if !.canLogAt(FatalLevel) { return } .base.Fatal(...) } func ( *Logger) ( string, ...interface{}) { .Debug(fmt.Sprintf(, ...)) } func ( *Logger) ( string, ...interface{}) { .Info(fmt.Sprintf(, ...)) } func ( *Logger) ( string, ...interface{}) { .Warn(fmt.Sprintf(, ...)) } func ( *Logger) ( string, ...interface{}) { .Error(fmt.Sprintf(, ...)) } func ( *Logger) ( string, ...interface{}) { .Fatal(fmt.Sprintf(, ...)) } // SetLevel sets the logger level. // It panics if v is less than DebugLevel or greater than FatalLevel. func ( *Logger) ( Level) { .mu.Lock() defer .mu.Unlock() if < DebugLevel || > FatalLevel { panic("log: invalid log level") } .level = }