github.com/RajatVaryani/mattermost-server@v5.11.1+incompatible/mlog/human/parser.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package human 5 6 import ( 7 "encoding/json" 8 "errors" 9 "fmt" 10 "io" 11 "strconv" 12 "strings" 13 "time" 14 15 "github.com/mattermost/mattermost-server/mlog" 16 ) 17 18 func ParseLogMessage(msg string) LogEntry { 19 result, err := parseLogMessage(msg) 20 if err != nil { 21 // If failed to parse, just output a LogEntry where all fields are blank, but Message is the original string 22 var result2 LogEntry 23 result2.Message = msg 24 return result2 25 } 26 return result 27 } 28 29 func parseLogMessage(msg string) (result LogEntry, err error) { 30 31 // Note: This implementation uses a custom json decoding loop. 32 // The primary advantage of this versus decoding directly into a map is to 33 // preserve the order of the fields. This can be simplified if we end up 34 // having the formatter sort fields alphabetically (logrus does by default) 35 36 dec := json.NewDecoder(strings.NewReader(msg)) 37 38 // look for an initial "{" 39 if token, err := dec.Token(); err != nil { 40 return result, err 41 } else { 42 d, ok := token.(json.Delim) 43 if !ok || d != '{' { 44 return result, errors.New(fmt.Sprintf("input is not a JSON object, found: %v", token)) 45 } 46 } 47 48 // read all key-value pairs 49 for dec.More() { 50 key, err := dec.Token() 51 if err != nil { 52 return result, err 53 } 54 if skey, ok := key.(string); !ok { 55 return result, errors.New("key is not a value string") 56 } else { 57 if !dec.More() { 58 return result, errors.New("missing value pair") 59 } 60 61 switch skey { 62 case "ts": 63 var ts json.Number 64 if err := dec.Decode(&ts); err != nil { 65 return result, err 66 } 67 if time, err := numberToTime(ts); err != nil { 68 return result, err 69 } else { 70 result.Time = time 71 } 72 73 case "level": 74 if s, err := decodeAsString(dec); err != nil { 75 return result, err 76 } else { 77 result.Level = s 78 } 79 80 case "msg": 81 if s, err := decodeAsString(dec); err != nil { 82 return result, err 83 } else { 84 result.Message = s 85 } 86 87 case "caller": 88 if s, err := decodeAsString(dec); err != nil { 89 return result, err 90 } else { 91 result.Caller = s 92 } 93 94 default: 95 var p interface{} 96 if err := dec.Decode(&p); err != nil { 97 return result, err 98 } 99 var f mlog.Field 100 f.Key = skey 101 f.Interface = p 102 result.Fields = append(result.Fields, f) 103 } 104 } 105 } 106 107 // read the "}" 108 if token, err := dec.Token(); err != nil { 109 return result, err 110 } else { 111 d, ok := token.(json.Delim) 112 if !ok || d != '}' { 113 return result, errors.New(fmt.Sprintf("failed to read '}', read: %v", token)) 114 } 115 } 116 117 // make sure nothing else trailing 118 if token, err := dec.Token(); err != io.EOF { 119 return result, err 120 } else if token != nil { 121 return result, errors.New("found trailing data") 122 } 123 124 return result, nil 125 } 126 127 // Translate a number into a time 128 func numberToTime(v json.Number) (time.Time, error) { 129 // Using floating point math to extract the nanoseconds leads to a time that doesn't exactly match the input 130 // Instead, parse out the components from the string representation 131 132 var t time.Time 133 134 // First make sure it is a number... 135 flt, err := v.Float64() 136 if err != nil { 137 return t, err 138 } 139 140 s := v.String() 141 142 if strings.ContainsAny(s, "eE") { 143 // input is in scientific notation. Convert to standard decimal notation 144 s = strconv.FormatFloat(flt, 'f', -1, 64) 145 } 146 147 // extract the seconds and nanoseconds separately 148 var nanos, sec int64 149 150 parts := strings.SplitN(s, ".", 2) 151 sec, err = strconv.ParseInt(parts[0], 10, 64) 152 if err != nil { 153 return t, err 154 } 155 156 if len(parts) == 2 { 157 nanosText := parts[1] + "000000000" 158 nanosText = nanosText[:9] 159 nanos, err = strconv.ParseInt(nanosText, 10, 64) 160 if err != nil { 161 return t, err 162 } 163 } 164 165 t = time.Unix(sec, nanos) 166 return t, nil 167 } 168 169 // Decodes a value from JSON, coercing it to a string value as necessary 170 func decodeAsString(dec *json.Decoder) (s string, err error) { 171 var v interface{} 172 if err = dec.Decode(&v); err != nil { 173 return s, err 174 } 175 var ok bool 176 if s, ok = v.(string); ok { 177 return s, err 178 } 179 s = fmt.Sprint(v) 180 return s, err 181 }