func joinKeys(keys ...string) string {
	if len(keys) > 0 && keys[0] == "" {
		keys = keys[1:]
	}
	return strings.Join(keys, ".")
}
joinKeys concatenates the keys into a single string with each key separated
by a dot.
package common
import (
	"encoding"
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"github.com/elastic/beats/libbeat/logp"
	"github.com/pkg/errors"
)
const eventDebugSelector = "event"
var eventDebugf = logp.MakeDebug(eventDebugSelector)
var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
type Float float64
func ConvertToGenericEvent(m MapStr) MapStr {
	keys := make([]string, 0, 10)
	event, errs := normalizeMap(m, keys...)
	if len(errs) > 0 {
		logp.Warn("Unsuccessful conversion to generic event: %v errors: %v, "+
			"event=%#v", len(errs), errs, m)
	}
	return event
}
func normalizeMap(m MapStr, keys ...string) (MapStr, []error) {
	var errs []error
	out := make(MapStr, len(m))
	for key, value := range m {
		v, err := normalizeValue(value, append(keys, key)...)
		if len(err) > 0 {
			errs = append(errs, err...)
		}
		if v == nil {
			if logp.IsDebug(eventDebugSelector) {
				eventDebugf("Dropped nil value from event where key=%v", joinKeys(append(keys, key)...))
			}
			continue
		}
		out[key] = v
	}
	return out, errs
}
func normalizeMapStrSlice(maps []MapStr, keys ...string) ([]MapStr, []error) {
	var errs []error
	out := make([]MapStr, 0, len(maps))
	for i, m := range maps {
		normalizedMap, err := normalizeMap(m, append(keys, strconv.Itoa(i))...)
		if len(err) > 0 {
			errs = append(errs, err...)
		}
		out = append(out, normalizedMap)
	}
	return out, errs
}
func normalizeMapStringSlice(maps []map[string]interface{}, keys ...string) ([]MapStr, []error) {
	var errs []error
	out := make([]MapStr, 0, len(maps))
	for i, m := range maps {
		normalizedMap, err := normalizeMap(m, append(keys, strconv.Itoa(i))...)
		if len(err) > 0 {
			errs = append(errs, err...)
		}
		out = append(out, normalizedMap)
	}
	return out, errs
}
func normalizeSlice(v reflect.Value, keys ...string) (interface{}, []error) {
	var errs []error
	var sliceValues []interface{}
	n := v.Len()
	for i := 0; i < n; i++ {
		sliceValue, err := normalizeValue(v.Index(i).Interface(), append(keys, strconv.Itoa(i))...)
		if len(err) > 0 {
			errs = append(errs, err...)
		}
		sliceValues = append(sliceValues, sliceValue)
	}
	return sliceValues, errs
}
func normalizeValue(value interface{}, keys ...string) (interface{}, []error) {
	if value == nil {
		return nil, nil
	}
	switch value.(type) {
	case encoding.TextMarshaler:
		text, err := value.(encoding.TextMarshaler).MarshalText()
		if err != nil {
			return nil, []error{errors.Wrapf(err, "key=%v: error converting %T to string", joinKeys(keys...), value)}
		}
		return string(text), nil
	case string, []string:
	case bool, []bool:
	case int, int8, int16, int32, int64:
	case []int, []int8, []int16, []int32, []int64:
	case uint, uint8, uint16, uint32, uint64:
	case []uint, []uint8, []uint16, []uint32, []uint64:
	case float32, float64:
		return Float(value.(float64)), nil
	case []float32, []float64:
	case complex64, complex128:
	case []complex64, []complex128:
	case Time, []Time:
	case MapStr:
		return normalizeMap(value.(MapStr), keys...)
	case []MapStr:
		return normalizeMapStrSlice(value.([]MapStr), keys...)
	case map[string]interface{}:
		return normalizeMap(value.(map[string]interface{}), keys...)
	case []map[string]interface{}:
		return normalizeMapStringSlice(value.([]map[string]interface{}), keys...)
	default:
		v := reflect.ValueOf(value)
		switch v.Type().Kind() {
		case reflect.Ptr:
			return normalizeValue(followPointer(value), keys...)
		case reflect.Bool:
			return v.Bool(), nil
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			return v.Int(), nil
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			return v.Uint(), nil
		case reflect.Float32, reflect.Float64:
			return Float(v.Float()), nil
		case reflect.Complex64, reflect.Complex128:
			return v.Complex(), nil
		case reflect.String:
			return v.String(), nil
		case reflect.Array, reflect.Slice:
			return normalizeSlice(v, keys...)
		case reflect.Map, reflect.Struct:
			var m MapStr
			err := marshalUnmarshal(value, &m)
			if err != nil {
				return m, []error{errors.Wrapf(err, "key=%v: error converting %T to MapStr", joinKeys(keys...), value)}
			}
			return m, nil
		default:
			return nil, []error{fmt.Errorf("key=%v: error unsupported type=%T value=%#v", joinKeys(keys...), value, value)}
		}
	}
	return value, nil
}
func marshalUnmarshal(in interface{}, out interface{}) error {
	marshaled, err := json.Marshal(in)
	if err != nil {
		return errors.Wrap(err, "error marshalling to JSON")
	}
	err = json.Unmarshal(marshaled, out)
	if err != nil {
		return errors.Wrap(err, "error unmarshalling from JSON")
	}
	return nil
}
func followPointer(v interface{}) interface{} {
	if v == nil || reflect.TypeOf(v).Kind() != reflect.Ptr {
		return v
	}
	val := reflect.ValueOf(v)
	if val.IsNil() {
		return nil
	}
	return val.Elem().Interface()
}