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  }