diff --git a/log.go b/log.go index e00acee..78de6c2 100644 --- a/log.go +++ b/log.go @@ -6,6 +6,7 @@ import ( "os" "runtime" "strings" + "sync" ) // Level indicates the level a log should be classified at @@ -60,6 +61,7 @@ var levelColor = map[Level]func(...interface{})string {LevelDebug: Debug, LevelI // privacyFilters by default apply all functions to printf args and add warnings to them for matches // privacyFilterReplace obscures any matches from the privacy filter functions type Logger struct { + lock sync.Mutex // ensures atomic writes; protects the following fields logger *golog.Logger level Level useColor bool @@ -85,10 +87,13 @@ func NewFile(level Level, filename string) (*Logger, error) { return &Logger{logger: golog.New(logfile, "", golog.Ldate|golog.Ltime), level: level, useColor: false, everythingFromPatterns: make([]string, 0), nothingExceptPatterns: make([]string, 0), privacyFilers: make([]func(string)bool, 0), privacyFilterReplace: false}, nil } +var stdLock sync.Mutex var std = New(LevelWarn) // SetStd sets the default logger all other functions use func SetStd(logger *Logger) { + stdLock.Lock() + defer stdLock.Unlock() std = logger } @@ -131,34 +136,48 @@ func (l *Logger) aboveLevel(level Level) bool { // SetLevel adjusts the output filter by logging level func (l *Logger) SetLevel(level Level) { + l.lock.Lock() + defer l.lock.Unlock() l.level = level } // SetUseColor toggles weather color output is used func (l *Logger) SetUseColor(useColor bool) { + l.lock.Lock() + defer l.lock.Unlock() l.useColor = useColor } // AddNothingExceptFilter enables strong filtering showing logs only for things on the approved list, adding this pattern to the list func (l *Logger) AddNothingExceptFilter(pattern string) { + l.lock.Lock() + defer l.lock.Unlock() l.nothingExceptPatterns = append(l.nothingExceptPatterns, pattern) } // AddEverythingFromPattern adds a pattern to skip log level filtering, guaranteeing all logs matching the pattern are seen func (l *Logger) AddEverythingFromPattern(pattern string) { + l.lock.Lock() + defer l.lock.Unlock() l.everythingFromPatterns = append(l.everythingFromPatterns, pattern) } // ExcludeFromPattern adds a pattern to exclude logs from func (l *Logger) ExcludeFromPattern(pattern string) { + l.lock.Lock() + defer l.lock.Unlock() l.excludeFromPatterns = append(l.excludeFromPatterns, pattern) } func (l *Logger) AddPrivacyFilter(fn func(string)bool) { + l.lock.Lock() + defer l.lock.Unlock() l.privacyFilers = append(l.privacyFilers, fn) } func (l *Logger) SetPrivacyFilterReplace(b bool) { + l.lock.Lock() + defer l.lock.Unlock() l.privacyFilterReplace = b } @@ -215,6 +234,8 @@ func (l *Logger) privacyFilter(v ...interface{}) []interface{} { // Printf outputs the format and variables, assuming it passes the filter levels func (l *Logger) Printf(level Level, format string, v ...interface{}) { + l.lock.Lock() + defer l.lock.Unlock() if l.filter(level) { l.logger.Output(3, l.header(level)+fmt.Sprintf(format, l.privacyFilter(v...)...)) } @@ -222,6 +243,8 @@ func (l *Logger) Printf(level Level, format string, v ...interface{}) { // Println outputs the variables assuming the filter levels are passed func (l *Logger) Println(level Level, v ...interface{}) { + l.lock.Lock() + defer l.lock.Unlock() if l.filter(level) { l.logger.Output(3, l.header(level)+fmt.Sprintln(v...)) }