more route info improvements

Former-commit-id: ccbe95de0badb1bf448fcc443cecda60772716dc
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-04-28 22:34:36 +03:00
parent 128cd255cb
commit 2a4043a3c2
14 changed files with 147 additions and 61 deletions

View File

@ -35,6 +35,8 @@ func configureAPI(api *iris.APIContainer) {
func main() {
app := iris.New()
app.Logger().SetLevel("debug")
app.ConfigureContainer(configureAPI)
app.Listen(":8080")
}

View File

@ -14,6 +14,8 @@ var cacheHandler = cache.Handler(10 * time.Second)
func main() {
app := iris.New()
app.Logger().SetLevel("debug")
mvc.Configure(app, configure)
// http://localhost:8080

View File

@ -103,7 +103,7 @@ func main() {
usersRoutes.Delete("/{id:uint64}", func(ctx iris.Context) {
id, _ := ctx.Params().GetUint64("id")
ctx.Writef("delete user by id: %d", id)
}).SetDescription("deletes a user")
}).Describe("deletes a user")
// Subdomains, depends on the host, you have to edit the hosts or nginx/caddy's configuration if you use them.
//

View File

@ -9,6 +9,10 @@ import (
"github.com/kataras/iris/v12/context"
)
func init() {
context.SetHandlerName("iris/cache/client.(*Handler).ServeHTTP-fm", "iris.cache")
}
// Handler the local cache service handler contains
// the original response, the memory cache entry and
// the validator for each of the incoming requests and post responses

View File

@ -19,7 +19,7 @@ var (
)
var (
handlerNames = make(map[*regexp.Regexp]string)
handlerNames = make(map[*nameExpr]string)
handlerNamesMu sync.RWMutex
)
@ -39,10 +39,35 @@ func SetHandlerName(original string, replacement string) {
}
handlerNamesMu.Lock()
handlerNames[regexp.MustCompile(original)] = replacement
// If regexp syntax is wrong
// then its `MatchString` will compare through literal. Fixes an issue
// when a handler name is declared as it's and cause regex parsing expression error,
// e.g. `iris/cache/client.(*Handler).ServeHTTP-fm`
regex, _ := regexp.Compile(original)
handlerNames[&nameExpr{
literal: original,
regex: regex,
}] = replacement
handlerNamesMu.Unlock()
}
type nameExpr struct {
regex *regexp.Regexp
literal string
}
func (expr *nameExpr) MatchString(s string) bool {
if expr.literal == s { // if matches as string, as it's.
return true
}
if expr.regex != nil {
return expr.regex.MatchString(s)
}
return false
}
// A Handler responds to an HTTP request.
// It writes reply headers and data to the Context.ResponseWriter() and then return.
// Returning signals that the request is finished;
@ -79,20 +104,16 @@ func HandlerName(h interface{}) string {
pc := valueOf(h).Pointer()
name := runtime.FuncForPC(pc).Name()
handlerNamesMu.RLock()
for regex, newName := range handlerNames {
if regex.String() == name { // if matches as string, as it's.
name = newName
break
}
if regex.MatchString(name) {
for expr, newName := range handlerNames {
if expr.MatchString(name) {
name = newName
break
}
}
handlerNamesMu.RUnlock()
return name
return trimHandlerName(name)
}
// HandlerFileLine returns the handler's file and line information.
@ -118,21 +139,98 @@ func HandlerFileLineRel(h interface{}) (file string, line int) {
// MainHandlerName tries to find the main handler that end-developer
// registered on the provided chain of handlers and returns its function name.
func MainHandlerName(handlers Handlers) (name string, index int) {
for i := 0; i < len(handlers); i++ {
name = HandlerName(handlers[i])
index = i
if !strings.HasPrefix(name, "github.com/kataras/iris/v12") ||
strings.HasPrefix(name, "github.com/kataras/iris/v12/core/router.StripPrefix") ||
strings.HasPrefix(name, "github.com/kataras/iris/v12/core/router.FileServer") {
break
func MainHandlerName(handlers ...interface{}) (name string, index int) {
if len(handlers) == 0 {
return
}
if hs, ok := handlers[0].(Handlers); ok {
tmp := make([]interface{}, 0, len(hs))
for _, h := range hs {
tmp = append(tmp, h)
}
return MainHandlerName(tmp...)
}
for i := 0; i < len(handlers); i++ {
name = HandlerName(handlers[i])
if name == "" {
continue
}
index = i
if !ingoreMainHandlerName(name) {
break
}
}
return
}
func trimHandlerName(name string) string {
// trim the path for Iris' internal middlewares, e.g.
// irs/mvc.GRPC.Apply.func1
if internalName := PackageName; strings.HasPrefix(name, internalName) {
name = strings.Replace(name, internalName, "iris", 1)
}
if internalName := "github.com/iris-contrib/middleware"; strings.HasPrefix(name, internalName) {
name = strings.Replace(name, internalName, "iris-contrib", 1)
}
name = strings.TrimSuffix(name, ".func1")
return name
}
var ignoreHandlerNames = [...]string{
"iris/macro/handler.MakeHandler",
"iris/hero.makeHandler.func2",
"iris/core/router.ExecutionOptions.buildHandler",
"iris/core/router.(*APIBuilder).Favicon",
"iris/core/router.StripPrefix",
}
// IgnoreHandlerName compares a static slice of Iris builtin
// internal methods that should be ignored from trace.
// Some internal methods are kept out of this list for actual debugging.
func IgnoreHandlerName(name string) bool {
for _, ignore := range ignoreHandlerNames {
if name == ignore {
return true
}
}
return false
}
var ignoreMainHandlerNames = [...]string{
"iris.cache",
"iris.basicauth",
"iris.hCaptcha",
"iris.reCAPTCHA",
"iris.profiling",
"iris.recover",
}
// ingoreMainHandlerName reports whether a main handler of "name" should
// be ignored and continue to match the next.
// The ignored main handler names are literals and respects the `ignoreNameHandlers` too.
func ingoreMainHandlerName(name string) bool {
if IgnoreHandlerName(name) {
// If ignored at all, it can't be the main.
return true
}
for _, ignore := range ignoreMainHandlerNames {
if name == ignore {
return true
}
}
return false
}
// Filter is just a type of func(Handler) bool which reports whether an action must be performed
// based on the incoming request.
//

View File

@ -399,7 +399,7 @@ func (api *APIBuilder) HandleDir(requestPath, directory string, opts ...DirOptio
for _, route := range routes {
if route.Method == http.MethodHead {
} else {
route.SetDescription(description)
route.Describe(description)
route.SetSourceLine(fileName, lineNumber)
}
@ -453,6 +453,7 @@ func (api *APIBuilder) CreateRoutes(methods []string, relativePath string, handl
// before join the middleware + handlers + done handlers and apply the execution rules.
mainHandlerName, mainHandlerIndex := context.MainHandlerName(mainHandlers)
mainHandlerFileName, mainHandlerFileNumber := context.HandlerFileLineRel(handlers[mainHandlerIndex])
// re-calculate mainHandlerIndex in favor of the middlewares.
@ -939,7 +940,7 @@ func (api *APIBuilder) Favicon(favPath string, requestPath ...string) *Route {
reqPath = requestPath[0]
}
return api.registerResourceRoute(reqPath, h).SetDescription(description)
return api.registerResourceRoute(reqPath, h).Describe(description)
}
// OnErrorCode registers an error http status code

View File

@ -117,7 +117,15 @@ func (api *APIContainer) Done(handlersFn ...interface{}) {
// See `OnError`, `RegisterDependency`, `Use`, `Done`, `Get`, `Post`, `Put`, `Patch` and `Delete` too.
func (api *APIContainer) Handle(method, relativePath string, handlersFn ...interface{}) *Route {
handlers := api.convertHandlerFuncs(relativePath, handlersFn...)
return api.Self.Handle(method, relativePath, handlers...)
route := api.Self.Handle(method, relativePath, handlers...)
// Fix main handler name and source modified by execution rules wrapper.
route.MainHandlerName, route.MainHandlerIndex = context.MainHandlerName(handlersFn...)
if len(handlersFn) > route.MainHandlerIndex {
route.SourceFileName, route.SourceLineNumber = context.HandlerFileLineRel(handlersFn[route.MainHandlerIndex])
}
return route
}
// Get registers a route for the Get HTTP Method.

View File

@ -145,11 +145,11 @@ func (r *Route) SetStatusOffline() bool {
return r.ChangeMethod(MethodNone)
}
// SetDescription sets the route's description
// Describe sets the route's description
// that will be logged alongside with the route information
// in DEBUG log level.
// Returns the `Route` itself.
func (r *Route) SetDescription(description string) *Route {
func (r *Route) Describe(description string) *Route {
r.Description = description
return r
}
@ -341,38 +341,10 @@ func (r *Route) ResolvePath(args ...string) string {
return formattedPath
}
var ignoreHandlersTraces = [...]string{
"iris/macro/handler.MakeHandler",
"iris/hero.makeHandler.func2",
"iris/core/router.(*APIBuilder).Favicon",
"iris/core/router.StripPrefix",
}
func ignoreHandlerTrace(name string) bool {
for _, ignore := range ignoreHandlersTraces {
if name == ignore {
return true
}
}
return false
}
func traceHandlerFile(method, name, line string, number int) string {
file := fmt.Sprintf("(%s:%d)", line, number)
// trim the path for Iris' internal middlewares, e.g.
// irs/mvc.GRPC.Apply.func1
if internalName := context.PackageName; strings.HasPrefix(name, internalName) {
name = strings.Replace(name, internalName, "iris", 1)
}
if internalName := "github.com/iris-contrib/middleware"; strings.HasPrefix(name, internalName) {
name = strings.Replace(name, internalName, "iris-contrib", 1)
}
name = strings.TrimSuffix(name, ".func1")
if ignoreHandlerTrace(name) {
if context.IgnoreHandlerName(name) {
return ""
}
@ -457,7 +429,7 @@ func (r *Route) Trace(w io.Writer) {
line int
)
if i == r.MainHandlerIndex {
if i == r.MainHandlerIndex && r.MainHandlerName != "" {
// Main handler info can be programmatically
// changed to be more specific, respect these changes.
name = r.MainHandlerName
@ -466,7 +438,6 @@ func (r *Route) Trace(w io.Writer) {
} else {
name = context.HandlerName(h)
file, line = context.HandlerFileLineRel(h)
// If a middleware, e.g (macro) which changes the main handler index,
// skip it.
if file == r.SourceFileName && line == r.SourceLineNumber {

View File

@ -13,7 +13,7 @@ import (
)
func init() {
context.SetHandlerName("iris/middleware/basicauth.*", "Basic Authentication")
context.SetHandlerName("iris/middleware/basicauth.*", "iris.basicauth")
}
type (

View File

@ -11,7 +11,7 @@ import (
)
func init() {
context.SetHandlerName("iris/middleware/hcaptcha.*", "hCaptcha")
context.SetHandlerName("iris/middleware/hcaptcha.*", "iris.hCaptcha")
}
var (

View File

@ -12,7 +12,7 @@ import (
)
func init() {
context.SetHandlerName("iris/middleware/logger.*", "Request Logger")
context.SetHandlerName("iris/middleware/logger.*", "iris.logger")
}
type requestLoggerMiddleware struct {

View File

@ -12,7 +12,7 @@ import (
)
func init() {
context.SetHandlerName("iris/middleware/pprof.*", "Profiling")
context.SetHandlerName("iris/middleware/pprof.*", "iris.profiling")
}
// New returns a new pprof (profile, cmdline, symbol, goroutine, heap, threadcreate, debug/block) Middleware.

View File

@ -12,7 +12,7 @@ import (
)
func init() {
context.SetHandlerName("iris/middleware/recaptcha.*", "reCAPTCHA")
context.SetHandlerName("iris/middleware/recaptcha.*", "iris.reCAPTCHA")
}
const (

View File

@ -10,7 +10,7 @@ import (
)
func init() {
context.SetHandlerName("iris/middleware/recover.*", "Panic Recover")
context.SetHandlerName("iris/middleware/recover.*", "iris.recover")
}
func getRequestLogs(ctx context.Context) string {