blob: 57c914049c64e34ed56b9ef1cc295af789140e9c [file] [log] [blame]
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("~")
}