github.com/go-spring/spring-base@v1.1.3/log/plugin_layout.go (about)

     1  /*
     2   * Copyright 2012-2019 the original author or authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *      https://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package log
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"github.com/go-spring/spring-base/color"
    25  	"github.com/go-spring/spring-base/util"
    26  )
    27  
    28  func init() {
    29  	RegisterPlugin("PatternLayout", PluginTypeLayout, (*PatternLayout)(nil))
    30  	RegisterPlugin("JSONLayout", PluginTypeLayout, (*JSONLayout)(nil))
    31  }
    32  
    33  // Layout lays out an Event in []byte format.
    34  type Layout interface {
    35  	ToBytes(e *Event) ([]byte, error)
    36  }
    37  
    38  type ColorStyle int
    39  
    40  const (
    41  	ColorStyleNone = ColorStyle(iota)
    42  	ColorStyleNormal
    43  	ColorStyleBright
    44  )
    45  
    46  // ParseColorStyle parses `s` to a ColorStyle value.
    47  func ParseColorStyle(s string) (ColorStyle, error) {
    48  	switch strings.ToLower(s) {
    49  	case "none":
    50  		return ColorStyleNone, nil
    51  	case "normal":
    52  		return ColorStyleNormal, nil
    53  	case "bright":
    54  		return ColorStyleBright, nil
    55  	default:
    56  		return -1, fmt.Errorf("invalid color style '%s'", s)
    57  	}
    58  }
    59  
    60  type FormatFunc func(e *Event) string
    61  
    62  // A PatternLayout is a flexible layout configurable with pattern string.
    63  type PatternLayout struct {
    64  	ColorStyle ColorStyle `PluginAttribute:"colorStyle,default=none"`
    65  	Pattern    string     `PluginAttribute:"pattern,default=[:level][:time][:fileline][:msg]"`
    66  	steps      []FormatFunc
    67  }
    68  
    69  func (c *PatternLayout) Init() error {
    70  	return c.parse(c.Pattern)
    71  }
    72  
    73  // ToBytes lays out an Event in []byte format.
    74  func (c *PatternLayout) ToBytes(e *Event) ([]byte, error) {
    75  	buf := bytes.NewBuffer(nil)
    76  	for _, step := range c.steps {
    77  		buf.WriteString(step(e))
    78  	}
    79  	buf.WriteByte('\n')
    80  	return buf.Bytes(), nil
    81  }
    82  
    83  func (c *PatternLayout) parse(pattern string) error {
    84  	write := func(s string) FormatFunc {
    85  		return func(e *Event) string {
    86  			return s
    87  		}
    88  	}
    89  	c.steps = append(c.steps, write("["))
    90  	c.steps = append(c.steps, c.getLevel)
    91  	c.steps = append(c.steps, write("]"))
    92  	c.steps = append(c.steps, write("["))
    93  	c.steps = append(c.steps, c.getTime)
    94  	c.steps = append(c.steps, write("]"))
    95  	c.steps = append(c.steps, write("["))
    96  	c.steps = append(c.steps, c.getFileLine)
    97  	c.steps = append(c.steps, write("]"))
    98  	c.steps = append(c.steps, write(" "))
    99  	c.steps = append(c.steps, c.getMsg)
   100  	return nil
   101  }
   102  
   103  func (c *PatternLayout) getMsg(e *Event) string {
   104  	buf := bytes.NewBuffer(nil)
   105  	if tag := e.Tag; tag != "" {
   106  		buf.WriteString(tag)
   107  		buf.WriteString("||")
   108  	}
   109  	enc := NewFlatEncoder(buf, "||")
   110  	err := enc.AppendEncoderBegin()
   111  	if err != nil {
   112  		return err.Error()
   113  	}
   114  	for _, f := range e.Fields {
   115  		err = enc.AppendKey(f.Key)
   116  		if err != nil {
   117  			return err.Error()
   118  		}
   119  		err = f.Val.Encode(enc)
   120  		if err != nil {
   121  			return err.Error()
   122  		}
   123  	}
   124  	err = enc.AppendEncoderEnd()
   125  	if err != nil {
   126  		return err.Error()
   127  	}
   128  	buf.WriteString(e.Message)
   129  	return buf.String()
   130  }
   131  
   132  func (c *PatternLayout) getLevel(e *Event) string {
   133  	strLevel := strings.ToUpper(e.Level.String())
   134  	switch c.ColorStyle {
   135  	case ColorStyleNormal:
   136  		if e.Level >= ErrorLevel {
   137  			strLevel = color.Red.Sprint(strLevel)
   138  		} else if e.Level == WarnLevel {
   139  			strLevel = color.Yellow.Sprint(strLevel)
   140  		} else if e.Level <= DebugLevel {
   141  			strLevel = color.Green.Sprint(strLevel)
   142  		}
   143  	}
   144  	return strLevel
   145  }
   146  
   147  func (c *PatternLayout) getTime(e *Event) string {
   148  	return e.Time.Format("2006-01-02T15:04:05.000")
   149  }
   150  
   151  func (c *PatternLayout) getFileLine(e *Event) string {
   152  	return util.Contract(fmt.Sprintf("%s:%d", e.File, e.Line), 48)
   153  }
   154  
   155  // A JSONLayout is a layout configurable with JSON encoding.
   156  type JSONLayout struct{}
   157  
   158  // ToBytes lays out an Event in []byte format.
   159  func (c *JSONLayout) ToBytes(e *Event) ([]byte, error) {
   160  	buf := bytes.NewBuffer(nil)
   161  	enc := NewJSONEncoder(buf)
   162  	err := enc.AppendEncoderBegin()
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	fields := []Field{
   167  		String("level", strings.ToUpper(e.Level.String())),
   168  		String("time", e.Time.Format("2006-01-02T15:04:05.000")),
   169  		String("fileLine", fmt.Sprintf("%s:%d", e.File, e.Line)),
   170  	}
   171  	fields = append(fields, e.Fields...)
   172  	for _, f := range fields {
   173  		err = enc.AppendKey(f.Key)
   174  		if err != nil {
   175  			return nil, err
   176  		}
   177  		err = f.Val.Encode(enc)
   178  		if err != nil {
   179  			return nil, err
   180  		}
   181  	}
   182  	err = enc.AppendEncoderEnd()
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	buf.WriteByte('\n')
   187  	return buf.Bytes(), nil
   188  }