Move to vendor
Signed-off-by: Olivier Gambier <olivier@docker.com>
This commit is contained in:
parent
c8d8e7e357
commit
77e69b9cf3
1268 changed files with 34 additions and 24 deletions
185
vendor/github.com/bugsnag/bugsnag-go/metadata.go
generated
vendored
Normal file
185
vendor/github.com/bugsnag/bugsnag-go/metadata.go
generated
vendored
Normal file
|
@ -0,0 +1,185 @@
|
|||
package bugsnag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MetaData is added to the Bugsnag dashboard in tabs. Each tab is
|
||||
// a map of strings -> values. You can pass MetaData to Notify, Recover
|
||||
// and AutoNotify as rawData.
|
||||
type MetaData map[string]map[string]interface{}
|
||||
|
||||
// Update the meta-data with more information. Tabs are merged together such
|
||||
// that unique keys from both sides are preserved, and duplicate keys end up
|
||||
// with the provided values.
|
||||
func (meta MetaData) Update(other MetaData) {
|
||||
for name, tab := range other {
|
||||
|
||||
if meta[name] == nil {
|
||||
meta[name] = make(map[string]interface{})
|
||||
}
|
||||
|
||||
for key, value := range tab {
|
||||
meta[name][key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add creates a tab of Bugsnag meta-data.
|
||||
// If the tab doesn't yet exist it will be created.
|
||||
// If the key already exists, it will be overwritten.
|
||||
func (meta MetaData) Add(tab string, key string, value interface{}) {
|
||||
if meta[tab] == nil {
|
||||
meta[tab] = make(map[string]interface{})
|
||||
}
|
||||
|
||||
meta[tab][key] = value
|
||||
}
|
||||
|
||||
// AddStruct creates a tab of Bugsnag meta-data.
|
||||
// The struct will be converted to an Object using the
|
||||
// reflect library so any private fields will not be exported.
|
||||
// As a safety measure, if you pass a non-struct the value will be
|
||||
// sent to Bugsnag under the "Extra data" tab.
|
||||
func (meta MetaData) AddStruct(tab string, obj interface{}) {
|
||||
val := sanitizer{}.Sanitize(obj)
|
||||
content, ok := val.(map[string]interface{})
|
||||
if ok {
|
||||
meta[tab] = content
|
||||
} else {
|
||||
// Wasn't a struct
|
||||
meta.Add("Extra data", tab, obj)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Remove any values from meta-data that have keys matching the filters,
|
||||
// and any that are recursive data-structures
|
||||
func (meta MetaData) sanitize(filters []string) interface{} {
|
||||
return sanitizer{
|
||||
Filters: filters,
|
||||
Seen: make([]interface{}, 0),
|
||||
}.Sanitize(meta)
|
||||
|
||||
}
|
||||
|
||||
// The sanitizer is used to remove filtered params and recursion from meta-data.
|
||||
type sanitizer struct {
|
||||
Filters []string
|
||||
Seen []interface{}
|
||||
}
|
||||
|
||||
func (s sanitizer) Sanitize(data interface{}) interface{} {
|
||||
for _, s := range s.Seen {
|
||||
// TODO: we don't need deep equal here, just type-ignoring equality
|
||||
if reflect.DeepEqual(data, s) {
|
||||
return "[RECURSION]"
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitizers are passed by value, so we can modify s and it only affects
|
||||
// s.Seen for nested calls.
|
||||
s.Seen = append(s.Seen, data)
|
||||
|
||||
t := reflect.TypeOf(data)
|
||||
v := reflect.ValueOf(data)
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Bool,
|
||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
|
||||
reflect.Float32, reflect.Float64:
|
||||
return data
|
||||
|
||||
case reflect.String:
|
||||
return data
|
||||
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return s.Sanitize(v.Elem().Interface())
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
ret := make([]interface{}, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
ret[i] = s.Sanitize(v.Index(i).Interface())
|
||||
}
|
||||
return ret
|
||||
|
||||
case reflect.Map:
|
||||
return s.sanitizeMap(v)
|
||||
|
||||
case reflect.Struct:
|
||||
return s.sanitizeStruct(v, t)
|
||||
|
||||
// Things JSON can't serialize:
|
||||
// case t.Chan, t.Func, reflect.Complex64, reflect.Complex128, reflect.UnsafePointer:
|
||||
default:
|
||||
return "[" + t.String() + "]"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s sanitizer) sanitizeMap(v reflect.Value) interface{} {
|
||||
ret := make(map[string]interface{})
|
||||
|
||||
for _, key := range v.MapKeys() {
|
||||
val := s.Sanitize(v.MapIndex(key).Interface())
|
||||
newKey := fmt.Sprintf("%v", key.Interface())
|
||||
|
||||
if s.shouldRedact(newKey) {
|
||||
val = "[REDACTED]"
|
||||
}
|
||||
|
||||
ret[newKey] = val
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (s sanitizer) sanitizeStruct(v reflect.Value, t reflect.Type) interface{} {
|
||||
ret := make(map[string]interface{})
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
|
||||
val := v.Field(i)
|
||||
// Don't export private fields
|
||||
if !val.CanInterface() {
|
||||
continue
|
||||
}
|
||||
|
||||
name := t.Field(i).Name
|
||||
var opts tagOptions
|
||||
|
||||
// Parse JSON tags. Supports name and "omitempty"
|
||||
if jsonTag := t.Field(i).Tag.Get("json"); len(jsonTag) != 0 {
|
||||
name, opts = parseTag(jsonTag)
|
||||
}
|
||||
|
||||
if s.shouldRedact(name) {
|
||||
ret[name] = "[REDACTED]"
|
||||
} else {
|
||||
sanitized := s.Sanitize(val.Interface())
|
||||
if str, ok := sanitized.(string); ok {
|
||||
if !(opts.Contains("omitempty") && len(str) == 0) {
|
||||
ret[name] = str
|
||||
}
|
||||
} else {
|
||||
ret[name] = sanitized
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (s sanitizer) shouldRedact(key string) bool {
|
||||
for _, filter := range s.Filters {
|
||||
if strings.Contains(strings.ToLower(filter), strings.ToLower(key)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue