package log import ( "fmt" "io" "os" "runtime" "strconv" "sync" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" ) // scream so user fixes it const warnImbalancedKey = "FIX_IMBALANCED_PAIRS" const warnImbalancedPairs = warnImbalancedKey + " => " const singleArgKey = "_" func badKeyAtIndex(i int) string { return "BAD_KEY_AT_INDEX_" + strconv.Itoa(i) } // DefaultLogLog is the default log for this package. var DefaultLog Logger // Suppress supresses logging and is useful to supress output in // in unit tests. // // Example // log.Suppress(true) // defer log.suppress(false) func Suppress(quiet bool) { silent = quiet } var silent bool // internalLog is the logger used by logxi itself var InternalLog Logger type loggerMap struct { sync.Mutex loggers map[string]Logger } var loggers = &loggerMap{ loggers: map[string]Logger{}, } func (lm *loggerMap) set(name string, logger Logger) { lm.loggers[name] = logger } // The assignment character between key-value pairs var AssignmentChar = ": " // Separator is the separator to use between key value pairs //var Separator = "{~}" var Separator = " " const ltsvAssignmentChar = ":" const ltsvSeparator = "\t" // logxiEnabledMap maps log name patterns to levels var logxiNameLevelMap map[string]int // logxiFormat is the formatter kind to create var logxiFormat string var colorableStdout io.Writer var defaultContextLines = 2 var defaultFormat string var defaultLevel int var defaultLogxiEnv string var defaultLogxiFormatEnv string var defaultMaxCol = 80 var defaultPretty = false var defaultLogxiColorsEnv string var defaultTimeFormat string var disableCallstack bool var disableCheckKeys bool var disableColors bool var home string var isPretty bool var isTerminal bool var isWindows = runtime.GOOS == "windows" var pkgMutex sync.Mutex var pool = NewBufferPool() var timeFormat string var wd string var pid = os.Getpid() var pidStr = strconv.Itoa(os.Getpid()) // KeyMapping is the key map used to print built-in log entry fields. type KeyMapping struct { Level string Message string Name string PID string Time string CallStack string } // KeyMap is the key map to use when printing log statements. var KeyMap = &KeyMapping{ Level: "_l", Message: "_m", Name: "_n", PID: "_p", Time: "_t", CallStack: "_c", } var logxiKeys []string func setDefaults(isTerminal bool) { var err error contextLines = defaultContextLines wd, err = os.Getwd() if err != nil { InternalLog.Error("Could not get working directory") } logxiKeys = []string{KeyMap.Level, KeyMap.Message, KeyMap.Name, KeyMap.Time, KeyMap.CallStack, KeyMap.PID} if isTerminal { defaultLogxiEnv = "*=WRN" defaultLogxiFormatEnv = "happy,fit,maxcol=80,t=15:04:05.000000,context=-1" defaultFormat = FormatHappy defaultLevel = LevelWarn defaultTimeFormat = "15:04:05.000000" } else { defaultLogxiEnv = "*=ERR" defaultLogxiFormatEnv = "JSON,t=2006-01-02T15:04:05-0700" defaultFormat = FormatJSON defaultLevel = LevelError defaultTimeFormat = "2006-01-02T15:04:05-0700" disableColors = true } if isWindows { home = os.Getenv("HOMEPATH") if os.Getenv("ConEmuANSI") == "ON" { defaultLogxiColorsEnv = "key=cyan+h,value,misc=blue+h,source=yellow,TRC,DBG,WRN=yellow+h,INF=green+h,ERR=red+h" } else { colorableStdout = NewConcurrentWriter(colorable.NewColorableStdout()) defaultLogxiColorsEnv = "ERR=red,misc=cyan,key=cyan" } // DefaultScheme is a color scheme optimized for dark background // but works well with light backgrounds } else { home = os.Getenv("HOME") term := os.Getenv("TERM") if term == "xterm-256color" { defaultLogxiColorsEnv = "key=cyan+h,value,misc=blue,source=88,TRC,DBG,WRN=yellow,INF=green+h,ERR=red+h,message=magenta+h" } else { defaultLogxiColorsEnv = "key=cyan+h,value,misc=blue,source=magenta,TRC,DBG,WRN=yellow,INF=green,ERR=red+h" } } } func isReservedKey(k interface{}) (bool, error) { key, ok := k.(string) if !ok { return false, fmt.Errorf("Key is not a string") } // check if reserved for _, key2 := range logxiKeys { if key == key2 { return true, nil } } return false, nil } func init() { colorableStdout = NewConcurrentWriter(os.Stdout) isTerminal = isatty.IsTerminal(os.Stdout.Fd()) // the internal logger to report errors if isTerminal { InternalLog = NewLogger3(NewConcurrentWriter(os.Stdout), "__logxi", NewTextFormatter("__logxi")) } else { InternalLog = NewLogger3(NewConcurrentWriter(os.Stdout), "__logxi", NewJSONFormatter("__logxi")) } InternalLog.SetLevel(LevelError) setDefaults(isTerminal) RegisterFormatFactory(FormatHappy, formatFactory) RegisterFormatFactory(FormatText, formatFactory) RegisterFormatFactory(FormatJSON, formatFactory) ProcessEnv(readFromEnviron()) // package logger for users DefaultLog = New("~") }