diff --git a/debug/gdebug/gdebug_stack.go b/debug/gdebug/gdebug_stack.go index af61b9591..09ac951cd 100644 --- a/debug/gdebug/gdebug_stack.go +++ b/debug/gdebug/gdebug_stack.go @@ -9,6 +9,7 @@ package gdebug import ( "bytes" "fmt" + "github.com/gogf/gf/internal/utils" "runtime" "strings" ) @@ -82,6 +83,11 @@ func StackWithFilters(filters []string, skip ...int) string { if strings.Contains(file, stackFilterKey) { continue } + if !utils.IsDebugEnabled() { + if strings.Contains(file, utils.StackFilterKeyForGoFrame) { + continue + } + } if fn := runtime.FuncForPC(pc); fn == nil { name = "unknown" } else { diff --git a/errors/gerror/gerror_error.go b/errors/gerror/gerror_error.go index 1e7588269..01d593134 100644 --- a/errors/gerror/gerror_error.go +++ b/errors/gerror/gerror_error.go @@ -10,6 +10,7 @@ import ( "bytes" "errors" "fmt" + "github.com/gogf/gf/internal/utils" "io" "runtime" "strings" @@ -24,7 +25,8 @@ type Error struct { } const ( - stackFilterKey = "/errors/gerror/gerror" + // Filtering key for current error module paths. + stackFilterKeyLocal = "/errors/gerror/gerror" ) var ( @@ -182,20 +184,34 @@ func formatSubStack(st stack, buffer *bytes.Buffer) { for _, p := range st { if fn := runtime.FuncForPC(p - 1); fn != nil { file, line := fn.FileLine(p - 1) - if strings.Contains(file, stackFilterKey) { - continue + // Custom filtering. + if !utils.IsDebugEnabled() { + if strings.Contains(file, utils.StackFilterKeyForGoFrame) { + continue + } + } else { + if strings.Contains(file, stackFilterKeyLocal) { + continue + } } // Avoid stack string like "" if strings.Contains(file, "<") { continue } - if goRootForFilter != "" && len(file) >= len(goRootForFilter) && file[0:len(goRootForFilter)] == goRootForFilter { + // Ignore GO ROOT paths. + if goRootForFilter != "" && + len(file) >= len(goRootForFilter) && + file[0:len(goRootForFilter)] == goRootForFilter { continue } + // Graceful indent. if index > 9 { space = " " } - buffer.WriteString(fmt.Sprintf(" %d).%s%s\n \t%s:%d\n", index, space, fn.Name(), file, line)) + buffer.WriteString(fmt.Sprintf( + " %d).%s%s\n \t%s:%d\n", + index, space, fn.Name(), file, line, + )) index++ } } diff --git a/internal/command/command.go b/internal/command/command.go new file mode 100644 index 000000000..56f2a9d55 --- /dev/null +++ b/internal/command/command.go @@ -0,0 +1,127 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. +// + +// Package command provides console operations, like options/arguments reading. +package command + +import ( + "os" + "regexp" + "strings" +) + +var ( + defaultParsedArgs = make([]string, 0) + defaultParsedOptions = make(map[string]string) + argumentRegex = regexp.MustCompile(`^\-{1,2}([\w\?\.\-]+)(=){0,1}(.*)$`) +) + +// Custom initialization. +func Init(args ...string) { + if len(args) == 0 { + if len(defaultParsedArgs) == 0 && len(defaultParsedOptions) == 0 { + args = os.Args + } else { + return + } + } else { + defaultParsedArgs = make([]string, 0) + defaultParsedOptions = make(map[string]string) + } + // Parsing os.Args with default algorithm. + for i := 0; i < len(args); { + array := argumentRegex.FindStringSubmatch(args[i]) + if len(array) > 2 { + if array[2] == "=" { + defaultParsedOptions[array[1]] = array[3] + } else if i < len(args)-1 { + if len(args[i+1]) > 0 && args[i+1][0] == '-' { + // Eg: gf gen -d -n 1 + defaultParsedOptions[array[1]] = array[3] + } else { + // Eg: gf gen -n 2 + defaultParsedOptions[array[1]] = args[i+1] + i += 2 + continue + } + } else { + // Eg: gf gen -h + defaultParsedOptions[array[1]] = array[3] + } + } else { + defaultParsedArgs = append(defaultParsedArgs, args[i]) + } + i++ + } +} + +// GetOpt returns the option value named . +func GetOpt(name string, def ...string) string { + Init() + if v, ok := defaultParsedOptions[name]; ok { + return v + } + if len(def) > 0 { + return def[0] + } + return "" +} + +// GetOptAll returns all parsed options. +func GetOptAll() map[string]string { + Init() + return defaultParsedOptions +} + +// ContainsOpt checks whether option named exist in the arguments. +func ContainsOpt(name string) bool { + Init() + _, ok := defaultParsedOptions[name] + return ok +} + +// GetArg returns the argument at . +func GetArg(index int, def ...string) string { + Init() + if index < len(defaultParsedArgs) { + return defaultParsedArgs[index] + } + if len(def) > 0 { + return def[0] + } + return "" +} + +// GetArgAll returns all parsed arguments. +func GetArgAll() []string { + Init() + return defaultParsedArgs +} + +// GetOptWithEnv returns the command line argument of the specified . +// If the argument does not exist, then it returns the environment variable with specified . +// It returns the default value if none of them exists. +// +// Fetching Rules: +// 1. Command line arguments are in lowercase format, eg: gf..; +// 2. Environment arguments are in uppercase format, eg: GF__; +func GetOptWithEnv(key string, def ...string) string { + cmdKey := strings.ToLower(strings.Replace(key, "_", ".", -1)) + if ContainsOpt(cmdKey) { + return GetOpt(cmdKey) + } else { + envKey := strings.ToUpper(strings.Replace(key, ".", "_", -1)) + if r, ok := os.LookupEnv(envKey); ok { + return r + } else { + if len(def) > 0 { + return def[0] + } + } + } + return "" +} diff --git a/internal/intlog/intlog.go b/internal/intlog/intlog.go index 98f12322c..d746d5862 100644 --- a/internal/intlog/intlog.go +++ b/internal/intlog/intlog.go @@ -10,7 +10,7 @@ package intlog import ( "fmt" "github.com/gogf/gf/debug/gdebug" - "github.com/gogf/gf/os/gcmd" + "github.com/gogf/gf/internal/utils" "path/filepath" "time" ) @@ -25,11 +25,7 @@ var ( ) func init() { - // Debugging configured. - if !gcmd.GetOptWithEnv("GF_DEBUG").IsEmpty() { - isGFDebug = true - return - } + isGFDebug = utils.IsDebugEnabled() } // SetEnabled enables/disables the internal logging manually. diff --git a/internal/utils/utils_debug.go b/internal/utils/utils_debug.go new file mode 100644 index 000000000..c03d30dd4 --- /dev/null +++ b/internal/utils/utils_debug.go @@ -0,0 +1,37 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package utils + +import ( + "github.com/gogf/gf/internal/command" +) + +const ( + debugKey = "gf.debug" // Debug key for checking if in debug mode. + StackFilterKeyForGoFrame = "/github.com/gogf/gf/" // Stack filtering key for all GoFrame module paths. +) + +var ( + // isDebugEnabled marks whether GoFrame debug mode is enabled. + isDebugEnabled = false +) + +func init() { + // Debugging configured. + value := command.GetOptWithEnv(debugKey) + if value == "" || value == "0" || value == "false" { + isDebugEnabled = false + } else { + isDebugEnabled = true + } +} + +// IsDebugEnabled checks and returns whether debug mode is enabled. +// The debug mode is enabled when command argument "gf.debug" or environment "GF_DEBUG" is passed. +func IsDebugEnabled() bool { + return isDebugEnabled +} diff --git a/os/gcmd/gcmd.go b/os/gcmd/gcmd.go index d3cf5e65d..777a881ac 100644 --- a/os/gcmd/gcmd.go +++ b/os/gcmd/gcmd.go @@ -9,69 +9,25 @@ package gcmd import ( + "github.com/gogf/gf/container/gvar" + "github.com/gogf/gf/internal/command" "os" "strings" - - "github.com/gogf/gf/container/gvar" - - "github.com/gogf/gf/text/gregex" ) var ( - defaultParsedArgs = make([]string, 0) - defaultParsedOptions = make(map[string]string) defaultCommandFuncMap = make(map[string]func()) ) // Custom initialization. func Init(args ...string) { - if len(args) == 0 { - if len(defaultParsedArgs) == 0 && len(defaultParsedOptions) == 0 { - args = os.Args - } else { - return - } - } else { - defaultParsedArgs = make([]string, 0) - defaultParsedOptions = make(map[string]string) - } - // Parsing os.Args with default algorithm. - for i := 0; i < len(args); { - array, _ := gregex.MatchString(`^\-{1,2}([\w\?\.\-]+)(=){0,1}(.*)$`, args[i]) - if len(array) > 2 { - if array[2] == "=" { - defaultParsedOptions[array[1]] = array[3] - } else if i < len(args)-1 { - if len(args[i+1]) > 0 && args[i+1][0] == '-' { - // Eg: gf gen -d -n 1 - defaultParsedOptions[array[1]] = array[3] - } else { - // Eg: gf gen -n 2 - defaultParsedOptions[array[1]] = args[i+1] - i += 2 - continue - } - } else { - // Eg: gf gen -h - defaultParsedOptions[array[1]] = array[3] - } - } else { - defaultParsedArgs = append(defaultParsedArgs, args[i]) - } - i++ - } + command.Init(args...) } // GetOpt returns the option value named . func GetOpt(name string, def ...string) string { Init() - if v, ok := defaultParsedOptions[name]; ok { - return v - } - if len(def) > 0 { - return def[0] - } - return "" + return command.GetOpt(name, def...) } // GetOptVar returns the option value named as gvar.Var. @@ -83,26 +39,19 @@ func GetOptVar(name string, def ...string) *gvar.Var { // GetOptAll returns all parsed options. func GetOptAll() map[string]string { Init() - return defaultParsedOptions + return command.GetOptAll() } // ContainsOpt checks whether option named exist in the arguments. -func ContainsOpt(name string, def ...string) bool { +func ContainsOpt(name string) bool { Init() - _, ok := defaultParsedOptions[name] - return ok + return command.ContainsOpt(name) } // GetArg returns the argument at . func GetArg(index int, def ...string) string { Init() - if index < len(defaultParsedArgs) { - return defaultParsedArgs[index] - } - if len(def) > 0 { - return def[0] - } - return "" + return command.GetArg(index, def...) } // GetArgVar returns the argument at as gvar.Var. @@ -114,7 +63,7 @@ func GetArgVar(index int, def ...string) *gvar.Var { // GetArgAll returns all parsed arguments. func GetArgAll() []string { Init() - return defaultParsedArgs + return command.GetArgAll() } // GetWithEnv is alias of GetOptWithEnv. @@ -131,20 +80,20 @@ func GetWithEnv(key string, def ...interface{}) *gvar.Var { // 1. Command line arguments are in lowercase format, eg: gf..; // 2. Environment arguments are in uppercase format, eg: GF__; func GetOptWithEnv(key string, def ...interface{}) *gvar.Var { - value := interface{}(nil) - if len(def) > 0 { - value = def[0] - } cmdKey := strings.ToLower(strings.Replace(key, "_", ".", -1)) - if v := GetOpt(cmdKey); v != "" { - value = v + if ContainsOpt(cmdKey) { + return gvar.New(GetOpt(cmdKey)) } else { envKey := strings.ToUpper(strings.Replace(key, ".", "_", -1)) - if v := os.Getenv(envKey); v != "" { - value = v + if r, ok := os.LookupEnv(envKey); ok { + return gvar.New(r) + } else { + if len(def) > 0 { + return gvar.New(def[0]) + } } } - return gvar.New(value) + return gvar.New(nil) } // BuildOptions builds the options as string.