func CommandBefore(ctx *cli.Context) error {
	name := strings.Join(strings.Split(ctx.Command.FullName(), " "), "/")
	event := CreateEvent(name)
	event.AddPayloads(zap.Strings("flags", ctx.FlagNames()))
	ctx.Context = context.WithValue(ctx.Context, EventKey, event)
	return nil
}
Create an event and inject into context
package common
import (
	"context"
	"fmt"
	"github.com/fatih/color"
	"github.com/ghodss/yaml"
	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/object"
	"github.com/pkg/errors"
	"github.com/rogpeppe/go-internal/modfile"
	"github.com/rookie-ninja/rk-common/common"
	"github.com/rookie-ninja/rk-logger"
	"github.com/rookie-ninja/rk-query"
	"github.com/urfave/cli/v2"
	"go.uber.org/zap"
	"go/build"
	"os"
	"path"
	"strings"
	"time"
)
const (
	EventKey = "rkEvent"
	BuildTarget = "target"
)
var (
	confStr = `{
     "level": "info",
     "encoding": "console",
     "outputPaths": ["%s"],
     "errorOutputPaths": ["stderr"],
     "initialFields": {},
     "encoderConfig": {
       "messageKey": "msg",
       "levelKey": "",
       "nameKey": "",
       "timeKey": "",
       "callerKey": "",
       "stacktraceKey": "",
       "callstackKey": "",
       "errorKey": "",
       "timeEncoder": "iso8601",
       "fileKey": "",
       "levelEncoder": "capital",
       "durationEncoder": "second",
       "callerEncoder": "full",
       "nameEncoder": "full"
     },
    "maxsize": 1,
    "maxage": 7,
    "maxbackups": 3,
    "localtime": true,
    "compress": true
   }`
	logger  *zap.Logger
	factory *rkquery.EventFactory
	BuildConfig = &BootConfigForBuild{}
	TargetPkgName = getPkgName()
	TargetGitInfo = getGitInfo()
)
type BootConfigForBuild struct {
	Build struct {
		Type     string   `yaml:"type"`
		Main     string   `yaml:"main"`
		GOOS     string   `yaml:"GOOS"`
		GOARCH   string   `yaml:"GOARCH"`
		Args     []string `yaml:"args"`
		Copy     []string `yaml:"copy"`
		Commands struct {
			Before []string `yaml:"before"`
			After  []string `yaml:"after"`
		} `yaml:"commands"`
		Scripts struct {
			Before []string `yaml:"before"`
			After  []string `yaml:"after"`
		} `yaml:"scripts"`
	} `yaml:"build"`
	Docker struct {
		Build struct {
			Registry string   `yaml:"registry"`
			Tag      string   `yaml:"tag"`
			Args     []string `yaml:"args"`
		} `yaml:"build"`
		Run struct {
			Args []string `yaml:"args"`
		} `yaml:"run"`
	} `yaml:"docker"`
}
func init() {
	userHomeDir, _ := os.UserHomeDir()
	rkDir := path.Join(userHomeDir, ".rk/logs")
	if err := os.MkdirAll(rkDir, os.ModePerm); err != nil {
		color.Yellow("Failed to create rk temp dir.")
		color.Red(err.Error())
	}
	bytes := []byte(fmt.Sprintf(confStr, path.Join(rkDir, "rk.log")))
	logger, _, _ = rklogger.NewZapLoggerWithBytes(bytes, rklogger.JSON)
	factory = rkquery.NewEventFactory(
		rkquery.WithAppName("rk-cmd"),
		rkquery.WithZapLogger(logger))
}
func GetEvent(ctx *cli.Context) rkquery.Event {
	if v := ctx.Context.Value(EventKey); v != nil {
		if event, ok := v.(rkquery.Event); ok {
			return event
		}
	}
	return factory.CreateEventNoop()
}
func CreateEvent(op string) rkquery.Event {
	event := factory.CreateEvent()
	event.SetOperation(op)
	event.SetStartTime(time.Now())
	return event
}
func Finish(event rkquery.Event, err error) {
	if err != nil {
		event.AddErr(err)
		event.SetResCode("Failed")
	} else if len(event.GetResCode()) < 1 {
		event.SetResCode("OK")
	}
	event.SetEndTime(time.Now())
	event.Finish()
}
func Error(err error) error {
	if err != nil {
		color.Red("[Error] %s", err.Error())
	} else {
		color.Red("[Error] internal error occur")
	}
	return err
}
func UnmarshalBootConfig(configFilePath string, config interface{}) error {
	if config == nil {
		return errors.New("Nil config provided")
	}
	if !path.IsAbs(configFilePath) {
		wd, _ := os.Getwd()
		configFilePath = path.Join(wd, configFilePath)
	}
	bytes := rkcommon.TryReadFile(configFilePath)
	if len(bytes) < 1 {
		return errors.New(fmt.Sprintf("Failed to read build.yaml file from path:%s", configFilePath))
	}
	if err := yaml.Unmarshal(bytes, config); err != nil {
		return err
	}
	return nil
}
func GetGoPathBin() string {
	return path.Join(build.Default.GOPATH, "bin")
}
func getPkgName() string {
	if rkcommon.FileExists("go.mod") {
		if bytes := rkcommon.TryReadFile("go.mod"); len(bytes) > 0 {
			return path.Base(modfile.ModulePath(bytes))
		}
	}
	if res, err := os.Getwd(); err == nil {
		return path.Base(res)
	}
	return ""
}
func getGitInfo() *rkcommon.Git {
	res := &rkcommon.Git{
		Commit: &rkcommon.Commit{
			Committer: &rkcommon.Committer{},
		},
	}
	opt := &git.PlainOpenOptions{
		DetectDotGit: true,
	}
	if repo, err := git.PlainOpenWithOptions(".", opt); err == nil {
		if config, e1 := repo.Config(); e1 == nil {
			for _, v := range config.Remotes {
				if len(v.URLs) > 0 {
					res.Url = strings.TrimSuffix(v.URLs[0], ".git")
				}
				break
			}
		}
		var head plumbing.Hash
		if ref, e1 := repo.Head(); e1 == nil {
			head = ref.Hash()
		}
		if iter, e1 := repo.Branches(); e1 == nil {
			iter.ForEach(func(ref *plumbing.Reference) error {
				if ref.Hash() == head {
					res.Branch = ref.Name().Short()
				}
				return nil
			})
		}
		if tag, e1 := repo.TagObject(head); e1 == nil {
			res.Tag = tag.Name
		}
		if commit, e1 := repo.CommitObject(head); e1 == nil {
			res.Commit.Committer.Name = commit.Committer.Name
			res.Commit.Committer.Email = commit.Committer.Email
			res.Commit.Date = commit.Author.When.Format(object.DateFormat)
			res.Commit.Id = commit.ID().String()
			if len(res.Commit.Id) > 7 {
				res.Commit.IdAbbr = commit.ID().String()[:7]
			}
			res.Commit.Sub = commit.Message
		}
	}
	return res
}
func GetRkMetaFromCmd() *rkcommon.RkMeta {
	meta := &rkcommon.RkMeta{}
	meta.Name = TargetPkgName
	meta.Git = TargetGitInfo
	if len(meta.Git.Tag) < 1 {
		if len(meta.Git.Branch) < 1 {
			meta.Version = meta.Git.Commit.IdAbbr
		} else {
			meta.Version = strings.Join([]string{meta.Git.Branch, meta.Git.Commit.IdAbbr}, "-")
		}
	} else {
		meta.Version = meta.Git.Tag
	}
	return meta
}