github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/common/flogging/fabenc/formatter.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package fabenc 8 9 import ( 10 "fmt" 11 "io" 12 "regexp" 13 "runtime" 14 "strings" 15 "sync" 16 "sync/atomic" 17 18 "go.uber.org/zap/zapcore" 19 ) 20 21 // formatRegexp is broken into three groups: 22 // 1. the format verb 23 // 2. an optional colon that is ungrouped with '?:' 24 // 3. an optional, non-greedy format directive 25 // 26 // The grouping simplifies the verb proccssing during spec parsing. 27 var formatRegexp = regexp.MustCompile(`%{(color|id|level|message|module|shortfunc|time)(?::(.*?))?}`) 28 29 // ParseFormat parses a log format spec and returns a slice of formatters 30 // that should be iterated over to build a formatted log record. 31 // 32 // The op-loggng specifiers supported by this formatter are: 33 // - %{color} - level specific SGR color escape or SGR reset 34 // - %{id} - a unique log sequence number 35 // - %{level} - the log level of the entry 36 // - %{message} - the log message 37 // - %{module} - the zap logger name 38 // - %{shortfunc} - the name of the function creating the log record 39 // - %{time} - the time the log entry was created 40 // 41 // Specifiers may include an optional format verb: 42 // - color: reset|bold 43 // - id: a fmt style numeric formatter without the leading % 44 // - level: a fmt style string formatter without the leading % 45 // - message: a fmt style string formatter without the leading % 46 // - module: a fmt style string formatter without the leading % 47 // 48 func ParseFormat(spec string) ([]Formatter, error) { 49 cursor := 0 50 formatters := []Formatter{} 51 52 // iterate over the regex groups and convert to formatters 53 matches := formatRegexp.FindAllStringSubmatchIndex(spec, -1) 54 for _, m := range matches { 55 start, end := m[0], m[1] 56 verbStart, verbEnd := m[2], m[3] 57 formatStart, formatEnd := m[4], m[5] 58 59 if start > cursor { 60 formatters = append(formatters, StringFormatter{Value: spec[cursor:start]}) 61 } 62 63 var format string 64 if formatStart >= 0 { 65 format = spec[formatStart:formatEnd] 66 } 67 68 formatter, err := NewFormatter(spec[verbStart:verbEnd], format) 69 if err != nil { 70 return nil, err 71 } 72 73 formatters = append(formatters, formatter) 74 cursor = end 75 } 76 77 // handle any trailing suffix 78 if cursor != len(spec) { 79 formatters = append(formatters, StringFormatter{Value: spec[cursor:]}) 80 } 81 82 return formatters, nil 83 } 84 85 // A MultiFormatter presents multiple formatters as a single Formatter. It can 86 // be used to change the set of formatters associated with an encoder at 87 // runtime. 88 type MultiFormatter struct { 89 mutex sync.RWMutex 90 formatters []Formatter 91 } 92 93 // NewMultiFormatter creates a new MultiFormatter that delegates to the 94 // provided formatters. The formatters are used in the order they are 95 // presented. 96 func NewMultiFormatter(formatters ...Formatter) *MultiFormatter { 97 return &MultiFormatter{ 98 formatters: formatters, 99 } 100 } 101 102 // Format iterates over its delegates to format a log record to the provided 103 // buffer. 104 func (m *MultiFormatter) Format(w io.Writer, entry zapcore.Entry, fields []zapcore.Field) { 105 m.mutex.RLock() 106 for i := range m.formatters { 107 m.formatters[i].Format(w, entry, fields) 108 } 109 m.mutex.RUnlock() 110 } 111 112 // SetFormatters replaces the delegate formatters. 113 func (m *MultiFormatter) SetFormatters(formatters []Formatter) { 114 m.mutex.Lock() 115 m.formatters = formatters 116 m.mutex.Unlock() 117 } 118 119 // A StringFormatter formats a fixed string. 120 type StringFormatter struct{ Value string } 121 122 // Format writes the formatter's fixed string to provided writer. 123 func (s StringFormatter) Format(w io.Writer, entry zapcore.Entry, fields []zapcore.Field) { 124 fmt.Fprintf(w, "%s", s.Value) 125 } 126 127 // NewFormatter creates the formatter for the provided verb. When a format is 128 // not provided, the default format for the verb is used. 129 func NewFormatter(verb, format string) (Formatter, error) { 130 switch verb { 131 case "color": 132 return newColorFormatter(format) 133 case "id": 134 return newSequenceFormatter(format), nil 135 case "level": 136 return newLevelFormatter(format), nil 137 case "message": 138 return newMessageFormatter(format), nil 139 case "module": 140 return newModuleFormatter(format), nil 141 case "shortfunc": 142 return newShortFuncFormatter(format), nil 143 case "time": 144 return newTimeFormatter(format), nil 145 default: 146 return nil, fmt.Errorf("unknown verb: %s", verb) 147 } 148 } 149 150 // A ColorFormatter formats an SGR color code. 151 type ColorFormatter struct { 152 Bold bool // set the bold attribute 153 Reset bool // reset colors and attributes 154 } 155 156 func newColorFormatter(f string) (ColorFormatter, error) { 157 switch f { 158 case "bold": 159 return ColorFormatter{Bold: true}, nil 160 case "reset": 161 return ColorFormatter{Reset: true}, nil 162 case "": 163 return ColorFormatter{}, nil 164 default: 165 return ColorFormatter{}, fmt.Errorf("invalid color option: %s", f) 166 } 167 } 168 169 // LevelColor returns the Color associated with a specific zap logging level. 170 func (c ColorFormatter) LevelColor(l zapcore.Level) Color { 171 switch l { 172 case zapcore.DebugLevel: 173 return ColorCyan 174 case zapcore.InfoLevel: 175 return ColorBlue 176 case zapcore.WarnLevel: 177 return ColorYellow 178 case zapcore.ErrorLevel: 179 return ColorRed 180 case zapcore.DPanicLevel, zapcore.PanicLevel: 181 return ColorMagenta 182 case zapcore.FatalLevel: 183 return ColorMagenta 184 default: 185 return ColorNone 186 } 187 } 188 189 // Format writes the SGR color code to the provided writer. 190 func (c ColorFormatter) Format(w io.Writer, entry zapcore.Entry, fields []zapcore.Field) { 191 switch { 192 case c.Reset: 193 fmt.Fprint(w, ResetColor()) 194 case c.Bold: 195 fmt.Fprint(w, c.LevelColor(entry.Level).Bold()) 196 default: 197 fmt.Fprint(w, c.LevelColor(entry.Level).Normal()) 198 } 199 } 200 201 // LevelFormatter formats a log level. 202 type LevelFormatter struct{ FormatVerb string } 203 204 func newLevelFormatter(f string) LevelFormatter { 205 return LevelFormatter{FormatVerb: "%" + stringOrDefault(f, "s")} 206 } 207 208 // Format writes the logging level to the provided writer. 209 func (l LevelFormatter) Format(w io.Writer, entry zapcore.Entry, fields []zapcore.Field) { 210 fmt.Fprintf(w, l.FormatVerb, entry.Level.CapitalString()) 211 } 212 213 // MessageFormatter formats a log message. 214 type MessageFormatter struct{ FormatVerb string } 215 216 func newMessageFormatter(f string) MessageFormatter { 217 return MessageFormatter{FormatVerb: "%" + stringOrDefault(f, "s")} 218 } 219 220 // Format writes the log entry message to the provided writer. 221 func (m MessageFormatter) Format(w io.Writer, entry zapcore.Entry, fields []zapcore.Field) { 222 fmt.Fprintf(w, m.FormatVerb, strings.TrimRight(entry.Message, "\n")) 223 } 224 225 // ModuleFormatter formats the zap logger name. 226 type ModuleFormatter struct{ FormatVerb string } 227 228 func newModuleFormatter(f string) ModuleFormatter { 229 return ModuleFormatter{FormatVerb: "%" + stringOrDefault(f, "s")} 230 } 231 232 // Format writes the zap logger name to the specified writer. 233 func (m ModuleFormatter) Format(w io.Writer, entry zapcore.Entry, fields []zapcore.Field) { 234 fmt.Fprintf(w, m.FormatVerb, entry.LoggerName) 235 } 236 237 // sequence maintains the global sequence number shared by all SequeneFormatter 238 // instances. 239 var sequence uint64 240 241 // SetSequence explicitly sets the global sequence number. 242 func SetSequence(s uint64) { atomic.StoreUint64(&sequence, s) } 243 244 // SequenceFormatter formats a global sequence number. 245 type SequenceFormatter struct{ FormatVerb string } 246 247 func newSequenceFormatter(f string) SequenceFormatter { 248 return SequenceFormatter{FormatVerb: "%" + stringOrDefault(f, "d")} 249 } 250 251 // SequenceFormatter increments a global sequence number and writes it to the 252 // provided writer. 253 func (s SequenceFormatter) Format(w io.Writer, entry zapcore.Entry, fields []zapcore.Field) { 254 fmt.Fprintf(w, s.FormatVerb, atomic.AddUint64(&sequence, 1)) 255 } 256 257 // ShortFuncFormatter formats the name of the function creating the log record. 258 type ShortFuncFormatter struct{ FormatVerb string } 259 260 func newShortFuncFormatter(f string) ShortFuncFormatter { 261 return ShortFuncFormatter{FormatVerb: "%" + stringOrDefault(f, "s")} 262 } 263 264 // Format writes the calling function name to the provided writer. The name is obtained from 265 // the runtime and the package and line numbers are discarded. 266 func (s ShortFuncFormatter) Format(w io.Writer, entry zapcore.Entry, fields []zapcore.Field) { 267 f := runtime.FuncForPC(entry.Caller.PC) 268 if f == nil { 269 fmt.Fprintf(w, s.FormatVerb, "(unknown)") 270 return 271 } 272 273 fname := f.Name() 274 funcIdx := strings.LastIndex(fname, ".") 275 fmt.Fprintf(w, s.FormatVerb, fname[funcIdx+1:]) 276 } 277 278 // TimeFormatter formats the time from the zap log entry. 279 type TimeFormatter struct{ Layout string } 280 281 func newTimeFormatter(f string) TimeFormatter { 282 return TimeFormatter{Layout: stringOrDefault(f, "2006-01-02T15:04:05.999Z07:00")} 283 } 284 285 // Format writes the log record time stamp to the provided writer. 286 func (t TimeFormatter) Format(w io.Writer, entry zapcore.Entry, fields []zapcore.Field) { 287 fmt.Fprint(w, entry.Time.Format(t.Layout)) 288 } 289 290 func stringOrDefault(str, dflt string) string { 291 if str != "" { 292 return str 293 } 294 return dflt 295 }