package exerr import ( "context" "fmt" "github.com/gin-gonic/gin" "github.com/rs/zerolog" "gogs.mikescher.com/BlackForestBytes/goext/langext" "net/http" "os" ) type ErrorPackageConfig struct { ZeroLogErrTraces bool // autom print zerolog logs on .Build() (for SevErr and SevFatal) ZeroLogAllTraces bool // autom print zerolog logs on .Build() (for all Severities) RecursiveErrors bool // errors contains their Origin-Error ExtendedGinOutput bool // Log extended data (trace, meta, ...) to gin in err.Output() IncludeMetaInGinOutput bool // Log meta fields ( from e.g. `.Str(key, val).Build()` ) to gin in err.Output() ExtendGinOutput func(err *ExErr, json map[string]any) // (Optionally) extend the gin output with more fields ExtendGinDataOutput func(err *ExErr, depth int, json map[string]any) // (Optionally) extend the gin `__data` output with more fields DisableErrorWrapping bool // Disables the exerr.Wrap()...Build() function - will always return the original error ZeroLogErrGinOutput bool // autom print zerolog logs on ginext.Error() / .Output(gin) (for SevErr and SevFatal) ZeroLogAllGinOutput bool // autom print zerolog logs on ginext.Error() / .Output(gin) (for all Severities) ExtendGinMeta func(ctx context.Context, b *Builder, g *gin.Context, req *http.Request) // (Optionally) extend the final error meta values with additional data from the gin context (a few are automatically added, here more can be included) ExtendContextMeta func(b *Builder, method Method, dctx context.Context) // (Optionally) extend the final error meta values with additional data from the context (a few are automatically added, here more can be included) ZeroLogger zerolog.Logger // The logger used to print exerr log messages } type ErrorPackageConfigInit struct { ZeroLogErrTraces *bool ZeroLogAllTraces *bool RecursiveErrors *bool ExtendedGinOutput *bool IncludeMetaInGinOutput *bool ExtendGinOutput func(err *ExErr, json map[string]any) ExtendGinDataOutput func(err *ExErr, depth int, json map[string]any) DisableErrorWrapping *bool ZeroLogErrGinOutput *bool ZeroLogAllGinOutput *bool ExtendGinMeta func(ctx context.Context, b *Builder, g *gin.Context, req *http.Request) ExtendContextMeta func(b *Builder, method Method, dctx context.Context) ZeroLogger *zerolog.Logger } var initialized = false var pkgconfig = ErrorPackageConfig{ ZeroLogErrTraces: true, ZeroLogAllTraces: false, RecursiveErrors: true, ExtendedGinOutput: false, IncludeMetaInGinOutput: true, ExtendGinOutput: func(err *ExErr, json map[string]any) {}, ExtendGinDataOutput: func(err *ExErr, depth int, json map[string]any) {}, DisableErrorWrapping: false, ZeroLogErrGinOutput: true, ZeroLogAllGinOutput: false, ExtendGinMeta: func(ctx context.Context, b *Builder, g *gin.Context, req *http.Request) {}, ExtendContextMeta: func(b *Builder, method Method, dctx context.Context) {}, } // Init initializes the exerr packages // Must be called at the program start, before (!) any errors // Is not thread-safe func Init(cfg ErrorPackageConfigInit) { if initialized { panic("Cannot re-init error package") } ego := func(err *ExErr, json map[string]any) {} egdo := func(err *ExErr, depth int, json map[string]any) {} egm := func(ctx context.Context, b *Builder, g *gin.Context, req *http.Request) {} egcm := func(b *Builder, method Method, dctx context.Context) {} if cfg.ExtendGinOutput != nil { ego = cfg.ExtendGinOutput } if cfg.ExtendGinDataOutput != nil { egdo = cfg.ExtendGinDataOutput } if cfg.ExtendGinMeta != nil { egm = cfg.ExtendGinMeta } if cfg.ExtendContextMeta != nil { egcm = cfg.ExtendContextMeta } var logger zerolog.Logger if cfg.ZeroLogger != nil { logger = *cfg.ZeroLogger } else { logger = newDefaultLogger() } pkgconfig = ErrorPackageConfig{ ZeroLogErrTraces: langext.Coalesce(cfg.ZeroLogErrTraces, pkgconfig.ZeroLogErrTraces), ZeroLogAllTraces: langext.Coalesce(cfg.ZeroLogAllTraces, pkgconfig.ZeroLogAllTraces), RecursiveErrors: langext.Coalesce(cfg.RecursiveErrors, pkgconfig.RecursiveErrors), ExtendedGinOutput: langext.Coalesce(cfg.ExtendedGinOutput, pkgconfig.ExtendedGinOutput), IncludeMetaInGinOutput: langext.Coalesce(cfg.IncludeMetaInGinOutput, pkgconfig.IncludeMetaInGinOutput), ExtendGinOutput: ego, ExtendGinDataOutput: egdo, DisableErrorWrapping: langext.Coalesce(cfg.DisableErrorWrapping, pkgconfig.DisableErrorWrapping), ZeroLogAllGinOutput: langext.Coalesce(cfg.ZeroLogAllGinOutput, pkgconfig.ZeroLogAllGinOutput), ZeroLogErrGinOutput: langext.Coalesce(cfg.ZeroLogErrGinOutput, pkgconfig.ZeroLogErrGinOutput), ExtendGinMeta: egm, ExtendContextMeta: egcm, ZeroLogger: logger, } initialized = true } func newDefaultLogger() zerolog.Logger { cw := zerolog.ConsoleWriter{ Out: os.Stdout, TimeFormat: "2006-01-02 15:04:05 Z07:00", } multi := zerolog.MultiLevelWriter(cw) return zerolog.New(multi).With().Timestamp().CallerWithSkipFrameCount(4).Logger() } func Initialized() bool { return initialized } func warnOnPkgConfigNotInitialized() { if !initialized { fmt.Printf("\n") fmt.Printf("%s\n", langext.StrRepeat("=", 80)) fmt.Printf("%s\n", "[WARNING] exerr package used without initializiation") fmt.Printf("%s\n", " call exerr.Init() in your main() function") fmt.Printf("%s\n", langext.StrRepeat("=", 80)) fmt.Printf("\n") } }