github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/logging/structure/structure.go (about) 1 // Copyright Monax Industries Limited 2 // SPDX-License-Identifier: Apache-2.0 3 4 package structure 5 6 import ( 7 "encoding/json" 8 "fmt" 9 10 "github.com/go-kit/kit/log" 11 ) 12 13 const ( 14 // Log time (time.Time) 15 TimeKey = "time" 16 // Call site for log invocation (go-stack.Call) 17 CallerKey = "caller" 18 // Trace for log call 19 TraceKey = "trace" 20 // Level name (string) 21 LevelKey = "level" 22 // Channel name in a vector channel logging context 23 ChannelKey = "log_channel" 24 // Log message (string) 25 MessageKey = "message" 26 // Error key 27 ErrorKey = "error" 28 // Tx hash key 29 TxHashKey = "tx_hash" 30 // Captured logging source (like tendermint_log15, stdlib_log) 31 CapturedLoggingSourceKey = "captured_logging_source" 32 // Top-level component (choose one) name 33 ComponentKey = "component" 34 // Tendermint component etc 35 Tendermint = "tendermint" 36 // Vector-valued scope 37 ScopeKey = "scope" 38 // Globally unique identifier persisting while a single instance (root process) 39 // of this program/service is running 40 RunId = "run_id" 41 // Provides special instructions (that may be ignored) to downstream loggers 42 SignalKey = "__signal__" 43 // The sync signal instructs sync-able loggers to sync 44 SyncSignal = "__sync__" 45 ReloadSignal = "__reload__" 46 InfoChannelName = "Info" 47 TraceChannelName = "Trace" 48 ) 49 50 // Pull the specified values from a structured log line into a map. 51 // Assumes keys are single-valued. 52 // Returns a map of the key-values from the requested keys and 53 // the unmatched remainder keyvals as context as a slice of key-values. 54 func ValuesAndContext(keyvals []interface{}, 55 keys ...interface{}) (map[string]interface{}, []interface{}) { 56 57 vals := make(map[string]interface{}, len(keys)) 58 context := make([]interface{}, len(keyvals)) 59 copy(context, keyvals) 60 deletions := 0 61 // We can't really do better than a linear scan of both lists here. N is small 62 // so screw the asymptotics. 63 // Guard against odd-length list 64 for i := 0; i < 2*(len(keyvals)/2); i += 2 { 65 for k := 0; k < len(keys); k++ { 66 if keyvals[i] == keys[k] { 67 // Pull the matching key-value pair into vals to return 68 vals[Stringify(keys[k])] = keyvals[i+1] 69 // Delete the key once it's found 70 keys = DeleteAt(keys, k) 71 // And remove the key-value pair from context 72 context = Delete(context, i-deletions, 2) 73 // Keep a track of how much we've shrunk the context to offset next 74 // deletion 75 deletions += 2 76 break 77 } 78 } 79 } 80 return vals, context 81 } 82 83 // Returns keyvals as a map from keys to vals 84 func KeyValuesMap(keyvals []interface{}) map[string]interface{} { 85 length := len(keyvals) / 2 86 vals := make(map[string]interface{}, length) 87 for i := 0; i < 2*length; i += 2 { 88 vals[Stringify(keyvals[i])] = keyvals[i+1] 89 } 90 return vals 91 } 92 93 func RemoveKeys(keyvals []interface{}, dropKeys ...interface{}) []interface{} { 94 return DropKeys(keyvals, func(key, value interface{}) bool { 95 for _, dropKey := range dropKeys { 96 if key == dropKey { 97 return true 98 } 99 } 100 return false 101 }) 102 } 103 104 func OnlyKeys(keyvals []interface{}, includeKeys ...interface{}) []interface{} { 105 return DropKeys(keyvals, func(key, value interface{}) bool { 106 for _, includeKey := range includeKeys { 107 if key == includeKey { 108 return false 109 } 110 } 111 return true 112 }) 113 } 114 115 // Drops all key value pairs where dropKeyValPredicate is true 116 func DropKeys(keyvals []interface{}, dropKeyValPredicate func(key, value interface{}) bool) []interface{} { 117 keyvalsDropped := make([]interface{}, 0, len(keyvals)) 118 for i := 0; i < 2*(len(keyvals)/2); i += 2 { 119 if !dropKeyValPredicate(keyvals[i], keyvals[i+1]) { 120 keyvalsDropped = append(keyvalsDropped, keyvals[i], keyvals[i+1]) 121 } 122 } 123 return keyvalsDropped 124 } 125 126 // Stateful index that tracks the location of a possible vector value 127 type vectorValueindex struct { 128 // Location of the value belonging to a key in output slice 129 valueIndex int 130 // Whether or not the value is currently a vector 131 vector bool 132 } 133 134 // To help with downstream serialisation 135 type Vector []interface{} 136 137 func (v Vector) Slice() []interface{} { 138 return v 139 } 140 141 func (v Vector) String() string { 142 return fmt.Sprintf("%v", v.Slice()) 143 } 144 145 func (v Vector) MarshalJSON() ([]byte, error) { 146 return json.Marshal(v.Slice()) 147 } 148 149 func (v Vector) MarshalText() ([]byte, error) { 150 return []byte(v.String()), nil 151 } 152 153 // 'Vectorises' values associated with repeated string keys member by collapsing many values into a single vector value. 154 // The result is a copy of keyvals where the first occurrence of each matching key and its first value are replaced by 155 // that key and all of its values in a single slice. 156 func Vectorise(keyvals []interface{}, vectorKeys ...string) []interface{} { 157 // We rely on working against a single backing array, so we use a capacity that is the maximum possible size of the 158 // slice after vectorising (in the case there are no duplicate keys and this is a no-op) 159 outputKeyvals := make([]interface{}, 0, len(keyvals)) 160 // Track the location and vector status of the values in the output 161 valueIndices := make(map[string]*vectorValueindex, len(vectorKeys)) 162 elided := 0 163 for i := 0; i < 2*(len(keyvals)/2); i += 2 { 164 key := keyvals[i] 165 val := keyvals[i+1] 166 167 // Only attempt to vectorise string keys 168 if k, ok := key.(string); ok { 169 if valueIndices[k] == nil { 170 // Record that this key has been seen once 171 valueIndices[k] = &vectorValueindex{ 172 valueIndex: i + 1 - elided, 173 } 174 // Copy the key-value to output with the single value 175 outputKeyvals = append(outputKeyvals, key, val) 176 } else { 177 // We have seen this key before 178 vi := valueIndices[k] 179 if !vi.vector { 180 // This must be the only second occurrence of the key so now vectorise the value 181 outputKeyvals[vi.valueIndex] = Vector([]interface{}{outputKeyvals[vi.valueIndex]}) 182 vi.vector = true 183 } 184 // Grow the vector value 185 outputKeyvals[vi.valueIndex] = append(outputKeyvals[vi.valueIndex].(Vector), val) 186 // We are now running two more elements behind the input keyvals because we have absorbed this key-value pair 187 elided += 2 188 } 189 } else { 190 // Just copy the key-value to the output for non-string keys 191 outputKeyvals = append(outputKeyvals, key, val) 192 } 193 } 194 return outputKeyvals 195 } 196 197 // Return a single value corresponding to key in keyvals 198 func Value(keyvals []interface{}, key interface{}) interface{} { 199 for i := 0; i < 2*(len(keyvals)/2); i += 2 { 200 if keyvals[i] == key { 201 return keyvals[i+1] 202 } 203 } 204 return nil 205 } 206 207 // Maps key values pairs with a function (key, value) -> (new key, new value) 208 func MapKeyValues(keyvals []interface{}, fn func(interface{}, interface{}) (interface{}, interface{})) ([]interface{}, error) { 209 mappedKeyvals := make([]interface{}, 0) 210 for i := 0; i < len(keyvals); { 211 keymap, ok := keyvals[i].(map[string]interface{}) 212 if ok { 213 for key, val := range keymap { 214 k, v := fn(key, val) 215 mappedKeyvals = append(mappedKeyvals, k, v) 216 } 217 i++ 218 } else { 219 if i+1 >= len(keyvals) { 220 return nil, fmt.Errorf("log line contains an odd number of elements so "+ 221 "was dropped: %v", keyvals) 222 } 223 k, v := fn(keyvals[i], keyvals[i+1]) 224 mappedKeyvals = append(mappedKeyvals, k, v) 225 i += 2 226 } 227 } 228 return mappedKeyvals, nil 229 } 230 231 // Deletes n elements starting with the ith from a slice by splicing. 232 // Beware uses append so the underlying backing array will be modified! 233 func Delete(slice []interface{}, i int, n int) []interface{} { 234 return append(slice[:i], slice[i+n:]...) 235 } 236 237 // Delete an element at a specific index and return the contracted list 238 func DeleteAt(slice []interface{}, i int) []interface{} { 239 return Delete(slice, i, 1) 240 } 241 242 // Provides a canonical way to stringify keys 243 func Stringify(v interface{}) string { 244 switch v { 245 // For named keys we want to handle explicitly 246 247 default: 248 // Stringify keys 249 switch k := v.(type) { 250 case string: 251 return k 252 case fmt.Stringer: 253 return k.String() 254 default: 255 return fmt.Sprint(v) 256 } 257 } 258 } 259 260 // Sends the sync signal which causes any syncing loggers to sync. 261 // loggers receiving the signal should drop the signal logline from output 262 func Sync(logger log.Logger) error { 263 return logger.Log(SignalKey, SyncSignal) 264 } 265 266 func Reload(logger log.Logger) error { 267 return logger.Log(SignalKey, ReloadSignal) 268 } 269 270 // Tried to interpret the logline as a signal by matching the last key-value pair as a signal, 271 // returns empty string if no match. The idea with signals is that the should be transmitted to a root logger 272 // as a single key-value pair so we avoid the need to do a linear probe over every log line in order to detect a signal. 273 func Signal(keyvals []interface{}) string { 274 last := len(keyvals) - 1 275 if last > 0 && keyvals[last-1] == SignalKey { 276 signal, ok := keyvals[last].(string) 277 if ok { 278 return signal 279 } 280 } 281 return "" 282 }