From 030e98086136798a8227af1d38bc6a74b89e2ccf Mon Sep 17 00:00:00 2001 From: barry Date: Sun, 7 Sep 2025 23:45:33 +0800 Subject: [PATCH] Feat/error (#48) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 百里(barry) Signed-off-by: barry Signed-off-by: barry --- assert/assert.go | 16 +- assert/assert_test.go | 15 +- assert/must.go | 26 +- assert/must_test.go | 15 +- assert/util.go | 66 +++++ cliutils/utils.go | 14 + cmds/configcmd/cmd.go | 14 +- cmds/envcmd/cmd.go | 37 +++ cmds/protoc-gen-go-cloudevent/internal/gen.go | 2 +- cmds/protoc-gen-go-enum/internal/gen.go | 2 +- cmds/testmain/main.go | 42 +++ cmds/versioncmd/cmd.go | 36 +++ component/cloudevent/client.go | 4 +- component/gormclient/migratecmd/cmd.go | 4 +- component/lifecycle/lifecycle.go | 37 +++ component/natsclient/client.go | 4 +- config/aaa.go | 3 + config/config.go | 64 ++++- config/configs/assets/assets.yaml | 2 +- config/envs.go | 32 +++ config/util.go | 34 ++- config/util_test.go | 13 +- ctxutil/util.go | 19 ++ env/env.go | 47 ++-- env/init.go | 35 --- env/reload.go | 55 ++++ env/util.go | 38 ++- env/util_test.go | 30 ++- errors/aaa.go | 98 +------ errors/errinter/aaa.go | 93 +++++++ errors/errinter/utils.go | 173 +++++++++++++ errors/errors.go | 114 +++------ errors/errutil/util.go | 6 +- errors/util.go | 42 +-- errors/z_code_test.go | 4 +- errors/z_err_code_test.go | 2 + errors/z_error_test.go | 2 +- go.mod | 45 ++-- go.sum | 68 ++--- log/_docs.go | 5 +- log/aaa.go | 6 +- log/context.go | 25 +- log/event.go | 29 +-- log/global.go | 38 ++- log/impl.log.go | 53 ++-- log/impl.slog.go | 73 ++++++ log/impl.std.go | 4 + log/log.go | 15 -- log/logfields/fields.go | 10 + log/{ => loghooks}/hooks.go | 2 +- log/logutil/util.go | 27 ++ log/util.go | 10 +- log/z_log_test.go | 19 +- netutil/util.go | 24 +- pretty/pretty.go | 15 ++ pretty/pretty_test.go | 4 + proto/errorpb/errors.pb.go | 242 +++++++++++------- proto/errorpb/errors.proto | 5 + protoutils/util.go | 11 - recovery/recovery.go | 32 ++- recovery/recovery_test.go | 7 +- running/runtime.go | 14 +- running/util.go | 15 +- stack/trace_test.go | 4 +- syncutil/util.go | 19 ++ utils/utils.go | 2 +- v2/result/api.go | 19 +- v2/result/error.go | 37 ++- v2/result/error_test.go | 7 +- v2/result/interface.go | 2 +- v2/result/proxy.go | 7 +- v2/result/proxy_test.go | 2 +- v2/result/result.go | 54 ++-- v2/result/result_test.go | 11 +- v2/result/resultchecker/checker_test.go | 2 +- v2/result/util.go | 108 ++++++-- vars/vars.go | 46 +++- version/version.go | 25 +- 78 files changed, 1654 insertions(+), 729 deletions(-) create mode 100644 assert/util.go create mode 100644 cliutils/utils.go create mode 100644 cmds/envcmd/cmd.go create mode 100644 cmds/testmain/main.go create mode 100644 cmds/versioncmd/cmd.go create mode 100644 component/lifecycle/lifecycle.go create mode 100644 config/envs.go delete mode 100644 env/init.go create mode 100644 env/reload.go create mode 100644 errors/errinter/aaa.go create mode 100644 errors/errinter/utils.go create mode 100644 log/impl.slog.go delete mode 100644 log/log.go create mode 100644 log/logfields/fields.go rename log/{ => loghooks}/hooks.go (95%) create mode 100644 log/logutil/util.go create mode 100644 syncutil/util.go diff --git a/assert/assert.go b/assert/assert.go index 8748d28c..07db5cea 100644 --- a/assert/assert.go +++ b/assert/assert.go @@ -2,42 +2,42 @@ package assert import ( "fmt" - - "github.com/pubgo/funk/errors" ) +var EnablePrintStack bool + func Assert(b bool, format string, a ...interface{}) { if b { - panic(errors.WrapStack(fmt.Errorf(format, a...))) + must(fmt.Errorf(format, a...)) } } func If(b bool, format string, a ...interface{}) { if b { - panic(errors.WrapStack(fmt.Errorf(format, a...))) + must(fmt.Errorf(format, a...)) } } func T(b bool, format string, a ...interface{}) { if b { - panic(errors.WrapStack(fmt.Errorf(format, a...))) + must(fmt.Errorf(format, a...)) } } func Err(b bool, err error) { if b { - panic(errors.WrapStack(err)) + must(err) } } func Fn(b bool, fn func() error) { if b { - panic(errors.WrapStack(fn())) + must(fn()) } } func Lazy(lazy func() bool, err error) { if lazy() { - panic(errors.WrapStack(err)) + must(err) } } diff --git a/assert/assert_test.go b/assert/assert_test.go index d16e77bf..dc127319 100644 --- a/assert/assert_test.go +++ b/assert/assert_test.go @@ -1,17 +1,20 @@ -package assert +package assert_test import ( "testing" - "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/assert" + "github.com/pubgo/funk/recovery" ) +func init() { + assert.EnablePrintStack = true +} + func TestCheckNil(t *testing.T) { var a *int - defer func() { - errors.Debug(errors.Parse(recover())) - }() + defer recovery.DebugPrint() - Assert(a == nil, "ok") + assert.Assert(a == nil, "ok") } diff --git a/assert/must.go b/assert/must.go index 873996b1..09eee9c5 100644 --- a/assert/must.go +++ b/assert/must.go @@ -2,11 +2,9 @@ package assert import ( "fmt" + "log/slog" "os" "runtime/debug" - - "github.com/pubgo/funk/errors" - "github.com/pubgo/funk/try" ) func Must(err error, args ...interface{}) { @@ -14,16 +12,16 @@ func Must(err error, args ...interface{}) { return } - panic(errors.WrapStack(errors.Wrap(err, fmt.Sprint(args...)))) + must(err, args...) } func MustFn(errFn func() error, args ...interface{}) { - err := try.Try(errFn) + err := try(errFn) if err == nil { return } - panic(errors.WrapStack(errors.Wrap(err, fmt.Sprint(args...)))) + must(err, args...) } func MustF(err error, msg string, args ...interface{}) { @@ -31,12 +29,12 @@ func MustF(err error, msg string, args ...interface{}) { return } - panic(errors.WrapStack(errors.Wrap(err, fmt.Sprintf(msg, args...)))) + must(err, fmt.Sprintf(msg, args...)) } -func Must1[T any](ret T, err error) T { +func Must1[T any](ret T, err error, args ...any) T { if err != nil { - panic(errors.WrapStack(err)) + must(err, args...) } return ret @@ -47,18 +45,18 @@ func Exit(err error, args ...interface{}) { return } - errors.Debug(errors.WrapStack(errors.Wrap(err, fmt.Sprint(args...)))) + slog.Error("os exit with error", "err", err, "msg", fmt.Sprint(args...)) debug.PrintStack() os.Exit(1) } func ExitFn(errFn func() error, args ...interface{}) { - err := try.Try(errFn) + err := try(errFn) if err == nil { return } - errors.Debug(errors.WrapStack(errors.Wrap(err, fmt.Sprint(args...)))) + slog.Error("os exit with error func", "err", err, "msg", fmt.Sprint(args...)) debug.PrintStack() os.Exit(1) } @@ -68,14 +66,14 @@ func ExitF(err error, msg string, args ...interface{}) { return } - errors.Debug(errors.WrapStack(errors.Wrapf(err, msg, args...))) + slog.Error("os exit with error format", "err", err, "msg", fmt.Sprintf(msg, args...)) debug.PrintStack() os.Exit(1) } func Exit1[T any](ret T, err error) T { if err != nil { - errors.Debug(errors.WrapStack(err)) + slog.Error("os exit with error unwrap", "err", err) debug.PrintStack() os.Exit(1) } diff --git a/assert/must_test.go b/assert/must_test.go index e0b9453c..7eea19d6 100644 --- a/assert/must_test.go +++ b/assert/must_test.go @@ -1,9 +1,10 @@ -package assert +package assert_test import ( "fmt" "testing" + assert1 "github.com/pubgo/funk/assert" "github.com/pubgo/funk/errors" "github.com/stretchr/testify/assert" ) @@ -23,12 +24,12 @@ func panicNoErr() (*errBase, error) { func TestPanicErr(t *testing.T) { is := assert.New(t) is.Panics(func() { - ret := Must1(panicErr()) + ret := assert1.Must1(panicErr()) fmt.Println(ret == nil) }) is.NotPanics(func() { - ret := Must1(panicNoErr()) + ret := assert1.Must1(panicNoErr()) fmt.Println(ret.msg) }) } @@ -37,22 +38,22 @@ func TestRespTest(t *testing.T) { defer func() { errors.Debug(errors.Parse(recover())) }() - Must(init1Next()) + assert1.Must(init1Next()) } func TestRespNext(t *testing.T) { - Must(init1Next()) + assert1.Must(init1Next()) } func init1Next() (err error) { - Must(fmt.Errorf("test next")) + assert1.Must(fmt.Errorf("test next")) return nil } func BenchmarkNoPanic(b *testing.B) { for i := 0; i < b.N; i++ { _ = func() (err error) { - Must(nil) + assert1.Must(nil) return }() } diff --git a/assert/util.go b/assert/util.go new file mode 100644 index 00000000..6db7507b --- /dev/null +++ b/assert/util.go @@ -0,0 +1,66 @@ +package assert + +import ( + "fmt" + "log/slog" + "runtime/debug" + + "github.com/pubgo/funk/stack" +) + +func messageFromMsgAndArgs(msgAndArgs ...any) string { + if len(msgAndArgs) == 0 { + return "" + } + + if len(msgAndArgs) == 1 { + if msgAsStr, ok := msgAndArgs[0].(string); ok { + return msgAsStr + } + return fmt.Sprintf("%+v", msgAndArgs[0]) + } + + return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) +} + +func must(err error, messageArgs ...any) { + if err == nil { + return + } + + message := messageFromMsgAndArgs(messageArgs...) + if message == "" { + message = err.Error() + } else { + message = fmt.Sprintf("msg:%s err:%s", message, err.Error()) + } + + if EnablePrintStack { + slog.Error(message) + debug.PrintStack() + } + + panic(message) +} + +func try(fn func() error) (gErr error) { + if fn == nil { + gErr = fmt.Errorf("[fn] is nil") + return + } + + defer func() { + if gErr != nil { + gErr = fmt.Errorf("stack:%s, err:%w", stack.CallerWithFunc(fn).String(), gErr) + } + }() + + defer func() { + if err := recover(); err != nil { + gErr = fmt.Errorf("%v", err) + } + }() + + gErr = fn() + return +} diff --git a/cliutils/utils.go b/cliutils/utils.go new file mode 100644 index 00000000..871332c1 --- /dev/null +++ b/cliutils/utils.go @@ -0,0 +1,14 @@ +package cliutils + +import ( + "os" + "strings" +) + +func IsHelp() bool { + help := strings.TrimSpace(os.Args[len(os.Args)-1]) + if strings.HasSuffix(help, "--help") || strings.HasSuffix(help, "-h") { + return true + } + return false +} diff --git a/cmds/configcmd/cmd.go b/cmds/configcmd/cmd.go index 5dbb09f7..8ff03fa1 100644 --- a/cmds/configcmd/cmd.go +++ b/cmds/configcmd/cmd.go @@ -4,14 +4,15 @@ import ( "context" "fmt" - "github.com/pubgo/dix" - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/config" "github.com/urfave/cli/v3" "gopkg.in/yaml.v3" + + "github.com/pubgo/funk/assert" + "github.com/pubgo/funk/config" + "github.com/pubgo/funk/recovery" ) -func New[Cfg any](di *dix.Dix) *cli.Command { +func New[Cfg any]() *cli.Command { return &cli.Command{ Name: "config", Usage: "config management", @@ -20,8 +21,9 @@ func New[Cfg any](di *dix.Dix) *cli.Command { Name: "show", Description: "show config data", Action: func(ctx context.Context, command *cli.Command) error { - fmt.Println("config path:", config.GetConfigPath()) - fmt.Println("config raw data:", string(assert.Must1(yaml.Marshal(config.Load[Cfg]().T)))) + defer recovery.Exit() + fmt.Println("config path:\n", config.GetConfigPath()) + fmt.Println("config raw data:\n", string(assert.Must1(yaml.Marshal(config.Load[Cfg]().T)))) return nil }, }, diff --git a/cmds/envcmd/cmd.go b/cmds/envcmd/cmd.go new file mode 100644 index 00000000..4e192833 --- /dev/null +++ b/cmds/envcmd/cmd.go @@ -0,0 +1,37 @@ +package envcmd + +import ( + "context" + "fmt" + + "github.com/urfave/cli/v3" + + "github.com/pubgo/funk/config" + "github.com/pubgo/funk/env" + "github.com/pubgo/funk/pretty" + "github.com/pubgo/funk/recovery" +) + +func New() *cli.Command { + return &cli.Command{ + Name: "envs", + Usage: "show all envs", + Action: func(ctx context.Context, command *cli.Command) error { + defer recovery.Exit() + + env.Reload() + + fmt.Println("config path:", config.GetConfigPath()) + envs := config.LoadEnvConfigMap(config.GetConfigPath()) + for name, cfg := range envs { + envData := env.Get(name) + if envData != "" { + cfg.Default = envData + } + } + + pretty.Println(envs) + return nil + }, + } +} diff --git a/cmds/protoc-gen-go-cloudevent/internal/gen.go b/cmds/protoc-gen-go-cloudevent/internal/gen.go index 431626ca..93de8fec 100644 --- a/cmds/protoc-gen-go-cloudevent/internal/gen.go +++ b/cmds/protoc-gen-go-cloudevent/internal/gen.go @@ -122,7 +122,7 @@ func GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.Generated info := subjects[subName] var keyName = fmt.Sprintf("%sCloudEventKey", info.mth.GoName) genFile.Commentf("%s /%s/%s", keyName, info.srv.Desc.FullName(), info.mth.GoName) - genFile.Commentf(strings.TrimSpace(info.mth.Comments.Leading.String())) + genFile.Comment(strings.TrimSpace(info.mth.Comments.Leading.String())) genFile.Const(). Id(keyName). Op("="). diff --git a/cmds/protoc-gen-go-enum/internal/gen.go b/cmds/protoc-gen-go-enum/internal/gen.go index 36e8f09f..ecb6b6a9 100644 --- a/cmds/protoc-gen-go-enum/internal/gen.go +++ b/cmds/protoc-gen-go-enum/internal/gen.go @@ -11,7 +11,7 @@ import ( func GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile { filename := file.GeneratedFilenamePrefix + ".pb.enum.go" genFile := jen.NewFile(string(file.GoPackageName)) - genFile.HeaderComment("Code generated by protoc-gen-go-sql. DO NOT EDIT.") + genFile.HeaderComment("Code generated by protoc-gen-go-enum. DO NOT EDIT.") genFile.HeaderComment("versions:") genFile.HeaderComment(fmt.Sprintf("- protoc-gen-go-enum %s", version)) genFile.HeaderComment(fmt.Sprintf("- protoc %s", protocVersion(gen))) diff --git a/cmds/testmain/main.go b/cmds/testmain/main.go new file mode 100644 index 00000000..ff3b9fb9 --- /dev/null +++ b/cmds/testmain/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "context" + "fmt" + "os" + "sort" + + "github.com/moby/term" + "github.com/pubgo/funk/assert" + "github.com/pubgo/funk/cliutils" + "github.com/pubgo/funk/cmds/versioncmd" + "github.com/pubgo/funk/ctxutil" + "github.com/pubgo/funk/version" + "github.com/urfave/cli/v3" +) + +func main() { + app := &cli.Command{ + Name: "testmain", + Suggest: true, + UseShortOptionHandling: true, + ShellComplete: cli.DefaultAppComplete, + Version: version.Version(), + Commands: []*cli.Command{ + versioncmd.New(), + }, + Before: func(ctx context.Context, command *cli.Command) (context.Context, error) { + if !term.IsTerminal(os.Stdin.Fd()) { + return ctx, fmt.Errorf("stdin is not a terminal") + } + + if cliutils.IsHelp() { + return ctx, cli.ShowAppHelp(command) + } + return ctx, nil + }, + } + + sort.Sort(cli.FlagsByName(app.Flags)) + assert.Exit(app.Run(ctxutil.Signal(), os.Args)) +} diff --git a/cmds/versioncmd/cmd.go b/cmds/versioncmd/cmd.go new file mode 100644 index 00000000..dfceabfe --- /dev/null +++ b/cmds/versioncmd/cmd.go @@ -0,0 +1,36 @@ +package versioncmd + +import ( + "context" + "fmt" + + "github.com/urfave/cli/v3" + + "github.com/pubgo/funk/pretty" + "github.com/pubgo/funk/recovery" + "github.com/pubgo/funk/running" + "github.com/pubgo/funk/version" +) + +func New() *cli.Command { + return &cli.Command{ + Name: "version", + Usage: fmt.Sprintf("%s version info", version.Project()), + Commands: []*cli.Command{ + { + Name: "validate", + Usage: "show version info", + Action: func(ctx context.Context, command *cli.Command) error { + defer recovery.Exit() + running.CheckVersion() + return nil + }, + }, + }, + Action: func(ctx context.Context, command *cli.Command) error { + defer recovery.Exit() + pretty.Println(running.GetSysInfo()) + return nil + }, + } +} diff --git a/component/cloudevent/client.go b/component/cloudevent/client.go index 2d608a42..b3aeab86 100644 --- a/component/cloudevent/client.go +++ b/component/cloudevent/client.go @@ -11,6 +11,7 @@ import ( "github.com/nats-io/nats.go/jetstream" ants "github.com/panjf2000/ants/v2" "github.com/pubgo/funk/assert" + "github.com/pubgo/funk/component/lifecycle" "github.com/pubgo/funk/component/natsclient" "github.com/pubgo/funk/errors" "github.com/pubgo/funk/errors/errcheck" @@ -22,7 +23,6 @@ import ( "github.com/pubgo/funk/try" "github.com/pubgo/funk/typex" "github.com/pubgo/funk/version" - "github.com/pubgo/lava/core/lifecycle" "github.com/rs/zerolog" "github.com/samber/lo" "google.golang.org/protobuf/proto" @@ -454,7 +454,7 @@ func (c *Client) doConsume() (r error) { c.doConsumeHandler(streamName, consumerName, jobSubjects, concurrent), c.doErrHandler(streamName, consumerName), )) - c.p.Lc.BeforeStop(func() { con.Stop() }) + c.p.Lc.BeforeStop(lifecycle.WrapNoCtxErr(con.Stop)) } } return diff --git a/component/gormclient/migratecmd/cmd.go b/component/gormclient/migratecmd/cmd.go index f02f6e6e..191e644d 100644 --- a/component/gormclient/migratecmd/cmd.go +++ b/component/gormclient/migratecmd/cmd.go @@ -46,10 +46,10 @@ func New(di *dix.Dix) *cli.Command { Destination: &id, }, }, - Before: func(ctx context.Context, command *cli.Command) error { + Before: func(ctx context.Context, command *cli.Command) (context.Context, error) { p := dix.Inject(di, new(params)) options.TableName = p.Db.TablePrefix + migrates.DefaultConfig.TableName - return nil + return ctx, nil }, Commands: []*cli.Command{ { diff --git a/component/lifecycle/lifecycle.go b/component/lifecycle/lifecycle.go new file mode 100644 index 00000000..8a71eb76 --- /dev/null +++ b/component/lifecycle/lifecycle.go @@ -0,0 +1,37 @@ +package lifecycle + +import "context" + +func WrapNoError(fn func(context.Context)) ExecFunc { + return func(ctx context.Context) error { fn(ctx); return nil } +} + +func WrapNoCtx(fn func() error) ExecFunc { + return func(ctx context.Context) error { return fn() } +} + +func WrapNoCtxErr(fn func()) ExecFunc { + return func(ctx context.Context) error { fn(); return nil } +} + +type ExecFunc = func(context.Context) error + +type Executor struct { + Exec ExecFunc +} + +type Handler func(lc Lifecycle) + +type Lifecycle interface { + AfterStop(f ExecFunc) + BeforeStop(f ExecFunc) + AfterStart(f ExecFunc) + BeforeStart(f ExecFunc) +} + +type Getter interface { + GetAfterStops() []Executor + GetBeforeStops() []Executor + GetAfterStarts() []Executor + GetBeforeStarts() []Executor +} diff --git a/component/natsclient/client.go b/component/natsclient/client.go index 9a424ce8..1ca3cc27 100644 --- a/component/natsclient/client.go +++ b/component/natsclient/client.go @@ -5,9 +5,9 @@ import ( "github.com/nats-io/nats.go" "github.com/pubgo/funk/assert" + "github.com/pubgo/funk/component/lifecycle" "github.com/pubgo/funk/log" "github.com/pubgo/funk/running" - "github.com/pubgo/lava/core/lifecycle" ) type Param struct { @@ -50,7 +50,7 @@ func New(p Param) *Client { log.Info().Bool("is_connected", nc.IsConnected()).Msg("nats connection ...") - p.Lc.BeforeStop(func() { nc.Close() }) + p.Lc.BeforeStop(lifecycle.WrapNoCtxErr(nc.Close)) return &Client{Param: p, logger: logger, Conn: nc} } diff --git a/config/aaa.go b/config/aaa.go index 678c98d0..bbe763fe 100644 --- a/config/aaa.go +++ b/config/aaa.go @@ -11,4 +11,7 @@ type Resources struct { // PatchResources resource config not required to exist PatchResources []string `yaml:"patch_resources"` + + // PatchEnvs config file or path, not required to exist + PatchEnvs []string `yaml:"patch_envs"` } diff --git a/config/config.go b/config/config.go index 9b79a6ee..52bd4b00 100644 --- a/config/config.go +++ b/config/config.go @@ -1,6 +1,7 @@ package config import ( + "bytes" "fmt" "os" "path/filepath" @@ -9,16 +10,18 @@ import ( "strings" "github.com/a8m/envsubst" + "github.com/samber/lo" + "gopkg.in/yaml.v3" + "github.com/pubgo/funk/assert" "github.com/pubgo/funk/errors" "github.com/pubgo/funk/log" "github.com/pubgo/funk/pathutil" + "github.com/pubgo/funk/pretty" "github.com/pubgo/funk/recovery" "github.com/pubgo/funk/result" "github.com/pubgo/funk/typex" "github.com/pubgo/funk/vars" - "github.com/samber/lo" - "gopkg.in/yaml.v3" ) const ( @@ -49,12 +52,43 @@ func GetConfigData(cfgPath string) (_ []byte, gErr error) { }) configBytes = result.Of(os.ReadFile(cfgPath)).Expect("failed to read config data: %s", cfgPath) + configBytes = cfgFormat(configBytes, &config{workDir: filepath.Dir(cfgPath)}) configBytes = result.Of(envsubst.Bytes(configBytes)).Expect("failed to handler config env data: %s", cfgPath) - configBytes = []byte(cfgFormat(string(configBytes), &config{workDir: filepath.Dir(cfgPath)})) return configBytes, nil } -func LoadFromPath[T any](val *T, cfgPath string) { +func LoadEnvConfigMap(cfgPath string) EnvConfigMap { return loadEnvConfigMap(cfgPath) } + +func loadEnvConfigMap(cfgPath string) EnvConfigMap { + var res Resources + configBytes := result.Of(os.ReadFile(cfgPath)).Expect("failed to read config data: %s", cfgPath) + assert.Must(yaml.Unmarshal(configBytes, &res), "failed to unmarshal resource config") + + parentDir := filepath.Dir(cfgPath) + var envCfgMap EnvConfigMap + for _, envPath := range res.PatchEnvs { + envPath = filepath.Join(parentDir, envPath) + if pathutil.IsNotExist(envPath) { + log.Warn().Str("env_path", envPath).Msg("env config cfgPath not found") + continue + } + + pathList := listAllPath(envPath).Expect("failed to list envPath: %s", envPath) + for _, p := range pathList { + envConfigBytes := result.Of(os.ReadFile(p)).Expect("failed to handler env config data, path=%s", p) + envConfigBytes = bytes.TrimSpace(envConfigBytes) + if len(envConfigBytes) == 0 { + continue + } + + assert.MustF(yaml.Unmarshal(envConfigBytes, &envCfgMap), "failed to unmarshal env config, data=%s path=%s", envConfigBytes, p) + } + } + initEnv(envCfgMap) + return envCfgMap +} + +func LoadFromPath[T any](val *T, cfgPath string) EnvConfigMap { defer recovery.Exit(func(err error) error { log.Err(err).Str("config_path", cfgPath).Msg("failed to load config") return err @@ -75,6 +109,8 @@ func LoadFromPath[T any](val *T, cfgPath string) { Msg("config type not correct") } + var envCfgMap = loadEnvConfigMap(cfgPath) + configBytes := result.Of(GetConfigData(cfgPath)).Expect("failed to handler config data") defer recovery.Exit(func(err error) error { log.Err(err). @@ -90,7 +126,7 @@ func LoadFromPath[T any](val *T, cfgPath string) { Str("config_data", string(configBytes)). Str("config_path", cfgPath). Msg("failed to unmarshal config") - return + return nil } parentDir := filepath.Dir(cfgPath) @@ -159,12 +195,20 @@ func LoadFromPath[T any](val *T, cfgPath string) { return pathList })...) - assert.Exit(Merge(val, cfgList...), "failed to merge config") + err := Merge(val, cfgList...) + if err != nil { + for _, cfg := range cfgList { + pretty.Simple().Println(cfg) + } + log.Fatal().Err(err).Msg("failed to merge config") + } + return envCfgMap } type Cfg[T any] struct { - T T - P *T + T T + P *T + EnvCfg *EnvConfigMap } func Load[T any]() Cfg[T] { @@ -175,6 +219,6 @@ func Load[T any]() Cfg[T] { } var cfg T - LoadFromPath(&cfg, configPath) - return Cfg[T]{T: cfg, P: &cfg} + cfgMap := LoadFromPath(&cfg, configPath) + return Cfg[T]{T: cfg, P: &cfg, EnvCfg: lo.ToPtr(cfgMap)} } diff --git a/config/configs/assets/assets.yaml b/config/configs/assets/assets.yaml index 8ade7918..e6ea108a 100644 --- a/config/configs/assets/assets.yaml +++ b/config/configs/assets/assets.yaml @@ -2,4 +2,4 @@ assets: test_md: test_abc: secret: ${{embed("test.md")}} - path_dir: ${{get_path_dir()}} + path_dir: ${{path_dir()}} diff --git a/config/envs.go b/config/envs.go new file mode 100644 index 00000000..bec1490d --- /dev/null +++ b/config/envs.go @@ -0,0 +1,32 @@ +package config + +import ( + "strings" + + "github.com/pubgo/funk/env" + "github.com/samber/lo" +) + +type EnvConfigMap map[string]*EnvConf + +type EnvConf struct { + Name string `yaml:"name"` + Description string `yaml:"description"` + Default string `yaml:"default"` + Required bool `yaml:"required"` + Example string `yaml:"example"` + Versions string `yaml:"versions"` + Tags string `yaml:"tags"` +} + +func initEnv(envMap EnvConfigMap) { + for name, cfg := range envMap { + envData := env.Get(name) + envData = strings.TrimSpace(lo.Ternary(envData != "", envData, cfg.Default)) + if cfg.Required && envData == "" { + panic("env " + cfg.Name + " is required") + } + + env.Set(name, envData).Must() + } +} diff --git a/config/util.go b/config/util.go index 3e3a6b82..10e01f0d 100644 --- a/config/util.go +++ b/config/util.go @@ -177,7 +177,7 @@ func unmarshalOneOrList[T any](list *[]T, value *yaml.Node) error { if value.Kind == yaml.SequenceNode { return value.Decode(list) } - return errors.Format("unmarshalled node: %v", value.Value) + return errors.Errorf("unmarshalled node: %v", value.Value) } func listAllPath(dirOrPath string) (ret result.Result[[]string]) { @@ -214,12 +214,24 @@ type config struct { workDir string } +var registerMap = make(map[string]any) + +func RegisterExpr(name string, expr any) { + if registerMap[name] != nil { + panic(fmt.Sprintf("expr:%s has existed", name)) + } + registerMap[name] = expr +} + func getEnvData(cfg *config) map[string]any { - return map[string]any{ + exprEnv := map[string]any{ "env": env.Map(), "get_path_dir": func() string { return cfg.workDir }, + "path_dir": func() string { + return cfg.workDir + }, "embed": func(name string) string { if name == "" { return "" @@ -237,11 +249,19 @@ func getEnvData(cfg *config) map[string]any { return strings.TrimSpace(base64.StdEncoding.EncodeToString(d)) }, } + + for k, v := range registerMap { + if exprEnv[k] != nil { + panic(fmt.Sprintf("expr:%s has existed", k)) + } + exprEnv[k] = v + } + return exprEnv } -func cfgFormat(template string, cfg *config) string { - tpl := fasttemplate.New(template, "${{", "}}") - return tpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { +func cfgFormat(template []byte, cfg *config) []byte { + tpl := fasttemplate.New(string(template), "${{", "}}") + return []byte(tpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { tag = strings.TrimSpace(tag) evalData, err := eval(tag, cfg) if err != nil { @@ -257,14 +277,14 @@ func cfgFormat(template string, cfg *config) string { } return w.Write(bytes.TrimSpace(data)) - }) + })) } func eval(code string, cfg *config) (any, error) { envData := getEnvData(cfg) data, err := expr.Eval(strings.TrimSpace(code), envData) if err != nil { - return nil, errors.WrapCaller(err) + return nil, errors.Wrapf(err, "failed to eval expr:%q", code) } return data, nil } diff --git a/config/util_test.go b/config/util_test.go index 4afc35d9..a3ef1dc0 100644 --- a/config/util_test.go +++ b/config/util_test.go @@ -1,6 +1,7 @@ package config import ( + "bytes" _ "embed" "os" "sort" @@ -28,18 +29,18 @@ var genYaml string func TestExpr(t *testing.T) { os.Setenv("testAbc", "hello") - env.Init() + env.Reload() - assert.Equal(t, cfgFormat("${{env.TEST_ABC}}", &config{}), "hello") - assert.Equal(t, cfgFormat(`${{embed("configs/assets/secret")}}`, &config{}), strings.TrimSpace(`MTIzNDU2CjEyMzQ1NgoxMjM0NTYKMTIzNDU2CjEyMzQ1NgoxMjM0NTYKMTIzNDU2CjEyMzQ1Ng==`)) + assert.Equal(t, string(cfgFormat([]byte("${{env.TEST_ABC}}"), &config{})), "hello") + assert.Equal(t, string(cfgFormat([]byte(`${{embed("configs/assets/secret")}}`), &config{})), strings.TrimSpace(`MTIzNDU2CjEyMzQ1NgoxMjM0NTYKMTIzNDU2CjEyMzQ1NgoxMjM0NTYKMTIzNDU2CjEyMzQ1Ng==`)) var dd, err = os.ReadFile("configs/assets/assets.yaml") assert.NoError(t, err) - var dd1 = strings.TrimSpace(cfgFormat(string(dd), &config{workDir: "configs/assets"})) + var dd1 = bytes.TrimSpace(cfgFormat(dd, &config{workDir: "configs/assets"})) var cfg testCfg - assert.NoError(t, yaml.Unmarshal([]byte(dd1), &cfg)) + assert.NoError(t, yaml.Unmarshal(dd1, &cfg)) - assert.Equal(t, dd1, strings.TrimSpace(genYaml)) + assert.Equal(t, string(dd1), strings.TrimSpace(genYaml)) } func TestEnv(t *testing.T) { diff --git a/ctxutil/util.go b/ctxutil/util.go index 218fb890..1e010eb0 100644 --- a/ctxutil/util.go +++ b/ctxutil/util.go @@ -2,6 +2,9 @@ package ctxutil import ( "context" + "os" + "os/signal" + "syscall" "time" "github.com/samber/lo" @@ -66,3 +69,19 @@ func GetTimeout(ctx context.Context) *time.Duration { } return nil } + +func Signal() context.Context { + ctx, cancel := context.WithCancel(context.Background()) + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL) + go func() { + defer cancel() + select { + case <-ch: + break + case <-ctx.Done(): + break + } + }() + return ctx +} diff --git a/env/env.go b/env/env.go index 3d40d44e..f41da03a 100644 --- a/env/env.go +++ b/env/env.go @@ -1,7 +1,8 @@ package env import ( - "log" + "fmt" + "log/slog" "os" "strconv" "strings" @@ -9,27 +10,34 @@ import ( "github.com/a8m/envsubst" "github.com/joho/godotenv" "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/result" + "github.com/pubgo/funk/pathutil" + "github.com/pubgo/funk/v2/result" + "github.com/samber/lo" ) -func Set(key, value string) error { - return os.Setenv(KeyHandler(key), value) +func Set(key, value string) result.Error { + return result.ErrOf(os.Setenv(KeyHandler(key), value)) +} + +func GetDefault(name string, defaultVal string) string { + val := Get(name) + return lo.If(val != "", val).Else(defaultVal) } func Get(names ...string) string { var val string - GetWith(&val, names...) + GetVal(&val, names...) return trim(val) } func MustGet(names ...string) string { var val string - GetWith(&val, names...) + GetVal(&val, names...) assert.If(val == "", "env not found, names=%q", names) return trim(val) } -func GetWith(val *string, names ...string) { +func GetVal(val *string, names ...string) { for _, name := range names { env, ok := Lookup(name) env = trim(env) @@ -48,7 +56,7 @@ func GetBoolVal(val *bool, names ...string) { v, err := strconv.ParseBool(dt) if err != nil { - log.Printf("env: failed to parse string to bool, err=%v\n", err) + slog.Error(fmt.Sprintf("env: failed to parse string to bool, keys=%q value=%s err=%v", names, dt, err)) return } @@ -63,7 +71,7 @@ func GetIntVal(val *int, names ...string) { v, err := strconv.Atoi(dt) if err != nil { - log.Printf("env: failed to parse string to int, err=%v\n", err) + slog.Error(fmt.Sprintf("env: failed to parse string to int, keys=%q value=%s err=%v", names, dt, err)) return } @@ -76,9 +84,9 @@ func GetFloatVal(val *float64, names ...string) { return } - v, err := strconv.ParseFloat(dt, 32) + v, err := strconv.ParseFloat(dt, 64) if err != nil { - log.Printf("env: failed to parse string to float, err=%v\n", err) + slog.Error(fmt.Sprintf("env: failed to parse string to float, keys=%q value=%s err=%v", names, dt, err)) return } @@ -89,12 +97,12 @@ func Lookup(key string) (string, bool) { return os.LookupEnv(Key(key)) } -func Delete(key string) error { - return os.Unsetenv(Key(key)) +func Delete(key string) result.Error { + return result.ErrOf(os.Unsetenv(Key(key))) } func Expand(value string) result.Result[string] { - return result.Of(envsubst.String(value)) + return result.Wrap(envsubst.String(value)) } func Map() map[string]string { @@ -110,7 +118,12 @@ func Key(key string) string { return KeyHandler(key) } -func Load(filenames ...string) { - assert.Must(godotenv.Load(filenames...)) - Init() +func LoadFiles(files ...string) (r result.Error) { + files = lo.Filter(files, func(item string, index int) bool { return pathutil.IsExist(item) }) + if result.CatchErr(&r, godotenv.Load(files...)) { + return + } + + loadEnv() + return } diff --git a/env/init.go b/env/init.go deleted file mode 100644 index 84e70ffc..00000000 --- a/env/init.go +++ /dev/null @@ -1,35 +0,0 @@ -package env - -import ( - "os" - "strings" -) - -func Init() { - initEnv() -} - -// 环境变量处理, key转大写, 同时把`-./`转换为`_` -// a-b=>a_b, a.b=>a_b, a/b=>a_b -func initEnv() { - for _, env := range os.Environ() { - kvs := strings.SplitN(env, "=", 2) - if len(kvs) != 2 { - continue - } - - var rawKey = kvs[0] - key, ok := Normalize(rawKey) - if !ok { - _ = os.Unsetenv(rawKey) - continue - } - - _ = os.Unsetenv(rawKey) - _ = os.Setenv(key, kvs[1]) - } -} - -func init() { - initEnv() -} diff --git a/env/reload.go b/env/reload.go new file mode 100644 index 00000000..9c4cb993 --- /dev/null +++ b/env/reload.go @@ -0,0 +1,55 @@ +package env + +import ( + "os" + "strings" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +func Reload() { + loadEnv() +} + +// Init reload env +// Deprecated: use Reload instead. +func Init() { + loadEnv() +} + +// 环境变量处理, key转大写, 同时把`-./`转换为`_` +// a-b=>a_b, a.b=>a_b, a/b=>a_b +func loadEnv() { + envPrefix := getEnvPrefix() + logger := log.With().Str("operation", "reload_env").Logger() + envPrefixEventFn := func(e *zerolog.Event) { + e.Dict("env_prefix", zerolog.Dict().Str("key", PrefixKey).Str("value", envPrefix)) + } + logRecord(logger.Info(), envPrefixEventFn).Msg("reload env") + + for _, env := range os.Environ() { + kvs := strings.SplitN(env, "=", 2) + if len(kvs) != 2 { + logRecord(logger.Error()).Msg("split env error") + continue + } + + envKey := trim(kvs[0]) + _ = os.Unsetenv(envKey) + + if envKey == "" || + strings.HasPrefix(envKey, "_") || + strings.HasPrefix(envKey, "=") || + !hasEnvPrefix(envKey, envPrefix) { + logRecord(logger.Warn()).Msgf("unset env, key=%s", envKey) + continue + } + + key, ok := Normalize(envKey) + if ok { + setOk := os.Setenv(key, kvs[1]) == nil + logRecord(logger.Info()).Msgf("reset env, old_key=%s new_key=%s set_ok=%v", envKey, key, setOk) + } + } +} diff --git a/env/util.go b/env/util.go index d5ed792e..ca2f5544 100644 --- a/env/util.go +++ b/env/util.go @@ -1,11 +1,35 @@ package env import ( + "os" "strings" - strcase "github.com/ettle/strcase" + "github.com/ettle/strcase" + "github.com/rs/zerolog" + + "github.com/pubgo/funk/log/logfields" + "github.com/pubgo/funk/log/logutil" ) +var logFn = func(e *zerolog.Event) { + e.Str(logfields.Module, "env") +} + +const PrefixKey = "ENV_PREFIX" + +func hasEnvPrefix(key string, prefix string) bool { + return strings.HasPrefix(strings.ToUpper(key), strings.ToUpper(prefix)) +} + +func getEnvPrefix() string { + prefix := strings.TrimSpace(os.Getenv(PrefixKey)) + if prefix != "" { + prefix = strings.ReplaceAll(prefix+"_", "__", "_") + } + return strings.ToUpper(prefix) +} + +var trim = strings.TrimSpace var replacer = strcase.NewCaser( true, map[string]bool{"SSL": true, "HTML": false}, @@ -15,10 +39,14 @@ var replacer = strcase.NewCaser( strcase.SplitAcronym, strcase.PreserveNumberFormatting, )) -var trim = strings.TrimSpace func KeyHandler(key string) string { - return strings.ToUpper(trim(strings.ReplaceAll(replacer.ToSNAKE(key), "__", "_"))) + key = strings.ToUpper(replacer.ToSNAKE(key)) + envPrefix := getEnvPrefix() + if envPrefix != "" { + key = envPrefix + "_" + strings.TrimPrefix(key, envPrefix) + } + return strings.ToUpper(trim(strings.ReplaceAll(key, "__", "_"))) } // Normalize a-b=>a_b, a.b=>a_b, a/b=>a_b @@ -30,3 +58,7 @@ func Normalize(key string) (string, bool) { return KeyHandler(key), true } + +func logRecord(evt *zerolog.Event, funcs ...func(e *zerolog.Event)) *zerolog.Event { + return logutil.Record(evt, append(funcs, logFn)...) +} diff --git a/env/util_test.go b/env/util_test.go index 1846b4d9..b231df49 100644 --- a/env/util_test.go +++ b/env/util_test.go @@ -1,13 +1,39 @@ -package env +package env_test import ( + "os" + "strings" "testing" + "github.com/pubgo/funk/env" + "github.com/pubgo/funk/pretty" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "github.com/samber/lo" "github.com/stretchr/testify/assert" ) func TestNormalize(t *testing.T) { - k, ok := Normalize("aA-bS3_AK/c.d") + k, ok := env.Normalize("aA-bS3_AK/c.d") assert.True(t, ok) assert.Equal(t, k, "A_A_B_S3_AK_C_D") } + +func TestEnvPrefix(t *testing.T) { + log.Logger = log.Hook(zerolog.HookFunc(func(e *zerolog.Event, level zerolog.Level, message string) { + if strings.HasPrefix(message, "unset not match env") { + e.Discard() + } + })) + + env.Reload() + pretty.Println("env_keys", lo.Keys(env.Map())) + + env.Set(env.PrefixKey, "test").Must() + env.Set("test_hello", "world").Must() + env.Reload() + + envMap := env.Map() + assert.Equal(t, envMap["TEST_HELLO"], "world") + pretty.Println(os.Environ()) +} diff --git a/errors/aaa.go b/errors/aaa.go index 66aa1dfd..5fe40d0d 100644 --- a/errors/aaa.go +++ b/errors/aaa.go @@ -1,93 +1,15 @@ package errors import ( - "encoding/json" - "fmt" - - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" -) - -var ( - _ json.Marshaler = (Tags)(nil) - _ fmt.Formatter = (Tags)(nil) + "github.com/pubgo/funk/errors/errinter" ) -type Maps map[string]any - -func (t Maps) Tags() Tags { - tags := make(Tags, 0, len(t)) - for k, v := range t { - tags = append(tags, Tag{K: k, V: v}) - } - return tags -} - -type Tags []Tag - -func (t Tags) Format(f fmt.State, verb rune) { - tags := make(map[string]any, len(t)) - for i := range t { - tags[t[i].K] = t[i].V - } - - data, err := json.Marshal(tags) - if err != nil { - fmt.Fprintf(f, "%v", err) - } else { - fmt.Fprintln(f, string(data)) - } -} - -func (t Tags) ToMap() map[string]string { - var data = make(map[string]string, len(t)) - for _, tag := range t { - data[tag.K] = fmt.Sprintf("%v", tag.V) - } - return data -} - -func (t Tags) MarshalJSON() ([]byte, error) { - tags := make(map[string]any, len(t)) - for i := range t { - tags[t[i].K] = t[i].V - } - return json.Marshal(tags) -} - -type Tag struct { - K string - V any -} - -func (t Tag) String() string { - return fmt.Sprintf("%s: %v", t.K, t.V) -} - -type ErrUnwrap interface { - Unwrap() error -} - -type ErrIs interface { - Is(error) bool -} - -type ErrAs interface { - As(any) bool -} - -type Error interface { - ID() string - Kind() string - Error() string - String() string - MarshalJSON() ([]byte, error) -} - -type ErrorProto interface { - Proto() proto.Message -} - -type GRPCStatus interface { - GRPCStatus() *status.Status -} +type Maps = errinter.Maps +type Tags = errinter.Tags +type Tag = errinter.Tag +type ErrIs = errinter.ErrIs +type ErrAs = errinter.ErrAs +type ErrUnwrap = errinter.ErrUnwrap +type Error = errinter.Error +type ErrorProto = errinter.ErrorProto +type GRPCStatus = errinter.GRPCStatus diff --git a/errors/errinter/aaa.go b/errors/errinter/aaa.go new file mode 100644 index 00000000..f40f718c --- /dev/null +++ b/errors/errinter/aaa.go @@ -0,0 +1,93 @@ +package errinter + +import ( + "encoding/json" + "fmt" + + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +type Error interface { + ID() string + Kind() string + Error() string + String() string + MarshalJSON() ([]byte, error) +} + +type ErrUnwrap interface { + Unwrap() error +} + +type ErrorProto interface { + Proto() proto.Message +} + +type GRPCStatus interface { + GRPCStatus() *status.Status +} + +var ( + _ json.Marshaler = (Tags)(nil) + _ fmt.Formatter = (Tags)(nil) +) + +type Maps map[string]any + +func (t Maps) Tags() Tags { + tags := make(Tags, 0, len(t)) + for k, v := range t { + tags = append(tags, Tag{K: k, V: v}) + } + return tags +} + +type Tags []Tag + +func (t Tags) Format(f fmt.State, verb rune) { + tags := make(map[string]any, len(t)) + for i := range t { + tags[t[i].K] = t[i].V + } + + data, err := json.Marshal(tags) + if err != nil { + fmt.Fprintf(f, "%v", err) + } else { + fmt.Fprintln(f, string(data)) + } +} + +func (t Tags) ToMap() map[string]string { + var data = make(map[string]string, len(t)) + for _, tag := range t { + data[tag.K] = fmt.Sprintf("%v", tag.V) + } + return data +} + +func (t Tags) MarshalJSON() ([]byte, error) { + tags := make(map[string]any, len(t)) + for i := range t { + tags[t[i].K] = t[i].V + } + return json.Marshal(tags) +} + +type Tag struct { + K string + V any +} + +func (t Tag) String() string { + return fmt.Sprintf("%s: %v", t.K, t.V) +} + +type ErrIs interface { + Is(error) bool +} + +type ErrAs interface { + As(any) bool +} diff --git a/errors/errinter/utils.go b/errors/errinter/utils.go new file mode 100644 index 00000000..e407a674 --- /dev/null +++ b/errors/errinter/utils.go @@ -0,0 +1,173 @@ +package errinter + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "strings" + "sync" + + "github.com/k0kubun/pp/v3" + "github.com/rs/zerolog/log" + "github.com/samber/lo" + "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/structpb" + + "github.com/pubgo/funk" + "github.com/pubgo/funk/log/logutil" + "github.com/pubgo/funk/pretty" + "github.com/pubgo/funk/proto/errorpb" +) + +func ParseError(val interface{}) error { + if funk.IsNil(val) { + return nil + } + + switch v := val.(type) { + case nil: + return nil + case error: + return v + case string: + return errors.New(v) + case []byte: + return errors.New(string(v)) + default: + return errors.New(SimplePrint(v)) + } +} + +var Simple = sync.OnceValue(func() *pp.PrettyPrinter { + printer := pp.New() + printer.SetColoringEnabled(false) + printer.SetExportedOnly(false) + printer.SetOmitEmpty(true) + printer.SetMaxDepth(3) + return printer +}) + +func SimplePrint(v interface{}) string { + return strings.ReplaceAll(Simple().Sprint(v), "\n", "") +} + +func GetErrorId(err error) string { + if err == nil { + return "" + } + + for err != nil { + if v, ok := err.(Error); ok { + return v.ID() + } + + err = Unwrap(err) + } + + return "" +} + +func Unwrap(err error) error { + u, ok := err.(ErrUnwrap) + if !ok { + return nil + } + return u.Unwrap() +} + +func ParseErrToPb(err error) proto.Message { + switch err1 := err.(type) { + case nil: + return nil + case ErrorProto: + return err1.Proto() + case GRPCStatus: + return err1.GRPCStatus().Proto() + case proto.Message: + return err1 + default: + return &errorpb.ErrMsg{Msg: err.Error(), Detail: fmt.Sprintf("%v", err)} + } +} + +func Debug(err error) { + if err == nil { + return + } + + if _err, ok := err.(fmt.Stringer); ok { + _, _ = fmt.Fprintln(os.Stderr, _err.String()) + return + } + + pretty.SetDefaultMaxDepth(20) + pretty.Println(err) +} + +func MustTagsToAny(tags ...*errorpb.Tag) []*anypb.Any { + if len(tags) == 0 { + return nil + } + + return lo.Map(tags, func(item *errorpb.Tag, index int) *anypb.Any { + return MustProtoToAny(item) + }) +} + +func MustStructToAny(p map[string]any) *anypb.Any { + if p == nil { + return nil + } + + pb, err := structpb.NewStruct(p) + if err != nil { + log.Err(err). + Any("params", p). + Func(logutil.WithNotice()). + Stack(). + Msgf("failed to encode map-any to struct protobuf") + return anyToProtobuf(p) + } else { + return MustProtoToAny(pb) + } +} + +func anyToProtobuf(v any) *anypb.Any { + data, err := json.Marshal(v) + if err != nil { + return &anypb.Any{ + TypeUrl: "type.googleapis.com/google.protobuf.StringValue", + Value: []byte(fmt.Sprintf("err:%s detail:%#v", err.Error(), v)), + } + } + return &anypb.Any{ + TypeUrl: "type.googleapis.com/google.protobuf.Struct", + Value: data, + } +} + +func MustProtoToAny(p proto.Message) *anypb.Any { + switch p := p.(type) { + case nil: + return nil + case *anypb.Any: + return p + } + + pb, err := anypb.New(p) + if err != nil { + params := prototext.Format(p) + log.Err(err). + Str("protobuf", params). + Func(logutil.WithNotice()). + Stack(). + Msgf("failed to encode protobuf message to any protobuf") + pb, _ = anypb.New(structpb.NewStringValue(params)) + return pb + } + + return pb +} diff --git a/errors/errors.go b/errors/errors.go index f98f0818..1f8768c5 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -3,19 +3,17 @@ package errors import ( "errors" "fmt" - "os" "reflect" "runtime/debug" - "github.com/pubgo/funk/pretty" - "github.com/pubgo/funk/proto/errorpb" - "github.com/pubgo/funk/stack" "github.com/rs/xid" - "github.com/rs/zerolog/log" "github.com/samber/lo" - "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" + + "github.com/pubgo/funk/errors/errinter" + "github.com/pubgo/funk/proto/errorpb" + "github.com/pubgo/funk/stack" ) func IfErr(err error, fn func(err error) error) error { @@ -26,8 +24,8 @@ func IfErr(err error, fn func(err error) error) error { return fn(err) } -func New(msg string) error { - return WrapCaller(&Err{Msg: msg, id: xid.New().String()}, 1) +func New(msg string, tags ...Tag) error { + return WrapCaller(&Err{Msg: msg, id: xid.New().String(), Tags: tags}, 1) } // NewFmt @@ -46,28 +44,8 @@ func Errorf(msg string, args ...interface{}) error { return WrapCaller(&Err{Msg: fmt.Sprintf(msg, args...), id: xid.New().String()}, 1) } -func NewTags(msg string, tags ...Tag) error { - return WrapCaller(&Err{Msg: msg, Tags: tags, id: xid.New().String()}, 1) -} - -func Parse(val interface{}) error { - return parseError(val) -} - -func Debug(err error) { - if err == nil { - return - } - - err = parseError(err) - if _err, ok := err.(fmt.Stringer); ok { - _, _ = fmt.Fprintln(os.Stderr, _err.String()) - return - } - - pretty.SetDefaultMaxDepth(20) - pretty.Println(err) -} +func Parse(val interface{}) error { return errinter.ParseError(val) } +func Debug(err error) { errinter.Debug(err) } func Is(err, target error) bool { return errors.Is(err, target) @@ -93,6 +71,30 @@ func UnwrapEach(err error, call func(e error) bool) { } } +func AsA[T any](err error) (*T, bool) { + var target T + val := reflect.ValueOf(&target) + typ := val.Type() + if typ.Kind() != reflect.Ptr || val.IsNil() { + panic("errors: target must be a non-nil pointer") + } + + targetType := typ.Elem() + for err != nil { + if reflect.TypeOf(err).AssignableTo(targetType) { + val.Elem().Set(reflect.ValueOf(err)) + return &target, true + } + + if x, ok := err.(ErrAs); ok && x.As(&target) { + return &target, true + } + + err = Unwrap(err) + } + return &target, false +} + func As(err error, target any) bool { if target == nil { panic("errors: target cannot be nil") @@ -266,50 +268,8 @@ func T(k string, v any) Tag { return Tag{K: k, V: v} } -func MustProtoToAny(p proto.Message) *anypb.Any { - switch p := p.(type) { - case nil: - return nil - case *anypb.Any: - return p - } - - pb, err := anypb.New(p) - if err != nil { - log.Err(err).Str("protobuf", prototext.Format(p)).Msgf("failed to encode protobuf message to any") - return nil - } else { - return pb - } -} - -func ParseErrToPb(err error) proto.Message { - switch err1 := err.(type) { - case nil: - return nil - case ErrorProto: - return err1.Proto() - case GRPCStatus: - return err1.GRPCStatus().Proto() - case proto.Message: - return err1 - default: - return &errorpb.ErrMsg{Msg: err.Error(), Detail: fmt.Sprintf("%v", err)} - } -} - -func GetErrorId(err error) string { - if err == nil { - return "" - } - - for err != nil { - if v, ok := err.(Error); ok { - return v.ID() - } - - err = Unwrap(err) - } - - return "" -} +func MustTagsToAny(tags ...*errorpb.Tag) []*anypb.Any { return errinter.MustTagsToAny(tags...) } +func MustStructToAny(p map[string]any) *anypb.Any { return errinter.MustStructToAny(p) } +func MustProtoToAny(p proto.Message) *anypb.Any { return errinter.MustProtoToAny(p) } +func ParseErrToPb(err error) proto.Message { return errinter.ParseErrToPb(err) } +func GetErrorId(err error) string { return errinter.GetErrorId(err) } diff --git a/errors/errutil/util.go b/errors/errutil/util.go index b1cf1a19..7e9a7571 100644 --- a/errors/errutil/util.go +++ b/errors/errutil/util.go @@ -9,7 +9,6 @@ import ( "strings" jjson "github.com/goccy/go-json" - "github.com/kr/pretty" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/anypb" @@ -17,6 +16,7 @@ import ( "github.com/pubgo/funk/errors" "github.com/pubgo/funk/generic" "github.com/pubgo/funk/log" + "github.com/pubgo/funk/pretty" "github.com/pubgo/funk/proto/errorpb" "github.com/pubgo/funk/version" ) @@ -29,7 +29,7 @@ func Json(err error) []byte { err = errors.Parse(err) data, err := jjson.Marshal(err) if err != nil { - log.Err(err).Stack().Str("err_stack", pretty.Sprint(err)).Msg("failed to marshal error") + log.Err(err).Stack().Str("err_stack", pretty.SimplePrint(err)).Msg("failed to marshal error") panic(fmt.Errorf("failed to marshal error, err=%w", err)) } return data @@ -43,7 +43,7 @@ func JsonPretty(err error) []byte { err = errors.Parse(err) data, err := jjson.MarshalIndent(err, " ", " ") if err != nil { - log.Err(err).Stack().Str("err_stack", pretty.Sprint(err)).Msg("failed to marshal error") + log.Err(err).Stack().Str("err_stack", pretty.SimplePrint(err)).Msg("failed to marshal error") panic(fmt.Errorf("failed to marshal error, err=%w", err)) } return data diff --git a/errors/util.go b/errors/util.go index 658ce54a..275938c7 100644 --- a/errors/util.go +++ b/errors/util.go @@ -3,19 +3,17 @@ package errors import ( "bytes" "encoding/json" - "errors" "fmt" "strings" - "github.com/kr/pretty" - "github.com/pubgo/funk/convert" - "github.com/pubgo/funk/errors/errinter" - "github.com/pubgo/funk/generic" - "github.com/pubgo/funk/proto/errorpb" - "github.com/pubgo/funk/stack" "github.com/rs/xid" "github.com/samber/lo" "google.golang.org/protobuf/proto" + + "github.com/pubgo/funk/errors/errinter" + "github.com/pubgo/funk/pretty" + "github.com/pubgo/funk/proto/errorpb" + "github.com/pubgo/funk/stack" ) func cloneAndCheck(code *errorpb.ErrCode) *errorpb.ErrCode { @@ -50,23 +48,6 @@ func handleGrpcError(err error) error { } } -func parseError(val interface{}) error { - if generic.IsNil(val) { - return nil - } - - switch v := val.(type) { - case error: - return v - case string: - return errors.New(v) - case []byte: - return errors.New(convert.B2S(v)) - default: - return &Err{Msg: fmt.Sprintf("%v", v), Detail: pretty.Sprint(v)} - } -} - func errStringify(buf *bytes.Buffer, err error) { if err == nil { return @@ -108,12 +89,17 @@ func errJsonify(err error) map[string]any { func strFormat(f fmt.State, verb rune, err Error) { switch verb { case 'v': - data, err := err.MarshalJSON() - if err != nil { - fmt.Fprintln(f, err.Error()) + if f.Flag('#') { + fmt.Fprint(f, pretty.SimplePrint(err)) } else { - fmt.Fprintln(f, string(data)) + data, err := err.MarshalJSON() + if err != nil { + fmt.Fprintln(f, err.Error()) + } else { + fmt.Fprintln(f, string(data)) + } } + case 's', 'q': fmt.Fprintln(f, err.String()) } diff --git a/errors/z_code_test.go b/errors/z_code_test.go index d4c6b6fd..16be6e5e 100644 --- a/errors/z_code_test.go +++ b/errors/z_code_test.go @@ -15,7 +15,7 @@ func TestWrapCaller(t *testing.T) { return errors.WrapCaller(err, 1) } - assert.Contains(t, fmt.Sprint(ff()), "z_code_test.go:20 TestWrapCaller") + assert.Contains(t, fmt.Sprint(ff()), "z_code_test.go:18 TestWrapCaller") } func TestCodeErr(t *testing.T) { @@ -47,7 +47,7 @@ func TestCodeErr(t *testing.T) { err = errors.WrapFn(err, func() errors.Tags { return errors.Tags{ - {"key", "map value"}, + errors.T("key", "map value"), } }) diff --git a/errors/z_err_code_test.go b/errors/z_err_code_test.go index a251c28e..8ab09ff8 100644 --- a/errors/z_err_code_test.go +++ b/errors/z_err_code_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/proto/errorpb" "github.com/pubgo/funk/proto/testcodepb" ) @@ -15,4 +16,5 @@ func TestErrCode(t *testing.T) { } t.Log(errors.As(err1, testcodepb.TestErrCodeDbConn)) + t.Log(errors.AsA[errorpb.ErrCode](err1)) } diff --git a/errors/z_error_test.go b/errors/z_error_test.go index 324d8d8e..06466973 100644 --- a/errors/z_error_test.go +++ b/errors/z_error_test.go @@ -31,7 +31,7 @@ func TestFormat(t *testing.T) { err = errors.WrapFn(err, func() errors.Tags { return errors.Tags{ - {"key", "map value"}, + errors.T("key", "map value"), } }) diff --git a/go.mod b/go.mod index 675f7f0f..fa4733f5 100644 --- a/go.mod +++ b/go.mod @@ -1,19 +1,18 @@ module github.com/pubgo/funk -go 1.22 +go 1.23.0 require ( dario.cat/mergo v1.0.0 entgo.io/ent v0.13.1 github.com/DATA-DOG/go-sqlmock v1.5.2 - github.com/a8m/envsubst v1.3.0 + github.com/a8m/envsubst v1.4.2 github.com/bradleyjkemp/memviz v0.2.3 github.com/dave/jennifer v1.7.0 github.com/deckarep/golang-set/v2 v2.6.0 github.com/dustin/go-humanize v1.0.0 github.com/ettle/strcase v0.2.0 - github.com/expr-lang/expr v1.16.9 - github.com/flosch/pongo2/v6 v6.0.0 + github.com/expr-lang/expr v1.17.5 github.com/goccy/go-json v0.10.2 github.com/gopherjs/gopherjs v1.17.2 github.com/hashicorp/go-version v1.6.0 @@ -22,36 +21,37 @@ require ( github.com/invopop/jsonschema v0.7.0 github.com/jinzhu/copier v0.4.0 github.com/joho/godotenv v1.5.1 - github.com/k0kubun/pp/v3 v3.2.0 - github.com/kr/pretty v0.3.1 + github.com/k0kubun/pp/v3 v3.5.0 github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-sqlite3 v1.14.16 github.com/mitchellh/mapstructure v1.5.0 + github.com/moby/term v0.5.0 github.com/nats-io/nats.go v1.37.0 github.com/open2b/scriggo v0.56.1 github.com/panjf2000/ants/v2 v2.10.0 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/phuslu/goid v1.0.0 + github.com/projectdiscovery/machineid v0.0.0-20250715113114-c77eb3567582 github.com/pubgo/dix v0.3.15 - github.com/pubgo/lava v0.2.20 github.com/rs/xid v1.5.0 github.com/rs/zerolog v1.33.0 - github.com/samber/lo v1.47.0 - github.com/stretchr/testify v1.9.0 + github.com/samber/lo v1.51.0 + github.com/samber/slog-common v0.19.0 + github.com/stretchr/testify v1.10.0 github.com/testcontainers/testcontainers-go v0.30.0 github.com/testcontainers/testcontainers-go/modules/postgres v0.30.0 github.com/tidwall/gjson v1.17.1 github.com/tidwall/match v1.1.1 - github.com/urfave/cli/v3 v3.0.0-alpha9 + github.com/urfave/cli/v3 v3.3.8 github.com/valyala/fastrand v1.1.0 github.com/valyala/fasttemplate v1.2.2 go.etcd.io/bbolt v1.3.7 go.etcd.io/etcd/client/v3 v3.5.9 go.uber.org/atomic v1.10.0 - golang.org/x/crypto v0.24.0 + golang.org/x/crypto v0.38.0 golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb - golang.org/x/sys v0.21.0 - golang.org/x/text v0.16.0 + golang.org/x/sys v0.33.0 + golang.org/x/text v0.26.0 google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 google.golang.org/grpc v1.66.1 google.golang.org/protobuf v1.34.3-0.20240816073751-94ecbc261689 @@ -106,15 +106,14 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.17.7 // indirect - github.com/kr/text v0.2.0 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/user v0.1.0 // indirect - github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect @@ -124,7 +123,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/shirou/gopsutil/v3 v3.23.12 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect @@ -132,21 +131,23 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zclconf/go-cty v1.8.0 // indirect go.etcd.io/etcd/api/v3 v3.5.9 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.26.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 // indirect go.opentelemetry.io/otel/metric v1.26.0 // indirect + go.opentelemetry.io/otel/sdk v1.26.0 // indirect go.opentelemetry.io/otel/trace v1.26.0 // indirect + go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.17.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/tools v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect gorm.io/datatypes v1.0.7 // indirect gorm.io/hints v1.1.0 // indirect diff --git a/go.sum b/go.sum index 43c21cb3..657141dd 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= -github.com/a8m/envsubst v1.3.0 h1:GmXKmVssap0YtlU3E230W98RWtWCyIZzjtf1apWWyAg= -github.com/a8m/envsubst v1.3.0/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= +github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg= +github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= @@ -73,12 +73,10 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= -github.com/expr-lang/expr v1.16.9 h1:WUAzmR0JNI9JCiF0/ewwHB1gmcGw5wW7nWt8gc6PpCI= -github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/expr-lang/expr v1.17.5 h1:i1WrMvcdLF249nSNlpQZN1S6NXuW9WaOfF5tPi3aw3k= +github.com/expr-lang/expr v1.17.5/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flosch/pongo2/v6 v6.0.0 h1:lsGru8IAzHgIAw6H2m4PCyleO58I40ow6apih0WprMU= -github.com/flosch/pongo2/v6 v6.0.0/go.mod h1:CuDpFm47R0uGGE7z13/tTlt1Y6zdxvr2RLT5LJhsHEU= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -211,8 +209,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/k0kubun/pp/v3 v3.2.0 h1:h33hNTZ9nVFNP3u2Fsgz8JXiF5JINoZfFq4SvKJwNcs= -github.com/k0kubun/pp/v3 v3.2.0/go.mod h1:ODtJQbQcIRfAD3N+theGCV1m/CBxweERz2dapdz1EwA= +github.com/k0kubun/pp/v3 v3.5.0 h1:iYNlYA5HJAJvkD4ibuf9c8y6SHM0QFhaBuCqm1zHp0w= +github.com/k0kubun/pp/v3 v3.5.0/go.mod h1:5lzno5ZZeEeTV/Ky6vs3g6d1U3WarDrH8k240vMtGro= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -244,8 +242,9 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -301,15 +300,16 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/projectdiscovery/machineid v0.0.0-20250715113114-c77eb3567582 h1:eR+0HE//Ciyfwy3HC7fjRyKShSJHYoX2Pv7pPshjK/Q= +github.com/projectdiscovery/machineid v0.0.0-20250715113114-c77eb3567582/go.mod h1:3G3BRKui7nMuDFAZKR/M2hiOLtaOmyukT20g88qRQjI= github.com/pubgo/dix v0.3.15 h1:DLjXfnyhcxT3skM1pZi60i/QgnUEg9nM6CI8wom7gVc= github.com/pubgo/dix v0.3.15/go.mod h1:0j+i8YYn4vJnsJQCsyHXUGovR+Mgkh3uZPRhacw09us= -github.com/pubgo/lava v0.2.20 h1:MSEmuFKQ+VM9kQEDzwdU/dfqKtQlevPyq1zKl1A+/p8= -github.com/pubgo/lava v0.2.20/go.mod h1:tbY4GlOKzR14uuqaIimkBNC0oWAzsBolnOwGkhGv41A= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -317,8 +317,10 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= -github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= +github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI= +github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= +github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI= +github.com/samber/slog-common v0.19.0/go.mod h1:dTz+YOU76aH007YUU0DffsXNsGFQRQllPQh9XyNoA3M= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -350,8 +352,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E= github.com/testcontainers/testcontainers-go v0.30.0/go.mod h1:K+kHNGiM5zjklKjgTtcrEetF3uhWbMUyqAQoyoh8Pf0= github.com/testcontainers/testcontainers-go/modules/postgres v0.30.0 h1:D3HFqpZS90iRGAN7M85DFiuhPfvYvFNnx8urQ6mPAvo= @@ -366,8 +368,8 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/urfave/cli/v3 v3.0.0-alpha9 h1:P0RMy5fQm1AslQS+XCmy9UknDXctOmG/q/FZkUFnJSo= -github.com/urfave/cli/v3 v3.0.0-alpha9/go.mod h1:0kK/RUFHyh+yIKSfWxwheGndfnrvYSmYFVeKCh03ZUc= +github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E= +github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8= @@ -376,8 +378,6 @@ github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= @@ -440,8 +440,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -449,8 +449,8 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -462,14 +462,14 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -495,8 +495,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -506,8 +506,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -522,8 +522,8 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/log/_docs.go b/log/_docs.go index 47b0b9ab..60ec87d1 100644 --- a/log/_docs.go +++ b/log/_docs.go @@ -1,3 +1,6 @@ package log -// https://github.com/phuslu/log +// github.com/phuslu/log +// github.com/rs/zerolog +// slog +// zap log diff --git a/log/aaa.go b/log/aaa.go index 56092120..c4468d64 100644 --- a/log/aaa.go +++ b/log/aaa.go @@ -6,16 +6,12 @@ import ( "github.com/rs/zerolog" ) -const ( - ModuleName = "module" -) - type ( Map = map[string]any Hook = zerolog.Hook Event = zerolog.Event Level = zerolog.Level - EnableChecker = func(ctx context.Context, lvl Level, nameOrMessage string, fields Map) bool + EnableChecker = func(ctx context.Context, lvl Level, name, message string, fields Map) bool ) type Logger interface { diff --git a/log/context.go b/log/context.go index c2f2aa94..6b2ffdec 100644 --- a/log/context.go +++ b/log/context.go @@ -11,7 +11,7 @@ type ( ctxMapFieldKey struct{} ) -func LoggerFromCtx(ctx context.Context, loggers ...Logger) Logger { +func GetFromCtx(ctx context.Context, loggers ...Logger) Logger { defaultLog := stdLog if len(loggers) > 0 { defaultLog = loggers[0] @@ -28,7 +28,7 @@ func LoggerFromCtx(ctx context.Context, loggers ...Logger) Logger { return defaultLog } -func CreateLoggerCtx(ctx context.Context, ll Logger) context.Context { +func CreateCtxWithLogger(ctx context.Context, ll Logger) context.Context { if ll == nil || ctx == nil { panic("ctx or log param is nil") } @@ -88,26 +88,27 @@ func isLogDisabled(ctx context.Context) bool { return b && ok } -func createFieldCtx(ctx context.Context, mm Map) context.Context { +type fieldMap struct { + fields Map + name string +} + +func createFieldCtx(ctx context.Context, field *fieldMap) context.Context { if ctx == nil { panic("ctx is nil") } - if len(mm) == 0 { - return ctx - } - - return context.WithValue(ctx, ctxMapFieldKey{}, mm) + return context.WithValue(ctx, ctxMapFieldKey{}, field) } -func getFieldFromCtx(ctx context.Context) Map { +func getFieldFromCtx(ctx context.Context) *fieldMap { if ctx == nil { - return make(Map) + return nil } - field, ok := ctx.Value(ctxMapFieldKey{}).(Map) + field, ok := ctx.Value(ctxMapFieldKey{}).(*fieldMap) if ok { return field } - return make(Map) + return nil } diff --git a/log/event.go b/log/event.go index ce45574b..823be722 100644 --- a/log/event.go +++ b/log/event.go @@ -13,9 +13,6 @@ type event struct { buf []byte } -//go:linkname putEvent github.com/rs/zerolog.putEvent -func putEvent(e *Event) - func WithEvent(evt *Event) func(e *Event) { return func(e *Event) { if !e.Enabled() { @@ -63,17 +60,17 @@ func GetEventBuf(evt *Event) []byte { return append(convertEvent(evt).buf, '}') } -func mergeEvent(to *Event, from ...*Event) *Event { +func mergeEvent(target *Event, from ...*Event) *Event { if len(from) == 0 { - return to + return target } - if to == nil { - to = zerolog.Dict() + if target == nil { + target = zerolog.Dict() } - to1 := convertEvent(to) - to1.buf = bytes.TrimSpace(bytes.Trim(to1.buf, ",")) + targetEvent := convertEvent(target) + targetEvent.buf = bytes.TrimSpace(bytes.Trim(targetEvent.buf, ",")) for i := range from { if from[i] == nil { continue @@ -90,14 +87,14 @@ func mergeEvent(to *Event, from ...*Event) *Event { continue } - if len(to1.buf) == 0 { - to1.buf = append(to1.buf, '{') - to1.buf = append(to1.buf, buf...) + if len(targetEvent.buf) == 0 { + targetEvent.buf = append(targetEvent.buf, '{') + targetEvent.buf = append(targetEvent.buf, buf...) } else { - to1.buf = append(to1.buf, ","...) - to1.buf = append(to1.buf, buf...) + targetEvent.buf = append(targetEvent.buf, ","...) + targetEvent.buf = append(targetEvent.buf, buf...) } } - to1.buf = bytes.TrimSpace(to1.buf) - return to + targetEvent.buf = bytes.TrimSpace(targetEvent.buf) + return target } diff --git a/log/global.go b/log/global.go index 07754a2f..13b8f506 100644 --- a/log/global.go +++ b/log/global.go @@ -7,24 +7,29 @@ import ( "os" "time" - "github.com/rs/zerolog" - zlog "github.com/rs/zerolog/log" - "google.golang.org/protobuf/encoding/prototext" - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/errors/errinter" "github.com/pubgo/funk/generic" + + "github.com/rs/zerolog" + zlog "github.com/rs/zerolog/log" ) var ( - logEnableChecker = func(ctx context.Context, lvl Level, nameOrMessage string, fields Map) bool { return true } + logEnableChecker EnableChecker logGlobalHook = zerolog.HookFunc(func(e *zerolog.Event, level zerolog.Level, message string) { if logEnableChecker == nil { return } ctx := e.GetCtx() - if logEnableChecker(ctx, level, message, getFieldFromCtx(ctx)) { + field := getFieldFromCtx(ctx) + + if field == nil { + return + } + + if logEnableChecker(ctx, level, field.name, message, field.fields) { return } @@ -38,20 +43,13 @@ var ( return nil } - var errDetail string - switch errData := err.(type) { - case errors.ErrorProto: - errDetail = prototext.Format(errData.Proto()) - default: - errDetail = fmt.Sprintf("%#v", err) - } - - id := errors.GetErrorId(err) + errDetail := errDetail(err) + id := errinter.GetErrorId(err) if id != "" { - return fmt.Sprintf("%s(%s): %s", err.Error(), id, errDetail) + return fmt.Sprintf("%s, error_id:%s error_detail:%s", err.Error(), id, errDetail) } - return fmt.Sprintf("%s: %v", err.Error(), errDetail) + return fmt.Sprintf("%s: %s", err.Error(), errDetail) } }) @@ -64,7 +62,7 @@ var ( Output(zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) { w.Out = os.Stderr w.TimeFormat = time.RFC3339 - })).Hook(new(hookImpl), logGlobalHook), + })).Hook(logGlobalHook), ) _ = generic.Init(func() { @@ -80,7 +78,7 @@ func GetLogger(names ...string) Logger { if len(names) == 0 || names[0] == "" { return stdLog } - return stdLog.nameWithCaller(names[0], 1) + return stdLog.nameWithCaller(names[0], 0) } // SetLogger set global log diff --git a/log/impl.log.go b/log/impl.log.go index 66c4001b..eadb07da 100644 --- a/log/impl.log.go +++ b/log/impl.log.go @@ -5,14 +5,20 @@ import ( "fmt" "strings" - "github.com/pubgo/funk/errors" - "github.com/pubgo/funk/stack" "github.com/rs/zerolog" - "google.golang.org/protobuf/encoding/prototext" + + "github.com/pubgo/funk/errors/errinter" + "github.com/pubgo/funk/log/logfields" ) var _ Logger = (*loggerImpl)(nil) +func New(log *zerolog.Logger) Logger { + return &loggerImpl{ + log: log, + } +} + type loggerImpl struct { name string log *zerolog.Logger @@ -59,18 +65,19 @@ func (l *loggerImpl) nameWithCaller(name string, caller int) Logger { if log.fields == nil { log.fields = make(Map, 1) } - log.fields[ModuleName] = stack.Caller(caller + 1).Pkg if log.name == "" { log.name = name } else { log.name = fmt.Sprintf("%s.%s", log.name, name) } + + log.callerSkip += caller return log } func (l *loggerImpl) WithName(name string) Logger { - return l.nameWithCaller(name, 1) + return l.nameWithCaller(name, 0) } func (l *loggerImpl) WithFields(m Map) Logger { @@ -94,8 +101,11 @@ func (l *loggerImpl) WithFields(m Map) Logger { func (l *loggerImpl) getCtx(ctxL ...context.Context) context.Context { ctx := context.Background() - if len(ctxL) > 0 { - ctx = ctxL[0] + for i := range ctxL { + if ctxL[i] != nil { + ctx = ctxL[i] + break + } } return ctx } @@ -143,21 +153,17 @@ func (l *loggerImpl) Err(err error, ctxL ...context.Context) *zerolog.Event { } var fn = func(e *zerolog.Event) { - if id := errors.GetErrorId(err); id != "" { - e.Str("error_id", id) + if err == nil { + return } - } - if err != nil { - if errStr, ok := err.(errors.ErrorProto); ok { - return l.newEvent(ctx, l.getLog().Error().Func(fn). - Str(zerolog.ErrorFieldName, err.Error()). - Str("error_detail", prototext.Format(errStr.Proto()))) + if id := errinter.GetErrorId(err); id != "" { + e.Str("error_id", id) } - return l.newEvent(ctx, l.getLog().Error().Func(fn).Str(zerolog.ErrorFieldName, err.Error())) + e.Str("error_detail", errDetail(err)) + e.Str(zerolog.ErrorFieldName, err.Error()) } - return l.newEvent(ctx, l.getLog().Err(err).Func(fn)) } @@ -184,11 +190,7 @@ func (l *loggerImpl) enabled(ctx context.Context, lvl zerolog.Level) bool { return false } - enabled := true - if logEnableChecker != nil { - enabled = logEnableChecker(ctx, lvl, l.name, l.fields) - } - return enabled && lvl >= l.lvl && lvl >= zerolog.GlobalLevel() + return lvl >= l.lvl && lvl >= zerolog.GlobalLevel() } func (l *loggerImpl) copy() *loggerImpl { @@ -205,7 +207,7 @@ func (l *loggerImpl) getLog() *zerolog.Logger { func (l *loggerImpl) newEvent(ctx context.Context, e *zerolog.Event) *zerolog.Event { if l.name != "" { - e = e.Str("logger", l.name) + e = e.Str(logfields.Logger, l.name) } if l.callerSkip != 0 { @@ -216,10 +218,7 @@ func (l *loggerImpl) newEvent(ctx context.Context, e *zerolog.Event) *zerolog.Ev e = e.Fields(l.fields) } - if ctx != nil { - ctx = createFieldCtx(ctx, l.fields) - e = e.Ctx(ctx) - } + e = e.Ctx(createFieldCtx(ctx, &fieldMap{name: l.name, fields: l.fields})) return mergeEvent(e, getEventFromCtx(ctx), l.content) } diff --git a/log/impl.slog.go b/log/impl.slog.go new file mode 100644 index 00000000..508d1912 --- /dev/null +++ b/log/impl.slog.go @@ -0,0 +1,73 @@ +package log + +import ( + "context" + "log/slog" + + "github.com/rs/zerolog" + slogcommon "github.com/samber/slog-common" +) + +func NewSlog(log Logger) slog.Handler { + return &slogImpl{l: log.WithCallerSkip(3)} +} + +var logLevels = map[slog.Level]zerolog.Level{ + slog.LevelDebug: zerolog.DebugLevel, + slog.LevelInfo: zerolog.InfoLevel, + slog.LevelWarn: zerolog.WarnLevel, + slog.LevelError: zerolog.ErrorLevel, +} +var _ slog.Handler = (*slogImpl)(nil) + +type slogImpl struct { + l Logger +} + +func (s slogImpl) Enabled(ctx context.Context, level slog.Level) bool { + return s.l.(*loggerImpl).enabled(ctx, logLevels[level]) +} + +func (s slogImpl) Handle(ctx context.Context, r slog.Record) error { + if r.Level < 0 { + r.Level = slog.LevelDebug + } + + logger := s.l.WithLevel(logLevels[r.Level]) + + var evt *Event + switch r.Level { + case slog.LevelDebug: + evt = logger.Debug(ctx) + case slog.LevelInfo: + evt = logger.Info(ctx) + case slog.LevelWarn: + evt = logger.Warn(ctx) + case slog.LevelError: + evt = logger.Error(ctx) + } + + if evt == nil { + return nil + } + + if !r.Time.IsZero() { + evt.Time(zerolog.TimestampFieldName, r.Time) + } + + r.Attrs(func(attr slog.Attr) bool { + evt.Any(attr.Key, attr.Value.Any()) + return true + }) + + evt.Msg(r.Message) + return nil +} + +func (s slogImpl) WithAttrs(attrs []slog.Attr) slog.Handler { + return &slogImpl{l: s.l.WithFields(slogcommon.AttrsToMap(attrs...))} +} + +func (s slogImpl) WithGroup(name string) slog.Handler { + return &slogImpl{l: s.l.WithName(name)} +} diff --git a/log/impl.std.go b/log/impl.std.go index 965de861..fcb67ab7 100644 --- a/log/impl.std.go +++ b/log/impl.std.go @@ -4,6 +4,10 @@ import "fmt" var _ StdLogger = (*stdLogImpl)(nil) +func NewStd(log Logger) StdLogger { + return &stdLogImpl{log: log.WithCallerSkip(1)} +} + type stdLogImpl struct { log Logger } diff --git a/log/log.go b/log/log.go deleted file mode 100644 index a382754e..00000000 --- a/log/log.go +++ /dev/null @@ -1,15 +0,0 @@ -package log - -import ( - "github.com/rs/zerolog" -) - -func NewStd(log Logger) StdLogger { - return &stdLogImpl{log: log.WithCallerSkip(1)} -} - -func New(log *zerolog.Logger) Logger { - return &loggerImpl{ - log: log, - } -} diff --git a/log/logfields/fields.go b/log/logfields/fields.go new file mode 100644 index 00000000..7e46499e --- /dev/null +++ b/log/logfields/fields.go @@ -0,0 +1,10 @@ +package logfields + +const ( + Module = "module" + Msg = "log_msg" + Logger = "logger" + Error = "error" + ErrorDetail = "error_detail" + ErrorStack = "error_stack" +) diff --git a/log/hooks.go b/log/loghooks/hooks.go similarity index 95% rename from log/hooks.go rename to log/loghooks/hooks.go index e9002038..e7eff0cd 100644 --- a/log/hooks.go +++ b/log/loghooks/hooks.go @@ -1,4 +1,4 @@ -package log +package loghooks import ( "sync/atomic" diff --git a/log/logutil/util.go b/log/logutil/util.go new file mode 100644 index 00000000..19bd86db --- /dev/null +++ b/log/logutil/util.go @@ -0,0 +1,27 @@ +package logutil + +import ( + "context" + + "github.com/rs/zerolog" +) + +func Record(evt *zerolog.Event, events ...func(e *zerolog.Event)) *zerolog.Event { + for _, fn := range events { + fn(evt) + } + return evt +} + +func RecordCtx(ctx context.Context, evt *zerolog.Event, events ...func(e *zerolog.Event)) *zerolog.Event { + for _, fn := range events { + fn(evt) + } + return evt.Ctx(ctx) +} + +func WithNotice() func(e *zerolog.Event) { + return func(e *zerolog.Event) { + e.Str("alert", "notice").Bool("critical", true) + } +} diff --git a/log/util.go b/log/util.go index 28da7bdf..17f83e0a 100644 --- a/log/util.go +++ b/log/util.go @@ -3,13 +3,17 @@ package log import ( "context" + "github.com/pubgo/funk/errors/errinter" "github.com/samber/lo" + "google.golang.org/protobuf/encoding/prototext" ) -func WithNotice() func(e *Event) { - return func(e *Event) { - e.Str("alert", "notice").Bool("critical", true) +func errDetail(err error) string { + if err == nil { + return "" } + + return prototext.Format(errinter.ParseErrToPb(err)) } func RecordErr(logs ...Logger) func(ctx context.Context, err error) error { diff --git a/log/z_log_test.go b/log/z_log_test.go index 25e87573..1e05d7fd 100644 --- a/log/z_log_test.go +++ b/log/z_log_test.go @@ -6,11 +6,13 @@ import ( "fmt" "testing" - "github.com/pubgo/funk/errors" - "github.com/pubgo/funk/log" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/tidwall/gjson" + + "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/log" + "github.com/pubgo/funk/log/logutil" ) func TestWithName(t *testing.T) { @@ -19,7 +21,6 @@ func TestWithName(t *testing.T) { Func(func(e *zerolog.Event) { var buf = gjson.ParseBytes(log.GetEventBuf(e)) assert.Equal(t, buf.Get("logger").String(), "log1") - assert.Equal(t, buf.Get("module").String(), "github.com/pubgo/funk/log_test") }).Msg("hello") log.GetLogger("log1"). @@ -28,14 +29,12 @@ func TestWithName(t *testing.T) { Func(func(e *zerolog.Event) { var buf = gjson.ParseBytes(log.GetEventBuf(e)) assert.Equal(t, buf.Get("logger").String(), "log1.log2") - assert.Equal(t, buf.Get("module").String(), "github.com/pubgo/funk/log_test") }).Msg("hello") log.Debug(). Func(func(e *zerolog.Event) { var buf = gjson.ParseBytes(log.GetEventBuf(e)) assert.Equal(t, buf.Get("logger").String(), "") - assert.Equal(t, buf.Get("module").String(), "") }).Msg("hello") } @@ -75,7 +74,7 @@ func TestName(t *testing.T) { WithFields(log.Map{"module": "pkg"}). Info(). Str("hello", "world world"). - Func(log.WithNotice()). + Func(logutil.WithNotice()). Msg("ok ok") } @@ -119,7 +118,7 @@ func TestChecker(t *testing.T) { l := log.GetLogger("test-checker") l.Info().Msg("hello") - log.SetEnableChecker(func(ctx context.Context, lvl log.Level, name string, fields log.Map) bool { + log.SetEnableChecker(func(ctx context.Context, lvl log.Level, name, message string, fields log.Map) bool { fmt.Println(lvl, name, fields) return true }) @@ -138,10 +137,10 @@ func TestErr(t *testing.T) { } func TestError(t *testing.T) { - err := fmt.Errorf("test error") + err := fmt.Errorf("test raw error") log.Error().Err(err).Msg(err.Error()) - err1 := errors.Errorf("test format") - log.Error().Err(err1).Msg(err1.Error()) + err1 := errors.Errorf("test errors format") + log.Error().Err(err1).Msg("raw error: " + err1.Error()) log.Err(err1).Msg(err1.Error()) } diff --git a/netutil/util.go b/netutil/util.go index b980b47e..0d68d89b 100644 --- a/netutil/util.go +++ b/netutil/util.go @@ -12,25 +12,31 @@ import ( "github.com/pubgo/funk/assert" ) -var localIp = assert.Exit1(regexp.Compile(`\d+\.\d+\.\d+\.\d+`)) +var localIpReg = assert.Exit1(regexp.Compile(`\d+\.\d+\.\d+\.\d+`)) func GetLocalIP() string { - localIP := "localhost" + localIP := "127.0.0.1" - // skip the error since we don't want to break RPC calls because of it - addresses, err := net.InterfaceAddrs() + interfaces, err := net.Interfaces() if err != nil { return localIP } - for _, addr := range addresses { - items := strings.Split(addr.String(), "/") - if len(items) < 2 || items[0] == "127.0.0.1" { + for _, netInterface := range interfaces { + if netInterface.Name != "en0" { continue } - if localIp.MatchString(items[0]) { - localIP = items[0] + addresses, _ := netInterface.Addrs() + for _, addr := range addresses { + items := strings.Split(addr.String(), "/") + if len(items) < 2 || items[0] == "127.0.0.1" { + continue + } + + if localIpReg.MatchString(items[0]) { + localIP = items[0] + } } } diff --git a/pretty/pretty.go b/pretty/pretty.go index e73df2f7..18c998f9 100644 --- a/pretty/pretty.go +++ b/pretty/pretty.go @@ -2,6 +2,8 @@ package pretty import ( "io" + "strings" + "sync" "github.com/k0kubun/pp/v3" ) @@ -41,3 +43,16 @@ func SetWriter(o io.Writer) { func SetDefaultMaxDepth(v int) { pp.SetDefaultMaxDepth(v) } + +var Simple = sync.OnceValue(func() *pp.PrettyPrinter { + printer := pp.New() + printer.SetColoringEnabled(false) + printer.SetExportedOnly(false) + printer.SetOmitEmpty(true) + printer.SetMaxDepth(3) + return printer +}) + +func SimplePrint(v interface{}) string { + return strings.ReplaceAll(Simple().Sprint(v), "\n", "") +} diff --git a/pretty/pretty_test.go b/pretty/pretty_test.go index 88a1ed2d..6921749f 100644 --- a/pretty/pretty_test.go +++ b/pretty/pretty_test.go @@ -5,3 +5,7 @@ import "testing" func TestName(t *testing.T) { Println(t) } + +func TestSimplePrint(t *testing.T) { + SimplePrint(t) +} diff --git a/proto/errorpb/errors.pb.go b/proto/errorpb/errors.pb.go index c6061b74..ac6b5529 100644 --- a/proto/errorpb/errors.pb.go +++ b/proto/errorpb/errors.pb.go @@ -21,6 +21,59 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type Tag struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *Tag) Reset() { + *x = Tag{} + mi := &file_errorpb_errors_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Tag) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Tag) ProtoMessage() {} + +func (x *Tag) ProtoReflect() protoreflect.Message { + mi := &file_errorpb_errors_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Tag.ProtoReflect.Descriptor instead. +func (*Tag) Descriptor() ([]byte, []int) { + return file_errorpb_errors_proto_rawDescGZIP(), []int{0} +} + +func (x *Tag) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *Tag) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + type ErrMsg struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -35,7 +88,7 @@ type ErrMsg struct { func (x *ErrMsg) Reset() { *x = ErrMsg{} - mi := &file_errorpb_errors_proto_msgTypes[0] + mi := &file_errorpb_errors_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -47,7 +100,7 @@ func (x *ErrMsg) String() string { func (*ErrMsg) ProtoMessage() {} func (x *ErrMsg) ProtoReflect() protoreflect.Message { - mi := &file_errorpb_errors_proto_msgTypes[0] + mi := &file_errorpb_errors_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -60,7 +113,7 @@ func (x *ErrMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use ErrMsg.ProtoReflect.Descriptor instead. func (*ErrMsg) Descriptor() ([]byte, []int) { - return file_errorpb_errors_proto_rawDescGZIP(), []int{0} + return file_errorpb_errors_proto_rawDescGZIP(), []int{1} } func (x *ErrMsg) GetMsg() string { @@ -119,7 +172,7 @@ type ErrCode struct { func (x *ErrCode) Reset() { *x = ErrCode{} - mi := &file_errorpb_errors_proto_msgTypes[1] + mi := &file_errorpb_errors_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -131,7 +184,7 @@ func (x *ErrCode) String() string { func (*ErrCode) ProtoMessage() {} func (x *ErrCode) ProtoReflect() protoreflect.Message { - mi := &file_errorpb_errors_proto_msgTypes[1] + mi := &file_errorpb_errors_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -144,7 +197,7 @@ func (x *ErrCode) ProtoReflect() protoreflect.Message { // Deprecated: Use ErrCode.ProtoReflect.Descriptor instead. func (*ErrCode) Descriptor() ([]byte, []int) { - return file_errorpb_errors_proto_rawDescGZIP(), []int{1} + return file_errorpb_errors_proto_rawDescGZIP(), []int{2} } func (x *ErrCode) GetStatusCode() Code { @@ -202,7 +255,7 @@ type ErrTrace struct { func (x *ErrTrace) Reset() { *x = ErrTrace{} - mi := &file_errorpb_errors_proto_msgTypes[2] + mi := &file_errorpb_errors_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -214,7 +267,7 @@ func (x *ErrTrace) String() string { func (*ErrTrace) ProtoMessage() {} func (x *ErrTrace) ProtoReflect() protoreflect.Message { - mi := &file_errorpb_errors_proto_msgTypes[2] + mi := &file_errorpb_errors_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -227,7 +280,7 @@ func (x *ErrTrace) ProtoReflect() protoreflect.Message { // Deprecated: Use ErrTrace.ProtoReflect.Descriptor instead. func (*ErrTrace) Descriptor() ([]byte, []int) { - return file_errorpb_errors_proto_rawDescGZIP(), []int{2} + return file_errorpb_errors_proto_rawDescGZIP(), []int{3} } func (x *ErrTrace) GetId() string { @@ -270,7 +323,7 @@ type Error struct { func (x *Error) Reset() { *x = Error{} - mi := &file_errorpb_errors_proto_msgTypes[3] + mi := &file_errorpb_errors_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -282,7 +335,7 @@ func (x *Error) String() string { func (*Error) ProtoMessage() {} func (x *Error) ProtoReflect() protoreflect.Message { - mi := &file_errorpb_errors_proto_msgTypes[3] + mi := &file_errorpb_errors_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -295,7 +348,7 @@ func (x *Error) ProtoReflect() protoreflect.Message { // Deprecated: Use Error.ProtoReflect.Descriptor instead. func (*Error) Descriptor() ([]byte, []int) { - return file_errorpb_errors_proto_rawDescGZIP(), []int{3} + return file_errorpb_errors_proto_rawDescGZIP(), []int{4} } func (x *Error) GetCode() *ErrCode { @@ -332,7 +385,7 @@ type ErrWrap struct { func (x *ErrWrap) Reset() { *x = ErrWrap{} - mi := &file_errorpb_errors_proto_msgTypes[4] + mi := &file_errorpb_errors_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -344,7 +397,7 @@ func (x *ErrWrap) String() string { func (*ErrWrap) ProtoMessage() {} func (x *ErrWrap) ProtoReflect() protoreflect.Message { - mi := &file_errorpb_errors_proto_msgTypes[4] + mi := &file_errorpb_errors_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -357,7 +410,7 @@ func (x *ErrWrap) ProtoReflect() protoreflect.Message { // Deprecated: Use ErrWrap.ProtoReflect.Descriptor instead. func (*ErrWrap) Descriptor() ([]byte, []int) { - return file_errorpb_errors_proto_rawDescGZIP(), []int{4} + return file_errorpb_errors_proto_rawDescGZIP(), []int{5} } func (x *ErrWrap) GetTags() map[string]string { @@ -395,64 +448,66 @@ var file_errorpb_errors_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x1a, 0x12, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcb, 0x01, - 0x0a, 0x06, 0x45, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, - 0x45, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01, 0x01, 0x1a, 0x37, 0x0a, 0x09, 0x54, - 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x69, 0x64, 0x22, 0xc6, 0x01, 0x0a, 0x07, - 0x45, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2d, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, - 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01, 0x01, 0x42, 0x05, 0x0a, - 0x03, 0x5f, 0x69, 0x64, 0x22, 0x6c, 0x0a, 0x08, 0x45, 0x72, 0x72, 0x54, 0x72, 0x61, 0x63, 0x65, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, - 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x22, 0x76, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x04, 0x63, - 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x73, 0x2e, 0x45, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, - 0x12, 0x26, 0x0a, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x10, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x45, 0x72, 0x72, 0x54, 0x72, 0x61, 0x63, - 0x65, 0x52, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x45, - 0x72, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0xcd, 0x01, 0x0a, 0x07, 0x45, - 0x72, 0x72, 0x57, 0x72, 0x61, 0x70, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x45, 0x72, - 0x72, 0x57, 0x72, 0x61, 0x70, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x16, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x63, 0x6b, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x75, 0x62, 0x67, 0x6f, 0x2f, 0x66, - 0x75, 0x6e, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x70, - 0x62, 0x3b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2d, 0x0a, + 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xcb, 0x01, 0x0a, + 0x06, 0x45, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x45, + 0x72, 0x72, 0x4d, 0x73, 0x67, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01, 0x01, 0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, + 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x69, 0x64, 0x22, 0xc6, 0x01, 0x0a, 0x07, 0x45, + 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2d, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, + 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01, 0x01, 0x42, 0x05, 0x0a, 0x03, + 0x5f, 0x69, 0x64, 0x22, 0x6c, 0x0a, 0x08, 0x45, 0x72, 0x72, 0x54, 0x72, 0x61, 0x63, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0x76, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x04, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x73, 0x2e, 0x45, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, + 0x26, 0x0a, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x45, 0x72, 0x72, 0x54, 0x72, 0x61, 0x63, 0x65, + 0x52, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x45, 0x72, + 0x72, 0x4d, 0x73, 0x67, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0xcd, 0x01, 0x0a, 0x07, 0x45, 0x72, + 0x72, 0x57, 0x72, 0x61, 0x70, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x45, 0x72, 0x72, + 0x57, 0x72, 0x61, 0x70, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, + 0x74, 0x61, 0x67, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x63, 0x6b, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x75, 0x62, 0x67, 0x6f, 0x2f, 0x66, 0x75, + 0x6e, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x70, 0x62, + 0x3b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -467,27 +522,28 @@ func file_errorpb_errors_proto_rawDescGZIP() []byte { return file_errorpb_errors_proto_rawDescData } -var file_errorpb_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_errorpb_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_errorpb_errors_proto_goTypes = []any{ - (*ErrMsg)(nil), // 0: errors.ErrMsg - (*ErrCode)(nil), // 1: errors.ErrCode - (*ErrTrace)(nil), // 2: errors.ErrTrace - (*Error)(nil), // 3: errors.Error - (*ErrWrap)(nil), // 4: errors.ErrWrap - nil, // 5: errors.ErrMsg.TagsEntry - nil, // 6: errors.ErrWrap.TagsEntry - (Code)(0), // 7: errors.Code - (*anypb.Any)(nil), // 8: google.protobuf.Any + (*Tag)(nil), // 0: errors.Tag + (*ErrMsg)(nil), // 1: errors.ErrMsg + (*ErrCode)(nil), // 2: errors.ErrCode + (*ErrTrace)(nil), // 3: errors.ErrTrace + (*Error)(nil), // 4: errors.Error + (*ErrWrap)(nil), // 5: errors.ErrWrap + nil, // 6: errors.ErrMsg.TagsEntry + nil, // 7: errors.ErrWrap.TagsEntry + (Code)(0), // 8: errors.Code + (*anypb.Any)(nil), // 9: google.protobuf.Any } var file_errorpb_errors_proto_depIdxs = []int32{ - 5, // 0: errors.ErrMsg.tags:type_name -> errors.ErrMsg.TagsEntry - 7, // 1: errors.ErrCode.status_code:type_name -> errors.Code - 8, // 2: errors.ErrCode.details:type_name -> google.protobuf.Any - 1, // 3: errors.Error.code:type_name -> errors.ErrCode - 2, // 4: errors.Error.trace:type_name -> errors.ErrTrace - 0, // 5: errors.Error.msg:type_name -> errors.ErrMsg - 6, // 6: errors.ErrWrap.tags:type_name -> errors.ErrWrap.TagsEntry - 8, // 7: errors.ErrWrap.error:type_name -> google.protobuf.Any + 6, // 0: errors.ErrMsg.tags:type_name -> errors.ErrMsg.TagsEntry + 8, // 1: errors.ErrCode.status_code:type_name -> errors.Code + 9, // 2: errors.ErrCode.details:type_name -> google.protobuf.Any + 2, // 3: errors.Error.code:type_name -> errors.ErrCode + 3, // 4: errors.Error.trace:type_name -> errors.ErrTrace + 1, // 5: errors.Error.msg:type_name -> errors.ErrMsg + 7, // 6: errors.ErrWrap.tags:type_name -> errors.ErrWrap.TagsEntry + 9, // 7: errors.ErrWrap.error:type_name -> google.protobuf.Any 8, // [8:8] is the sub-list for method output_type 8, // [8:8] is the sub-list for method input_type 8, // [8:8] is the sub-list for extension type_name @@ -501,15 +557,15 @@ func file_errorpb_errors_proto_init() { return } file_errorpb_code_proto_init() - file_errorpb_errors_proto_msgTypes[0].OneofWrappers = []any{} file_errorpb_errors_proto_msgTypes[1].OneofWrappers = []any{} + file_errorpb_errors_proto_msgTypes[2].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_errorpb_errors_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 8, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/errorpb/errors.proto b/proto/errorpb/errors.proto index 9bc90c08..0ae55a63 100644 --- a/proto/errorpb/errors.proto +++ b/proto/errorpb/errors.proto @@ -7,6 +7,11 @@ import "google/protobuf/any.proto"; option go_package = "github.com/pubgo/funk/proto/errorpb;errorpb"; +message Tag { + string key = 1; + string value = 2; +} + message ErrMsg { string msg = 1; string detail = 2; diff --git a/protoutils/util.go b/protoutils/util.go index e9ccaac9..cc888daa 100644 --- a/protoutils/util.go +++ b/protoutils/util.go @@ -9,7 +9,6 @@ import ( "strings" "unicode" - pongo2 "github.com/flosch/pongo2/v6" "github.com/pubgo/funk/assert" "github.com/pubgo/funk/errors" options "google.golang.org/genproto/googleapis/api/annotations" @@ -281,16 +280,6 @@ func trim(s string) string { return strings.Trim(strings.TrimSpace(s), ".-_/") } -type Context = pongo2.Context - -func Template(tpl string, m pongo2.Context) string { - temp := assert.Must1(pongo2.FromString(tpl)) - - w := bytes.NewBuffer(nil) - assert.Must(temp.ExecuteWriter(m, w), tpl) - return w.String() -} - func goZeroValue(f *descriptorpb.FieldDescriptorProto) string { const nilString = "nil" if *f.Label == descriptorpb.FieldDescriptorProto_LABEL_REPEATED { diff --git a/recovery/recovery.go b/recovery/recovery.go index ab914d4e..a2b982e2 100644 --- a/recovery/recovery.go +++ b/recovery/recovery.go @@ -2,14 +2,15 @@ package recovery import ( "os" + "runtime/debug" "testing" "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/errors/errinter" ) func Err(gErr *error, callbacks ...func(err error) error) { - err := errors.Parse(recover()) + err := errinter.ParseError(recover()) if err == nil { return } @@ -21,11 +22,12 @@ func Err(gErr *error, callbacks ...func(err error) error) { } } - *gErr = errors.WrapStack(err) + debug.PrintStack() + *gErr = err } func Raise(callbacks ...func(err error) error) { - err := errors.Parse(recover()) + err := errinter.ParseError(recover()) if err == nil { return } @@ -37,22 +39,24 @@ func Raise(callbacks ...func(err error) error) { } } - panic(errors.WrapStack(err)) + debug.PrintStack() + panic(err) } func Recovery(fn func(err error)) { assert.If(fn == nil, "[fn] should not be nil") - err := errors.Parse(recover()) + err := errinter.ParseError(recover()) if err == nil { return } - fn(errors.WrapStack(err)) + debug.PrintStack() + fn(err) } func Exit(handlers ...func(err error) error) { - err := errors.Parse(recover()) + err := errinter.ParseError(recover()) if err == nil { return } @@ -64,25 +68,27 @@ func Exit(handlers ...func(err error) error) { } } - errors.Debug(errors.WrapStack(err)) + debug.PrintStack() + errinter.Debug(err) os.Exit(1) } func DebugPrint() { - err := errors.Parse(recover()) + err := errinter.ParseError(recover()) if err == nil { return } - errors.Debug(errors.WrapStack(err)) + debug.PrintStack() + errinter.Debug(err) } func Testing(t *testing.T) { - err := errors.Parse(recover()) + err := errinter.ParseError(recover()) if err == nil { return } - errors.Debug(errors.WrapStack(err)) + errinter.Debug(err) t.Fatal(err) } diff --git a/recovery/recovery_test.go b/recovery/recovery_test.go index 0b380831..cc3d080a 100644 --- a/recovery/recovery_test.go +++ b/recovery/recovery_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/generic" "github.com/pubgo/funk/log" "github.com/pubgo/funk/recovery" "github.com/pubgo/funk/result" @@ -31,11 +30,7 @@ func TestErr(t *testing.T) { panic("ok") } - - err := handler() - if generic.IsNil(err) { - t.Log(err) - } + t.Log("error:", handler()) } func TestResult(t *testing.T) { diff --git a/running/runtime.go b/running/runtime.go index 0a1387f1..dbf3952a 100644 --- a/running/runtime.go +++ b/running/runtime.go @@ -4,6 +4,7 @@ import ( "os" "strings" + "github.com/projectdiscovery/machineid" "github.com/rs/xid" "github.com/pubgo/funk/assert" @@ -26,6 +27,8 @@ var ( // InstanceID service id InstanceID = xid.New().String() + DeviceID = InstanceID + Version = version.Version() CommitID = version.CommitID() @@ -53,9 +56,16 @@ var ( return strings.TrimSpace(string(assert.Exit1(os.ReadFile(file)))) }, ) + + Domain string ) func init() { - env.GetBoolVal(&IsDebug, "enable_debug", "debug") - env.GetWith(&Env, "env", "run_mode") + env.GetBoolVal(&IsDebug, "enable_debug", "debug", "dev_mode") + env.GetVal(&Env, "env", "run_mode", "run_env") + + id, err := machineid.ID() + if err == nil { + DeviceID = id + } } diff --git a/running/util.go b/running/util.go index 72974a01..f7aaf443 100644 --- a/running/util.go +++ b/running/util.go @@ -11,6 +11,10 @@ import ( "github.com/pubgo/funk/version" ) +func SetVersion(v string) { Version = v } +func SetProject(p string) { Project = p } +func SetDomain(d string) { Domain = d } + func GetSysInfo() map[string]string { return map[string]string{ "main_path": version.MainPath(), @@ -18,12 +22,15 @@ func GetSysInfo() map[string]string { "http_post": fmt.Sprintf("%v", HttpPort), "debug": fmt.Sprintf("%v", IsDebug), "cur_dir": Pwd, + "local_ip": LocalIP, "namespace": Namespace, "instance_id": InstanceID, + "device_id": DeviceID, "project": Project, "hostname": Hostname, "build_time": version.BuildTime(), "version": Version, + "domain": Domain, "commit_id": CommitID, "go_root": rt.GOROOT(), "go_arch": rt.GOARCH, @@ -36,7 +43,13 @@ func GetSysInfo() map[string]string { func CheckVersion() { defer recovery.Exit() - assert.Must1(semver.NewVersion(version.Version())) + assert.MustFn(func() error { + _, err := semver.NewVersion(version.Version()) + if err != nil { + return fmt.Errorf("version(%s) error: %w", version.Version(), err) + } + return nil + }) assert.If(version.Project() == "", "project is null") assert.If(version.Version() == "", "version is null") assert.If(version.CommitID() == "", "commitID is null") diff --git a/stack/trace_test.go b/stack/trace_test.go index 9ec07b7a..b0448295 100644 --- a/stack/trace_test.go +++ b/stack/trace_test.go @@ -3,11 +3,11 @@ package stack_test import ( "testing" - "github.com/k0kubun/pp/v3" + "github.com/pubgo/funk/pretty" "github.com/pubgo/funk/stack" ) func TestTrace(t *testing.T) { traces := stack.Trace() - t.Log(pp.Sprint(traces)) + t.Log(pretty.Sprint(traces)) } diff --git a/syncutil/util.go b/syncutil/util.go new file mode 100644 index 00000000..5f92a6ee --- /dev/null +++ b/syncutil/util.go @@ -0,0 +1,19 @@ +package syncutil + +import "context" + +func CallWithContext(ctx context.Context, fn func() error) error { + var err error + done := make(chan struct{}) + go func() { + defer close(done) + err = fn() + }() + + select { + case <-done: + return err + case <-ctx.Done(): + return ctx.Err() + } +} diff --git a/utils/utils.go b/utils/utils.go index e92b5614..721ac433 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -8,6 +8,6 @@ import ( func SafeClose(closer io.Closer) { if err := closer.Close(); err != nil { - log.Warn().Err(err).Msg("Close operation failed") + log.Err(err).Msg("failed to safe close operation") } } diff --git a/v2/result/api.go b/v2/result/api.go index ad238088..6995c508 100644 --- a/v2/result/api.go +++ b/v2/result/api.go @@ -20,37 +20,40 @@ func All[T any](results ...Result[T]) Result[[]T] { func Recovery(setter *error, callbacks ...func(err error) error) { if setter == nil { - errMust(errors.Errorf("setter is nil")) + errNilOrPanic(errors.Errorf("setter is nil")) return } - *setter = errRecovery( - func() bool { return *setter != nil }, + setError(ErrProxyOf(setter), errRecovery( func() error { return *setter }, callbacks..., - ) + )) } func RecoveryErr(setter ErrSetter, callbacks ...func(err error) error) { if setter == nil { - errMust(errors.Errorf("setter is nil")) + errNilOrPanic(errors.Errorf("setter is nil")) return } - setter.setError(errRecovery( - func() bool { return setter.IsErr() }, + setError(setter, errRecovery( func() error { return setter.GetErr() }, callbacks..., )) } +func Errorf(msg string, args ...any) Error { + return newError(errors.WrapCaller(fmt.Errorf(msg, args...), 1)) +} + +// Deprecated: use Errorf func ErrorOf(msg string, args ...any) Error { return newError(errors.WrapCaller(fmt.Errorf(msg, args...), 1)) } func ErrProxyOf(err *error) ErrProxy { if err == nil { - errMust(errors.Errorf("err param is nil")) + errNilOrPanic(errors.Errorf("err param is nil")) return ErrProxy{} } return ErrProxy{err: err} diff --git a/v2/result/error.go b/v2/result/error.go index ae46f294..6e8cf335 100644 --- a/v2/result/error.go +++ b/v2/result/error.go @@ -4,9 +4,10 @@ import ( "context" "fmt" + "github.com/rs/zerolog" + "github.com/pubgo/funk/errors" "github.com/pubgo/funk/errors/errutil" - "github.com/pubgo/funk/log" ) var _ Catchable = new(Error) @@ -33,13 +34,13 @@ func (e Error) Map(fn func(error) error) Error { return Error{err: err} } -func (e Error) LogErr(contexts ...context.Context) Error { - if e.IsErr() { - log.Err(e.err, contexts...). - CallerSkipFrame(1). - Msg(e.err.Error()) - } +func (e Error) LogCtx(ctx context.Context, events ...func(e *zerolog.Event)) Error { + logErr(ctx, e.err, events...) + return e +} +func (e Error) Log(events ...func(e *zerolog.Event)) Error { + logErr(nil, e.err, events...) return e } @@ -47,9 +48,16 @@ func (e Error) WrapErr(err *errors.Err, tags ...errors.Tag) Error { return Error{err: errors.WrapTag(errors.WrapCaller(err, 1), tags...)} } +func (e Error) WithFn(fn func() error) Error { + return Error{err: errors.WrapCaller(fn(), 1)} +} + func (e Error) WithErr(err error) Error { return Error{err: errors.WrapCaller(err, 1)} } +func (e Error) WithErrorf(format string, args ...any) Error { + return Error{err: errors.WrapCaller(fmt.Errorf(format, args...), 1)} +} func (e Error) Inspect(fn func(error)) Error { if e.IsErr() { @@ -60,7 +68,12 @@ func (e Error) Inspect(fn func(error)) Error { return e } +func (e Error) InspectErr(fn func(error)) Error { return e.Inspect(fn) } + func (e Error) Unwrap() error { return e.err } +func (e Error) UnwrapErr(setter ErrSetter, contexts ...context.Context) bool { + return catchErr(e, setter, nil, contexts...) +} func (e Error) Catch(setter *error, ctx ...context.Context) bool { return catchErr(e, nil, setter, ctx...) @@ -87,7 +100,7 @@ func (e Error) Must() { return } - errMust(errors.WrapCaller(e.getErr(), 1)) + errNilOrPanic(errors.WrapCaller(e.getErr(), 1)) } func (e Error) Expect(format string, args ...any) { @@ -97,7 +110,7 @@ func (e Error) Expect(format string, args ...any) { err := errors.WrapCaller(e.getErr(), 1) err = errors.Wrapf(err, format, args...) - errMust(err) + errNilOrPanic(err) } func (e Error) String() string { @@ -118,9 +131,5 @@ func (e Error) MarshalJSON() ([]byte, error) { func (e Error) getErr() error { return e.err } -func (e *Error) setError(err error) { - if err == nil { - return - } - e.err = err +func (e Error) setErrorInner() { } diff --git a/v2/result/error_test.go b/v2/result/error_test.go index b75cb9a9..ebbc69ff 100644 --- a/v2/result/error_test.go +++ b/v2/result/error_test.go @@ -4,8 +4,13 @@ import ( "testing" "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/log/logfields" + "github.com/rs/zerolog" ) func TestErrorLog(t *testing.T) { - ErrOf(errors.New("test")).LogErr() + ErrOf(errors.New("test")). + Log(func(e *zerolog.Event) { + e.Str(logfields.Msg, "ok") + }) } diff --git a/v2/result/interface.go b/v2/result/interface.go index 27321675..45873291 100644 --- a/v2/result/interface.go +++ b/v2/result/interface.go @@ -17,7 +17,7 @@ type Checkable interface { type ErrSetter interface { Checkable - setError(err error) + setErrorInner() } type UnWrapper[T any] interface { diff --git a/v2/result/proxy.go b/v2/result/proxy.go index bd5ace75..970f6a2e 100644 --- a/v2/result/proxy.go +++ b/v2/result/proxy.go @@ -32,10 +32,5 @@ func (e ErrProxy) String() string { return fmt.Sprintf("Error(%v)", lo.FromPtr(e.err)) } -func (e *ErrProxy) setError(err error) { - if err == nil { - return - } - - *e.err = err +func (e ErrProxy) setErrorInner() { } diff --git a/v2/result/proxy_test.go b/v2/result/proxy_test.go index 0a3c8c63..f5da4843 100644 --- a/v2/result/proxy_test.go +++ b/v2/result/proxy_test.go @@ -9,7 +9,7 @@ import ( func TestProxy(t *testing.T) { var gErr error var err = ErrProxyOf(&gErr) - ErrorOf("test proxy error").CatchErr(&err) + Errorf("test proxy error").Log().CatchErr(&err) assert.NotNil(t, gErr) assert.NotNil(t, err.GetErr()) assert.Equal(t, gErr, err.GetErr()) diff --git a/v2/result/result.go b/v2/result/result.go index 9b1f6352..35f4766b 100644 --- a/v2/result/result.go +++ b/v2/result/result.go @@ -5,10 +5,11 @@ import ( "encoding/json" "fmt" + "github.com/rs/zerolog" + "github.com/samber/lo" + "github.com/pubgo/funk" "github.com/pubgo/funk/errors" - "github.com/pubgo/funk/log" - "github.com/samber/lo" ) var _ Catchable = new(Result[any]) @@ -22,14 +23,23 @@ type Result[T any] struct { err error } -func (r Result[T]) GetValue() T { +func (r Result[T]) GetValue() (t T) { if r.IsErr() { - errMust(errors.WrapCaller(r.getErr(), 1)) + return } return r.getValue() } +func (r Result[T]) WithFn(fn func() (T, error)) Result[T] { + if r.IsErr() { + err := errors.WrapCaller(r.getErr(), 1) + return Result[T]{err: err} + } + + return WrapFn(fn) +} + func (r Result[T]) WithValue(v T) Result[T] { if r.IsErr() { err := errors.WrapCaller(r.getErr(), 1) @@ -55,7 +65,7 @@ func (r Result[T]) ValueTo(v *T) Error { func (r Result[T]) Expect(format string, args ...any) T { if r.IsErr() { err := errors.WrapCaller(r.getErr(), 1) - errMust(errors.Wrapf(err, format, args...)) + errNilOrPanic(errors.Wrapf(err, format, args...)) } return r.getValue() @@ -63,7 +73,7 @@ func (r Result[T]) Expect(format string, args ...any) T { func (r Result[T]) Must() T { if r.IsErr() { - errMust(errors.WrapCaller(r.getErr(), 1)) + errNilOrPanic(errors.WrapCaller(r.getErr(), 1)) } return r.getValue() @@ -95,13 +105,13 @@ func (r Result[T]) Inspect(fn func(T)) Result[T] { return r } -func (r Result[T]) LogErr(contexts ...context.Context) Result[T] { - if r.IsErr() { - log.Err(r.err, contexts...). - CallerSkipFrame(1). - Msg(r.err.Error()) - } +func (r Result[T]) LogCtx(ctx context.Context, events ...func(e *zerolog.Event)) Result[T] { + logErr(ctx, r.err, events...) + return r +} +func (r Result[T]) Log(events ...func(e *zerolog.Event)) Result[T] { + logErr(nil, r.err, events...) return r } @@ -160,16 +170,12 @@ func (r Result[T]) String() string { return fmt.Sprintf("Error(%v)", r.getErr()) } -func (r Result[T]) WithErrorf(str string, args ...any) Result[T] { - err := fmt.Errorf(str, args...) +func (r Result[T]) WithErrorf(format string, args ...any) Result[T] { + err := fmt.Errorf(format, args...) err = errors.WrapCaller(err, 1) return Result[T]{err: err} } -func (r Result[T]) WrapErr(err *errors.Err, tags ...errors.Tag) Result[T] { - return Result[T]{err: errors.WrapTag(errors.WrapCaller(err, 1), tags...)} -} - func (r Result[T]) WithErr(err error) Result[T] { if err == nil { return r @@ -179,6 +185,10 @@ func (r Result[T]) WithErr(err error) Result[T] { return Result[T]{err: err} } +func (r Result[T]) WrapErr(err *errors.Err, tags ...errors.Tag) Result[T] { + return Result[T]{err: errors.WrapTag(errors.WrapCaller(err, 1), tags...)} +} + func (r Result[T]) Unwrap(setter *error, contexts ...context.Context) T { ret, err := unwrapErr(r, setter, nil, contexts...) if err != nil { @@ -190,7 +200,7 @@ func (r Result[T]) Unwrap(setter *error, contexts ...context.Context) T { func (r Result[T]) UnwrapErr(setter ErrSetter, contexts ...context.Context) T { ret, err := unwrapErr(r, nil, setter, contexts...) if err != nil { - setter.setError(errors.WrapCaller(err, 1)) + setError(setter, errors.WrapCaller(err, 1)) } return ret } @@ -207,9 +217,5 @@ func (r Result[T]) getValue() T { return lo.FromPtr(r.v) } func (r Result[T]) getErr() error { return r.err } -func (r *Result[T]) setError(err error) { - if err == nil { - return - } - r.err = err +func (r Result[T]) setErrorInner() { } diff --git a/v2/result/result_test.go b/v2/result/result_test.go index 2beb47fd..0f74552c 100644 --- a/v2/result/result_test.go +++ b/v2/result/result_test.go @@ -67,8 +67,8 @@ func fn1() (r result.Result[string]) { func fn2() (r result.Result[string]) { fn3(). - Map(func(err error) error { - return errors.Wrap(err, "test error") + InspectErr(func(err error) { + log.Err(err).Msg("test error") }). CatchErr(&r) if r.IsErr() { @@ -79,9 +79,10 @@ func fn2() (r result.Result[string]) { } func fn3() result.Error { - return result.ErrOf(fmt.Errorf("error test, this is error")). - Inspect(func(err error) { + return result. + ErrOf(fmt.Errorf("error test, this is error")). + InspectErr(func(err error) { log.Err(err).Msg("ddd") }). - LogErr() + Log() } diff --git a/v2/result/resultchecker/checker_test.go b/v2/result/resultchecker/checker_test.go index 4a99a510..e4c043e4 100644 --- a/v2/result/resultchecker/checker_test.go +++ b/v2/result/resultchecker/checker_test.go @@ -19,7 +19,7 @@ func TestErrCheck(t *testing.T) { assert.Equal(t, RegisterErrCheck(errCheck1), false) assert.Equal(t, len(GetErrCheckStacks()), 1) - assert.Equal(t, GetErrCheckStacks()[0].Short(), "aherrcheck/errcheck_test.go:10 errCheck1") + assert.Equal(t, GetErrCheckStacks()[0].Short(), "resultchecker/checker_test.go:10 errCheck1") RemoveErrCheck(errCheck1) assert.Equal(t, len(GetErrCheckStacks()), 0) diff --git a/v2/result/util.go b/v2/result/util.go index 8a26bbdc..d76129bd 100644 --- a/v2/result/util.go +++ b/v2/result/util.go @@ -3,14 +3,21 @@ package result import ( "context" "fmt" + + "log/slog" + "reflect" "runtime/debug" + "strings" + + "github.com/rs/zerolog" + "github.com/samber/lo" + "google.golang.org/protobuf/encoding/prototext" "github.com/pubgo/funk/errors" "github.com/pubgo/funk/generic" "github.com/pubgo/funk/log" "github.com/pubgo/funk/stack" "github.com/pubgo/funk/v2/result/resultchecker" - "github.com/samber/lo" ) var errFnIsNil = errors.New("[fn] is nil") @@ -24,7 +31,6 @@ func try(fn func() error) (gErr error) { defer func() { if err := errors.Parse(recover()); !generic.IsNil(err) { gErr = errors.WrapStack(err) - debug.PrintStack() errors.Debug(gErr) } @@ -43,7 +49,6 @@ func try1[T any](fn func() (T, error)) (t T, gErr error) { defer func() { if err := errors.Parse(recover()); !generic.IsNil(err) { gErr = errors.WrapStack(err) - debug.PrintStack() errors.Debug(gErr) } @@ -56,7 +61,7 @@ func try1[T any](fn func() (T, error)) (t T, gErr error) { return } -func errMust(err error, args ...any) { +func errNilOrPanic(err error, args ...any) { if err == nil { return } @@ -72,7 +77,7 @@ func errMust(err error, args ...any) { func catchErr(r Error, setter ErrSetter, rawSetter *error, contexts ...context.Context) bool { if setter == nil && rawSetter == nil { - errMust(errors.Errorf("error setter is nil")) + errNilOrPanic(errors.Errorf("error setter is nil")) } if r.IsOK() { @@ -105,20 +110,14 @@ func catchErr(r Error, setter ErrSetter, rawSetter *error, contexts ...context.C var setErr = func(err error) { if setter != nil { - setter.setError(err) + setError(setter, err) } if rawSetter != nil { - *rawSetter = err + setError(ErrProxyOf(rawSetter), err) } } - // err No checking, repeat setting - if isErr() { - err := getErr() - log.Err(err).Msgf("error setter is has value, err=%s", err.Error()) - } - var ctx = context.Background() for i := range contexts { if contexts[i] == nil { @@ -128,7 +127,13 @@ func catchErr(r Error, setter ErrSetter, rawSetter *error, contexts ...context.C break } - checkers := append(resultchecker.GetErrChecks(), resultchecker.GetCheckersFromCtx(ctx)...) + // err No checking, repeat setting + if isErr() { + err := getErr() + log.Err(err, ctx).Msgf("error setter has already set the error, err=%s", err.Error()) + } + + var checkers = append(resultchecker.GetErrChecks(), resultchecker.GetCheckersFromCtx(ctx)...) var err = r.getErr() for _, fn := range checkers { err = fn(ctx, err) @@ -142,14 +147,14 @@ func catchErr(r Error, setter ErrSetter, rawSetter *error, contexts ...context.C return true } -func errRecovery(isErr func() bool, getErr func() error, callbacks ...func(err error) error) error { +func errRecovery(getErr func() error, callbacks ...func(err error) error) error { err := errors.Parse(recover()) - if err == nil && !isErr() { - return nil + if err == nil { + err = getErr() } if err == nil { - err = getErr() + return nil } for _, fn := range callbacks { @@ -158,13 +163,14 @@ func errRecovery(isErr func() bool, getErr func() error, callbacks ...func(err e return nil } } + + debug.PrintStack() return err } func unwrapErr[T any](r Result[T], setter1 *error, setter2 ErrSetter, contexts ...context.Context) (T, error) { if setter1 == nil && setter2 == nil { - debug.PrintStack() - panic("Unwrap: error setter is nil") + errNilOrPanic(fmt.Errorf("error setter is nil")) } var ret = r.getValue() @@ -177,20 +183,20 @@ func unwrapErr[T any](r Result[T], setter1 *error, setter2 ErrSetter, contexts . ctx = contexts[0] } - getSetterErr := func() error { + getErr := func() error { err := lo.FromPtr(setter1) if err == nil { err = setter2.GetErr() } return err } - setterErr := getSetterErr() - if setterErr != nil { - log.Error(ctx).Msgf("Unwrap: error setter has value, err=%v", setterErr) + if preErr := getErr(); preErr != nil { + log.Err(preErr, ctx).Msgf("error setter has already set the error, err=%v", preErr) } var err = r.getErr() - for _, fn := range resultchecker.GetErrChecks() { + var checkers = append(resultchecker.GetErrChecks(), resultchecker.GetCheckersFromCtx(ctx)...) + for _, fn := range checkers { err = fn(ctx, err) if err == nil { return ret, nil @@ -199,3 +205,55 @@ func unwrapErr[T any](r Result[T], setter1 *error, setter2 ErrSetter, contexts . return ret, err } + +func setError(setter ErrSetter, err error) { + if err == nil { + return + } + + if setter == nil { + errNilOrPanic(errors.Errorf("error setter is nil")) + return + } + + switch errSet := setter.(type) { + case *Error: + errSet.err = err + case *ErrProxy: + *errSet.err = err + default: + rv := reflect.ValueOf(setter) + t := rv.Type() + + if !strings.Contains(t.String(), "Result[") { + slog.Error("error setter type error", + slog.String("type", fmt.Sprintf("%T", setter)), + slog.String("stack", string(debug.Stack())), + ) + return + } + + ret := (*Result[any])(rv.UnsafePointer()) + ret.err = err + } +} + +func logErr(ctx context.Context, err error, events ...func(e *zerolog.Event)) { + if err == nil { + return + } + + log.Error(ctx). + Func(func(e *zerolog.Event) { + for _, fn := range events { + fn(e) + } + + if id := errors.GetErrorId(err); id != "" { + e.Str("error_id", id) + } + }). + Str(zerolog.ErrorFieldName, err.Error()). + CallerSkipFrame(2). + Msgf("%s\n%s", err.Error(), prototext.Format(errors.ParseErrToPb(err))) +} diff --git a/vars/vars.go b/vars/vars.go index ef7415fe..123b9a13 100644 --- a/vars/vars.go +++ b/vars/vars.go @@ -4,7 +4,11 @@ import ( "encoding/json" "expvar" "fmt" + "strconv" + "strings" + "github.com/rs/xid" + "github.com/pubgo/funk/assert" "github.com/pubgo/funk/convert" "github.com/pubgo/funk/pretty" @@ -54,10 +58,14 @@ func (f Value) MarshalJSON() ([]byte, error) { func (f Value) Value() interface{} { return f() } func (f Value) String() (r string) { + return toString(f()) +} + +func toString(dt any) (r string) { var errStr = func(err any) string { ret, err := json.Marshal(err) if err != nil { - return pretty.Sprint(err) + return strconv.Quote(pretty.SimplePrint(err)) } else { return convert.B2S(ret) } @@ -65,28 +73,50 @@ func (f Value) String() (r string) { defer recovery.Recovery(func(err error) { r = errStr(err) }) - dt := f() switch dt := dt.(type) { case nil: return "null" case string: - return dt + return strconv.Quote(dt) case []byte: - return string(dt) + return strconv.Quote(string(dt)) case fmt.Stringer: - return dt.String() + return strconv.Quote(dt.String()) + case error: + return strconv.Quote(fmt.Sprintf("err:%s detail:%#v", dt, dt)) default: return errStr(dt) } } +func Any(v any) expvar.Var { + switch v.(type) { + case nil: + return anyValue{v: nil} + case Value: + return v.(Value) + default: + return anyValue{v: v} + } +} + +var _ expvar.Var = (*anyValue)(nil) + +type anyValue struct { + v any +} + +func (a anyValue) String() string { + return toString(a.v) +} + func Register(name string, value Value) { defer recovery.Exit() assert.If(Has(name), "name:%s already exists", name) expvar.Publish(name, value) } -func RegisterValue(name string, data interface{}) { +func RegisterValue(name string, data any) { defer recovery.Exit() assert.If(Has(name), "name:%s already exists", name) expvar.Publish(name, Value(func() interface{} { return data })) @@ -99,3 +129,7 @@ func Has(name string) bool { func Each(fn func(key string, val expvar.Var)) { expvar.Do(func(kv expvar.KeyValue) { fn(kv.Key, kv.Value) }) } + +func UniqueName(names ...string) string { + return strings.Join(append(names, xid.New().String()), "_") +} diff --git a/version/version.go b/version/version.go index b79e2b21..858709f2 100644 --- a/version/version.go +++ b/version/version.go @@ -2,6 +2,7 @@ package version import ( "runtime/debug" + "strings" ) var mainPath string @@ -20,6 +21,13 @@ var ( project = "project" ) +var ( + modified bool + os string + arch string + buildTags []string +) + func init() { bi, ok := debug.ReadBuildInfo() if !ok { @@ -30,12 +38,21 @@ func init() { for i := range bi.Settings { setting := bi.Settings[i] - if setting.Key == "vcs.revision" { + switch setting.Key { + case "vcs.revision": commitID = setting.Value - } - - if setting.Key == "vcs.time" { + case "vcs.time": buildTime = setting.Value + case "vcs.modified": + modified = setting.Value == "true" + case "GOOS": + os = setting.Value + case "GOARCH": + arch = setting.Value + case "-tags": + if setting.Value != "" { + buildTags = strings.Split(setting.Value, ",") + } } } }