func GenerateKeyword(e error) string {
	switch v := e.(type) {
	case Error:
		return v.GenerateKeyword()
	case error:
		return generateKeyWord(e.Error())
	}
	return generateKeyWord(e.Error())
}
generate key word to an error type
package errorx
import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"time"
)
const (
	LcauseBy = 1 << iota
	LdateTime
	Llongfile
)
type Error struct {
	index int
	E           error
	StackTraces []string
	isServiceErr   bool
	serviceErrcode int
	serviceErrmsg  string
	Context map[string]interface{}
	Header  map[string][]string
	ReGenerated bool
	Errors      []error
	Flag        int
	Keyword     string
}
func (e Error) String() string {
	return e.Error()
}
func (e *Error) SetHeader(key string, value string) {
	if e.Header == nil {
		e.Header = make(map[string][]string, 0)
	}
	if e.Header[key] == nil {
		e.Header[key] = make([]string, 0, 10)
	}
	if len(e.Header[key]) == 0 {
		e.Header[key] = append(e.Header[key], value)
	} else {
		e.Header[key][0] = value
	}
}
func (e Error) GetHeader(key string) string {
	if e.Header == nil {
		return ""
	}
	if e.Header[key] == nil || len(e.Header[key]) == 0 {
		return ""
	}
	return e.Header[key][0]
}
func Empty() Error {
	return Error{
		index:       0,
		E:           nil,
		StackTraces: make([]string, 0, 30),
		Context:     make(map[string]interface{}, 0),
		ReGenerated: false,
		Errors:      make([]error, 0, 30),
		Flag:        Llongfile | LcauseBy | LdateTime,
	}
}
func (e Error) Error() string {
	var header = ""
	if len(e.Header) != 0 {
		buf, _ := json.MarshalIndent(e.Header, "  ", "  ")
		header += fmt.Sprintf("header:\n%s\n", buf)
	}
	rs := fmt.Sprintf("%s%s\n", header, e.StackTraceValue())
	if len(e.Context) != 0 {
		buf, _ := json.MarshalIndent(e.Context, "  ", "  ")
		rs += fmt.Sprintf("context:\n%s\n", buf)
	}
	return rs
}
func (e Error) BasicError() string {
	if e.E != nil {
		return e.E.Error()
	}
	return ""
}
func (e Error) StackTrace() string {
	rs := "\n"
	for _, v := range e.StackTraces {
		rs = rs + v + "\n"
	}
	return rs
}
func NewWithHeader(e error, header map[string]interface{}) error {
	if e == nil {
		return nil
	}
	er := New(e).(Error)
	for k, v := range header {
		er.SetHeader(k, ToString(v))
	}
	return er
}
func NewWithAttach(e error, msg interface{}) error {
	if e == nil {
		return nil
	}
	msg = ToString(msg)
	er := New(e).(Error)
	er.SetHeader("attach", msg.(string))
	return er
}
func New(e error) error {
	if e == nil {
		return nil
	}
	switch v := e.(type) {
	case Error:
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(v.Flag, file, line, v.BasicError())
		v.StackTraces = append(v.StackTraces, trace)
		return v
	case error:
		errorX := Empty()
		errorX.E = e
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(Llongfile|LcauseBy|LdateTime, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		return errorX
	}
	return New(errors.New("invalid error type,error type should be official or errorx.Error"))
}
func (e Error) PrintStackTrace() string {
	for _, v := range e.StackTraces {
		fmt.Println(v)
	}
	return strings.Join(e.StackTraces, "\n")
}
func (e Error) StackTraceValue() string {
	rs := make([]string, 0, len(e.StackTraces)+1)
	rs = append(rs, e.StackTraces...)
	return strings.Join(rs, "\n")
}
func Wrap(e error) error {
	if e == nil {
		return nil
	}
	switch v := e.(type) {
	case Error:
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(v.Flag, file, line, v.BasicError())
		v.StackTraces = append(v.StackTraces, trace)
		v.index++
		return v
	case ServiceError:
		errorX := Empty()
		errorX.E = e
		errorX.isServiceErr = true
		errorX.serviceErrcode = v.Errcode
		errorX.serviceErrmsg = v.Errmsg
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(LdateTime|Llongfile|LcauseBy, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		return errorX
	case error:
		errorX := Empty()
		errorX.E = e
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(LdateTime|Llongfile|LcauseBy, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		return errorX
	}
	return Wrap(errors.New("invalid error type,error type should be official or errorx.Error"))
}
func NewFromString(msg string) error {
	e := errors.New(msg)
	switch v := e.(type) {
	case Error:
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(v.Flag, file, line, v.BasicError())
		v.StackTraces = append(v.StackTraces, trace)
		return v
	case ServiceError:
		errorX := Empty()
		errorX.E = e
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(Llongfile|LcauseBy|LdateTime, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		errorX.isServiceErr = true
		errorX.serviceErrcode = v.Errcode
		errorX.serviceErrmsg = v.Errmsg
		return errorX
	case error:
		errorX := Empty()
		errorX.E = e
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(Llongfile|LcauseBy|LdateTime, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		return errorX
	}
	return New(errors.New("invalid error type,error type should be official or errorx.Error"))
}
func NewFromStringWithDepth(msg string, depth int) error {
	e := errors.New(msg)
	switch v := e.(type) {
	case Error:
		_, file, line, _ := runtime.Caller(depth)
		trace := PrintStackFormat(v.Flag, file, line, v.BasicError())
		v.StackTraces = append(v.StackTraces, trace)
		return v
	case error:
		errorX := Empty()
		errorX.E = e
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(depth)
		trace := PrintStackFormat(Llongfile|LcauseBy|LdateTime, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		return errorX
	}
	return New(errors.New("invalid error type,error type should be official or errorx.Error"))
}
func newFromStringWithDepth(msg string, depth int) error {
	e := errors.New(msg)
	switch v := e.(type) {
	case Error:
		_, file, line, _ := runtime.Caller(depth)
		trace := PrintStackFormat(v.Flag, file, line, v.BasicError())
		v.StackTraces = append(v.StackTraces, trace)
		return v
	case ServiceError:
		errorX := Empty()
		errorX.E = e
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(depth)
		trace := PrintStackFormat(Llongfile|LcauseBy|LdateTime, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		errorX.isServiceErr = true
		errorX.serviceErrcode = v.Errcode
		errorX.serviceErrmsg = v.Errmsg
		return errorX
	case error:
		errorX := Empty()
		errorX.E = e
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(depth)
		trace := PrintStackFormat(Llongfile|LcauseBy|LdateTime, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		return errorX
	}
	return New(errors.New("invalid error type,error type should be official or errorx.Error"))
}
func NewFromStringWithHeader(msg string, header map[string]interface{}) error {
	er := NewFromString(msg).(Error)
	for k, v := range header {
		er.SetHeader(k, ToString(v))
	}
	return er
}
func NewFromStringWithHeaderf(format string, msg string, header map[string]interface{}) error {
	er := NewFromStringf(format, msg).(Error)
	for k, v := range header {
		er.SetHeader(k, ToString(v))
	}
	return er
}
func NewFromStringWithAttach(msg string, attach interface{}) error {
	er := NewFromString(msg).(Error)
	er.SetHeader("attach", ToString(attach))
	return er
}
func NewFromStringWithAttachf(format string, msg string, attach interface{}) error {
	er := NewFromStringf(format, msg).(Error)
	er.SetHeader("attach", ToString(attach))
	return er
}
func NewFromStringf(format string, msg ...interface{}) error {
	return newFromStringWithDepth(fmt.Sprintf(format, msg...), 2)
}
func NewWithParam(e error, params ...interface{}) error {
	if e == nil {
		return nil
	}
	if len(params) == 0 {
		return Wrap(e)
	}
	type ErrWithParam struct {
		ErrMsg string      `json:"error"`
		Params interface{} `json:"params"`
	}
	var errorMsg string
	switch v := e.(type) {
	case Error:
		errorMsg = fmt.Sprintf("\n" + strings.Join(v.StackTraces, "\n"))
	case error:
		errorMsg = fmt.Sprintf(v.Error())
	}
	ep := ErrWithParam{}
	ep.ErrMsg = errorMsg
	ep.Params = params
	buf, _ := json.MarshalIndent(ep, "", "  ")
	return NewFromString(fmt.Sprintf("%s", buf))
}
func NewFromStringWithParam(msg string, params ...interface{}) error {
	if len(params) == 0 {
		return NewFromString(msg)
	}
	type ErrWithParam struct {
		ErrMsg string      `json:"error"`
		Params interface{} `json:"params"`
	}
	ep := ErrWithParam{}
	ep.ErrMsg = msg
	ep.Params = params
	buf, _ := json.MarshalIndent(ep, "", "  ")
	return NewFromString(fmt.Sprintf("%s", buf))
}
func GroupErrors(errors ...error) error {
	var tmp error
	var stackTrace = make([]string, 0, 10*len(errors))
	stackTrace = append(stackTrace, "######## Get a bunch of errors ########")
	defer func() {
		stackTrace = append(stackTrace, "######## /Get a bunch of errors ########")
	}()
	for i, e := range errors {
		if e == nil {
			continue
		}
		tmp = New(e)
		stackTrace = append(stackTrace, fmt.Sprintf("\n##### error_%d #####", i))
		stackTrace = append(stackTrace, tmp.(Error).StackTraces...)
		stackTrace = append(stackTrace, fmt.Sprintf("##### /error_%d #####", i))
	}
	return NewFromStackTrace(stackTrace, "an error bunch")
}
func NewFromStackTrace(stackTrace []string, msg string) error {
	e := errors.New(msg)
	v := Empty()
	v.E = e
	v.StackTraces = stackTrace
	v.Errors = append(v.Errors, e)
	_, file, line, _ := runtime.Caller(1)
	trace := PrintStackFormat(v.Flag, file, line, v.Error())
	v.StackTraces = append(v.StackTraces, trace)
	return v
}
func WrapContext(e error, ctx map[string]interface{}) error {
	if e == nil {
		return nil
	}
	switch v := e.(type) {
	case Error:
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(v.Flag, file, line, v.BasicError())
		v.StackTraces = append(v.StackTraces, trace)
		if v.Context == nil || len(v.Context) == 0 {
			v.Context = ctx
		} else {
			for i, va := range ctx {
				_, ok := v.Context[i]
				if !ok {
					v.Context[i] = va
				} else {
					v.Context[fmt.Sprintf("%s_%d", i, v.index)] = va
				}
			}
		}
		return v
	case ServiceError:
		errorX := Empty()
		errorX.E = e
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(LdateTime|Llongfile|LcauseBy, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		if len(ctx) != 0 {
			errorX.Context = ctx
		}
		errorX.isServiceErr = true
		errorX.serviceErrcode = v.Errcode
		errorX.serviceErrmsg = v.Errmsg
		return errorX
	case error:
		errorX := Empty()
		errorX.E = e
		errorX.Errors = append(errorX.Errors, e)
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(LdateTime|Llongfile|LcauseBy, file, line, v.Error())
		errorX.StackTraces = append(errorX.StackTraces, trace)
		if len(ctx) != 0 {
			errorX.Context = ctx
		}
		return errorX
	}
	return Wrap(errors.New("invalid error type,error type should be official or errorx.Error"))
}
func ReGen(old error, new error) error {
	e := Empty()
	e.E = old
	e.ReGenerated = true
	switch o := old.(type) {
	case Error:
		e = o
		e.ReGenerated = true
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(e.Flag, file, line, new.Error())
		e.StackTraces = append(e.StackTraces, trace)
		e.Errors = append(e.Errors, old, new)
	case error:
		_, file, line, _ := runtime.Caller(1)
		trace := PrintStackFormat(e.Flag, file, line, new.Error())
		e.StackTraces = append(e.StackTraces, trace)
		e.Errors = append(e.Errors, old, new)
	}
	return e
}
func MustWrap(e error) Error {
	switch v := e.(type) {
	case Error:
		return v
	case error:
		return New(v).(Error)
	}
	return Empty()
}
func PrintStackFormat(flag int, file string, line int, cause string) string {
	var formatGroup = make([]string, 0, 3)
	var formatArgs = make([]interface{}, 0, 3)
	if flag&LdateTime > 0 {
		formatGroup = append(formatGroup, "%s")
		formatArgs = append(formatArgs, time.Now().Format("2006-01-02 15:04:05"))
	}
	if flag&Llongfile > 0 {
		formatGroup = append(formatGroup, "%s")
		trace := fmt.Sprintf("%s:%d", file, line)
		formatArgs = append(formatArgs, trace)
	}
	if flag&LcauseBy > 0 {
		formatGroup = append(formatGroup, "%s")
		formatArgs = append(formatArgs, cause)
	}
	return fmt.Sprintf(strings.Join(formatGroup, " | "), formatArgs...)
}
func (e Error) GenerateKeyword() string {
	arr := strings.Split((e).StackTraces[len(e.StackTraces)-1], "|")
	core := strings.TrimSpace(arr[len(arr)-1])
	return generateKeyWord(core)
}