ConsoleWriter: fix race condition (#120)

Alternative approach to #118: fix the race condition by replacing the package-level customization settings with curried functions.
This commit is contained in:
Ingmar Stein 2018-12-07 18:59:01 +01:00 committed by Olivier Poitrey
parent 7179aeef58
commit c482b20623
1 changed files with 58 additions and 57 deletions

View File

@ -35,19 +35,10 @@ var (
return bytes.NewBuffer(make([]byte, 0, 100)) return bytes.NewBuffer(make([]byte, 0, 100))
}, },
} }
)
const (
consoleDefaultTimeFormat = time.Kitchen consoleDefaultTimeFormat = time.Kitchen
consoleDefaultPartsOrder = func() []string {
return []string{
TimestampFieldName,
LevelFieldName,
CallerFieldName,
MessageFieldName,
}
}
consoleNoColor = false
consoleTimeFormat = consoleDefaultTimeFormat
) )
// Formatter transforms the input into a formatted string. // Formatter transforms the input into a formatted string.
@ -98,18 +89,6 @@ func (w ConsoleWriter) Write(p []byte) (n int, err error) {
if w.PartsOrder == nil { if w.PartsOrder == nil {
w.PartsOrder = consoleDefaultPartsOrder() w.PartsOrder = consoleDefaultPartsOrder()
} }
if w.TimeFormat == "" && consoleTimeFormat != consoleDefaultTimeFormat {
consoleTimeFormat = consoleDefaultTimeFormat
}
if w.TimeFormat != "" && consoleTimeFormat != w.TimeFormat {
consoleTimeFormat = w.TimeFormat
}
if w.NoColor == false && consoleNoColor != false {
consoleNoColor = false
}
if w.NoColor == true && consoleNoColor != w.NoColor {
consoleNoColor = w.NoColor
}
var buf = consoleBufPool.Get().(*bytes.Buffer) var buf = consoleBufPool.Get().(*bytes.Buffer)
defer func() { defer func() {
@ -177,19 +156,19 @@ func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *bytes.Buffer
if field == ErrorFieldName { if field == ErrorFieldName {
if w.FormatErrFieldName == nil { if w.FormatErrFieldName == nil {
fn = consoleDefaultFormatErrFieldName fn = consoleDefaultFormatErrFieldName(w.NoColor)
} else { } else {
fn = w.FormatErrFieldName fn = w.FormatErrFieldName
} }
if w.FormatErrFieldValue == nil { if w.FormatErrFieldValue == nil {
fv = consoleDefaultFormatErrFieldValue fv = consoleDefaultFormatErrFieldValue(w.NoColor)
} else { } else {
fv = w.FormatErrFieldValue fv = w.FormatErrFieldValue
} }
} else { } else {
if w.FormatFieldName == nil { if w.FormatFieldName == nil {
fn = consoleDefaultFormatFieldName fn = consoleDefaultFormatFieldName(w.NoColor)
} else { } else {
fn = w.FormatFieldName fn = w.FormatFieldName
} }
@ -234,13 +213,13 @@ func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{},
switch p { switch p {
case LevelFieldName: case LevelFieldName:
if w.FormatLevel == nil { if w.FormatLevel == nil {
f = consoleDefaultFormatLevel f = consoleDefaultFormatLevel(w.NoColor)
} else { } else {
f = w.FormatLevel f = w.FormatLevel
} }
case TimestampFieldName: case TimestampFieldName:
if w.FormatTimestamp == nil { if w.FormatTimestamp == nil {
f = consoleDefaultFormatTimestamp f = consoleDefaultFormatTimestamp(w.TimeFormat, w.NoColor)
} else { } else {
f = w.FormatTimestamp f = w.FormatTimestamp
} }
@ -252,7 +231,7 @@ func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{},
} }
case CallerFieldName: case CallerFieldName:
if w.FormatCaller == nil { if w.FormatCaller == nil {
f = consoleDefaultFormatCaller f = consoleDefaultFormatCaller(w.NoColor)
} else { } else {
f = w.FormatCaller f = w.FormatCaller
} }
@ -294,49 +273,65 @@ func colorize(s interface{}, c int, disabled bool) string {
// ----- DEFAULT FORMATTERS --------------------------------------------------- // ----- DEFAULT FORMATTERS ---------------------------------------------------
var ( func consoleDefaultPartsOrder() []string {
consoleDefaultFormatTimestamp = func(i interface{}) string { return []string{
TimestampFieldName,
LevelFieldName,
CallerFieldName,
MessageFieldName,
}
}
func consoleDefaultFormatTimestamp(timeFormat string, noColor bool) Formatter {
if timeFormat == "" {
timeFormat = consoleDefaultTimeFormat
}
return func(i interface{}) string {
t := "<nil>" t := "<nil>"
switch tt := i.(type) { switch tt := i.(type) {
case string: case string:
ts, err := time.Parse(time.RFC3339, tt) ts, err := time.Parse(TimeFieldFormat, tt)
if err != nil { if err != nil {
t = tt t = tt
} else { } else {
t = ts.Format(consoleTimeFormat) t = ts.Format(timeFormat)
} }
case json.Number: case json.Number:
t = tt.String() t = tt.String()
} }
return colorize(t, colorFaint, consoleNoColor) return colorize(t, colorFaint, noColor)
} }
}
consoleDefaultFormatLevel = func(i interface{}) string { func consoleDefaultFormatLevel(noColor bool) Formatter {
return func(i interface{}) string {
var l string var l string
if ll, ok := i.(string); ok { if ll, ok := i.(string); ok {
switch ll { switch ll {
case "debug": case "debug":
l = colorize("DBG", colorYellow, consoleNoColor) l = colorize("DBG", colorYellow, noColor)
case "info": case "info":
l = colorize("INF", colorGreen, consoleNoColor) l = colorize("INF", colorGreen, noColor)
case "warn": case "warn":
l = colorize("WRN", colorRed, consoleNoColor) l = colorize("WRN", colorRed, noColor)
case "error": case "error":
l = colorize(colorize("ERR", colorRed, consoleNoColor), colorBold, consoleNoColor) l = colorize(colorize("ERR", colorRed, noColor), colorBold, noColor)
case "fatal": case "fatal":
l = colorize(colorize("FTL", colorRed, consoleNoColor), colorBold, consoleNoColor) l = colorize(colorize("FTL", colorRed, noColor), colorBold, noColor)
case "panic": case "panic":
l = colorize(colorize("PNC", colorRed, consoleNoColor), colorBold, consoleNoColor) l = colorize(colorize("PNC", colorRed, noColor), colorBold, noColor)
default: default:
l = colorize("???", colorBold, consoleNoColor) l = colorize("???", colorBold, noColor)
} }
} else { } else {
l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3] l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3]
} }
return l return l
} }
}
consoleDefaultFormatCaller = func(i interface{}) string { func consoleDefaultFormatCaller(noColor bool) Formatter {
return func(i interface{}) string {
var c string var c string
if cc, ok := i.(string); ok { if cc, ok := i.(string); ok {
c = cc c = cc
@ -347,28 +342,34 @@ var (
c = strings.TrimPrefix(c, cwd) c = strings.TrimPrefix(c, cwd)
c = strings.TrimPrefix(c, "/") c = strings.TrimPrefix(c, "/")
} }
c = colorize(c, colorBold, consoleNoColor) + colorize(" >", colorFaint, consoleNoColor) c = colorize(c, colorBold, noColor) + colorize(" >", colorFaint, noColor)
} }
return c return c
} }
}
consoleDefaultFormatMessage = func(i interface{}) string { func consoleDefaultFormatMessage(i interface{}) string {
return fmt.Sprintf("%s", i) return fmt.Sprintf("%s", i)
} }
consoleDefaultFormatFieldName = func(i interface{}) string { func consoleDefaultFormatFieldName(noColor bool) Formatter {
return colorize(fmt.Sprintf("%s=", i), colorFaint, consoleNoColor) return func(i interface{}) string {
return colorize(fmt.Sprintf("%s=", i), colorFaint, noColor)
} }
}
consoleDefaultFormatFieldValue = func(i interface{}) string { func consoleDefaultFormatFieldValue(i interface{}) string {
return fmt.Sprintf("%s", i) return fmt.Sprintf("%s", i)
} }
consoleDefaultFormatErrFieldName = func(i interface{}) string { func consoleDefaultFormatErrFieldName(noColor bool) Formatter {
return colorize(fmt.Sprintf("%s=", i), colorRed, consoleNoColor) return func(i interface{}) string {
return colorize(fmt.Sprintf("%s=", i), colorRed, noColor)
} }
}
consoleDefaultFormatErrFieldValue = func(i interface{}) string { func consoleDefaultFormatErrFieldValue(noColor bool) Formatter {
return colorize(fmt.Sprintf("%s", i), colorRed, consoleNoColor) return func(i interface{}) string {
return colorize(fmt.Sprintf("%s", i), colorRed, noColor)
} }
) }