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 }