mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
improve route debug info, see HISTORY.md
Former-commit-id: ae245bae5fefa57c5f7663f7d1d661ec68ad366a
This commit is contained in:
parent
5d3c96947c
commit
77a79cae58
|
@ -180,7 +180,9 @@ Other Improvements:
|
||||||
- New Router [Wrapper](middleware/grpc).
|
- New Router [Wrapper](middleware/grpc).
|
||||||
- New MVC `.Handle(ctrl, mvc.GRPC{...})` option which allows to register gRPC services per-party (without the requirement of a full wrapper) and optionally strict access to gRPC clients only, see the [example here](_examples/mvc/grpc-compatible).
|
- New MVC `.Handle(ctrl, mvc.GRPC{...})` option which allows to register gRPC services per-party (without the requirement of a full wrapper) and optionally strict access to gRPC clients only, see the [example here](_examples/mvc/grpc-compatible).
|
||||||
|
|
||||||
- Improved logging (with `app.Logger().SetLevel("debug")`) for MVC-registered routes.
|
- Improved tracing (with `app.Logger().SetLevel("debug")`) for routes. Example:
|
||||||
|
|
||||||
|
![DBUG routes](https://iris-go.com/images/v12.2.0-dbug.png)
|
||||||
|
|
||||||
- New `iris.WithLowercaseRouting` option which forces all routes' paths to be lowercase and converts request paths to their lowercase for matching.
|
- New `iris.WithLowercaseRouting` option which forces all routes' paths to be lowercase and converts request paths to their lowercase for matching.
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,12 @@ func main() {
|
||||||
|
|
||||||
func newApp() *iris.Application {
|
func newApp() *iris.Application {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
app.Logger().SetLevel("debug")
|
// app.Configure(iris.WithLowercaseRouting) // OPTIONAL.
|
||||||
|
app.Logger().SetLevel("debug").SetTimeFormat("")
|
||||||
|
|
||||||
|
app.Get("/", func(ctx iris.Context) {
|
||||||
|
ctx.HTML("<h1>Index Page</h1>")
|
||||||
|
})
|
||||||
|
|
||||||
ctrl := &myController{}
|
ctrl := &myController{}
|
||||||
// Register gRPC server.
|
// Register gRPC server.
|
||||||
|
|
|
@ -51,25 +51,30 @@ func HandlerFileLine(h interface{}) (file string, line int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandlerFileLineRel same as `HandlerFileLine` but it returns the path as relative to the "workingDir".
|
// HandlerFileLineRel same as `HandlerFileLine` but it returns the path as relative to the "workingDir".
|
||||||
func HandlerFileLineRel(h interface{}, workingDir string) (string, int) {
|
func HandlerFileLineRel(h interface{}, workingDir string) (file string, line int) {
|
||||||
file, line := HandlerFileLine(h)
|
file, line = HandlerFileLine(h)
|
||||||
if relFile, err := filepath.Rel(workingDir, file); err == nil {
|
if relFile, err := filepath.Rel(workingDir, file); err == nil {
|
||||||
|
if !strings.HasPrefix(relFile, "..") {
|
||||||
|
// Only if it's relative to this path, not parent.
|
||||||
file = "./" + relFile
|
file = "./" + relFile
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return file, line
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// MainHandlerName tries to find the main handler than end-developer
|
// MainHandlerName tries to find the main handler that end-developer
|
||||||
// registered on the provided chain of handlers and returns its function name.
|
// registered on the provided chain of handlers and returns its function name.
|
||||||
func MainHandlerName(handlers Handlers) (name string) {
|
func MainHandlerName(handlers Handlers) (name string, index int) {
|
||||||
for i := 0; i < len(handlers); i++ {
|
for i := 0; i < len(handlers); i++ {
|
||||||
name = HandlerName(handlers[i])
|
name = HandlerName(handlers[i])
|
||||||
|
index = i
|
||||||
if !strings.HasPrefix(name, "github.com/kataras/iris/v12") ||
|
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.StripPrefix") ||
|
||||||
strings.HasPrefix(name, "github.com/kataras/iris/v12/core/router.FileServer") {
|
strings.HasPrefix(name, "github.com/kataras/iris/v12/core/router.FileServer") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -444,7 +444,9 @@ func (api *APIBuilder) CreateRoutes(methods []string, relativePath string, handl
|
||||||
mainHandlers := context.Handlers(handlers)
|
mainHandlers := context.Handlers(handlers)
|
||||||
// before join the middleware + handlers + done handlers and apply the execution rules.
|
// before join the middleware + handlers + done handlers and apply the execution rules.
|
||||||
|
|
||||||
possibleMainHandlerName := context.MainHandlerName(mainHandlers)
|
possibleMainHandlerName, mainHandlerIndex := context.MainHandlerName(mainHandlers)
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
mainHandlerFileName, mainHandlerFileNumber := context.HandlerFileLineRel(handlers[mainHandlerIndex], wd)
|
||||||
|
|
||||||
// TODO: for UseGlobal/DoneGlobal that doesn't work.
|
// TODO: for UseGlobal/DoneGlobal that doesn't work.
|
||||||
applyExecutionRules(api.handlerExecutionRules, &beginHandlers, &doneHandlers, &mainHandlers)
|
applyExecutionRules(api.handlerExecutionRules, &beginHandlers, &doneHandlers, &mainHandlers)
|
||||||
|
@ -470,8 +472,11 @@ func (api *APIBuilder) CreateRoutes(methods []string, relativePath string, handl
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
route.SourceFileName = filename
|
route.SourceFileName = mainHandlerFileName
|
||||||
route.SourceLineNumber = line
|
route.SourceLineNumber = mainHandlerFileNumber
|
||||||
|
|
||||||
|
route.RegisterFileName = filename
|
||||||
|
route.RegisterLineNumber = line
|
||||||
|
|
||||||
// Add UseGlobal & DoneGlobal Handlers
|
// Add UseGlobal & DoneGlobal Handlers
|
||||||
route.Use(api.beginGlobalHandlers...)
|
route.Use(api.beginGlobalHandlers...)
|
||||||
|
@ -1011,8 +1016,8 @@ func getCaller() (string, int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(file, "/kataras/iris") ||
|
if !strings.Contains(file, "/kataras/iris") ||
|
||||||
strings.Contains(file, "/kataras/iris/_examples") ||
|
strings.Contains(file, "_examples") ||
|
||||||
strings.Contains(file, "iris-contrib/examples") {
|
strings.Contains(file, "examples") {
|
||||||
if relFile, err := filepath.Rel(wd, file); err == nil {
|
if relFile, err := filepath.Rel(wd, file); err == nil {
|
||||||
file = "./" + relFile
|
file = "./" + relFile
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,16 @@ package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/context"
|
"github.com/kataras/iris/v12/context"
|
||||||
"github.com/kataras/iris/v12/macro"
|
"github.com/kataras/iris/v12/macro"
|
||||||
"github.com/kataras/iris/v12/macro/handler"
|
"github.com/kataras/iris/v12/macro/handler"
|
||||||
|
|
||||||
|
"github.com/kataras/pio"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Route contains the information about a registered Route.
|
// Route contains the information about a registered Route.
|
||||||
|
@ -37,8 +41,12 @@ type Route struct {
|
||||||
FormattedPath string `json:"formattedPath"`
|
FormattedPath string `json:"formattedPath"`
|
||||||
|
|
||||||
// the source code's filename:filenumber that this route was created from.
|
// the source code's filename:filenumber that this route was created from.
|
||||||
SourceFileName string
|
SourceFileName string `json:"sourceFileName"`
|
||||||
SourceLineNumber int
|
SourceLineNumber int `json:"sourceLineNumber"`
|
||||||
|
|
||||||
|
// where the route registered.
|
||||||
|
RegisterFileName string `json:"registerFileName"`
|
||||||
|
RegisterLineNumber int `json:"registerLineNumber"`
|
||||||
|
|
||||||
// StaticSites if not empty, refers to the system (or virtual if embedded) directory
|
// StaticSites if not empty, refers to the system (or virtual if embedded) directory
|
||||||
// and sub directories that this "GET" route was registered to serve files and folders
|
// and sub directories that this "GET" route was registered to serve files and folders
|
||||||
|
@ -317,34 +325,82 @@ func (r *Route) ResolvePath(args ...string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trace returns some debug infos as a string sentence.
|
// Trace returns some debug infos as a string sentence.
|
||||||
// Should be called after Build.
|
// Should be called after `Build` state.
|
||||||
|
//
|
||||||
|
// It prints the @method: @path (@description) (@route_rel_location)
|
||||||
|
// * @handler_name (@handler_rel_location)
|
||||||
|
// * @second_handler ...
|
||||||
|
// If route and handler line:number locations are equal then the second is ignored.
|
||||||
func (r *Route) Trace() string {
|
func (r *Route) Trace() string {
|
||||||
printfmt := fmt.Sprintf("[%s:%d] %s:", r.SourceFileName, r.SourceLineNumber, r.Method)
|
// Color the method.
|
||||||
|
color := pio.Black
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
color = pio.Green
|
||||||
|
case http.MethodPost:
|
||||||
|
color = pio.Magenta
|
||||||
|
case http.MethodPut:
|
||||||
|
color = pio.Blue
|
||||||
|
case http.MethodDelete:
|
||||||
|
color = pio.Red
|
||||||
|
case http.MethodConnect:
|
||||||
|
color = pio.Green
|
||||||
|
case http.MethodHead:
|
||||||
|
color = pio.Green
|
||||||
|
case http.MethodPatch:
|
||||||
|
color = pio.Blue
|
||||||
|
case http.MethodOptions:
|
||||||
|
color = pio.Gray
|
||||||
|
case http.MethodTrace:
|
||||||
|
color = pio.Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
path := r.Tmpl().Src
|
||||||
if r.Subdomain != "" {
|
if r.Subdomain != "" {
|
||||||
printfmt += fmt.Sprintf(" %s", r.Subdomain)
|
path = fmt.Sprintf("%s %s", r.Subdomain, path)
|
||||||
}
|
}
|
||||||
printfmt += fmt.Sprintf(" %s", r.Tmpl().Src)
|
|
||||||
|
|
||||||
|
// @method: @path
|
||||||
|
s := fmt.Sprintf("%s: %s", pio.Rich(r.Method, color), path)
|
||||||
|
|
||||||
|
// (@description)
|
||||||
if r.Description != "" {
|
if r.Description != "" {
|
||||||
printfmt += fmt.Sprintf(" (%s)", r.Description)
|
s += fmt.Sprintf(" %s", pio.Rich(r.Description, pio.Cyan, pio.Underline))
|
||||||
}
|
}
|
||||||
|
|
||||||
mainHandlerName := r.MainHandlerName
|
// (@route_rel_location)
|
||||||
if !strings.HasSuffix(mainHandlerName, ")") {
|
s += fmt.Sprintf(" (%s:%d)", r.RegisterFileName, r.RegisterLineNumber)
|
||||||
mainHandlerName += "()"
|
|
||||||
|
// if the main handler is not an anonymous function (so, differs from @route_rel_location)
|
||||||
|
// then * @handler_name (@handler_rel_location)
|
||||||
|
if r.SourceFileName != r.RegisterFileName || r.SourceLineNumber != r.RegisterLineNumber {
|
||||||
|
s += fmt.Sprintf("\n ⬝ %s (%s:%d)", r.MainHandlerName, r.SourceFileName, r.SourceLineNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
if l := r.RegisteredHandlersLen(); l > 1 {
|
wd, _ := os.Getwd()
|
||||||
printfmt += fmt.Sprintf(" -> %s and %d more", mainHandlerName, l-1)
|
|
||||||
} else {
|
for _, h := range r.Handlers {
|
||||||
printfmt += fmt.Sprintf(" -> %s", mainHandlerName)
|
name := context.HandlerName(h)
|
||||||
|
if name == r.MainHandlerName {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// printfmt := fmt.Sprintf("%s: %s >> %s", r.Method, r.Subdomain+r.Tmpl().Src, r.MainHandlerName)
|
// trim the path for Iris' internal middlewares, e.g.
|
||||||
// if l := len(r.Handlers); l > 0 {
|
// irs/mvc.GRPC.Apply.func1
|
||||||
// printfmt += fmt.Sprintf(" and %d more", l)
|
if internalName := "github.com/kataras/iris/v12"; strings.HasPrefix(name, internalName) {
|
||||||
// }
|
name = strings.Replace(name, internalName, "iris", 1)
|
||||||
return printfmt // without new line.
|
}
|
||||||
|
|
||||||
|
file, line := context.HandlerFileLineRel(h, wd)
|
||||||
|
if file == r.RegisterFileName && line == r.RegisterLineNumber {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// * @handler_name (@handler_rel_location)
|
||||||
|
s += fmt.Sprintf("\n ⬝ %s (%s:%d)", name, file, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
type routeReadOnlyWrapper struct {
|
type routeReadOnlyWrapper struct {
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -21,7 +21,8 @@ require (
|
||||||
github.com/iris-contrib/pongo2 v0.0.1
|
github.com/iris-contrib/pongo2 v0.0.1
|
||||||
github.com/iris-contrib/schema v0.0.1
|
github.com/iris-contrib/schema v0.0.1
|
||||||
github.com/json-iterator/go v1.1.9
|
github.com/json-iterator/go v1.1.9
|
||||||
github.com/kataras/golog v0.0.10
|
github.com/kataras/golog v0.0.11
|
||||||
|
github.com/kataras/pio v0.0.3
|
||||||
github.com/kataras/neffos v0.0.14
|
github.com/kataras/neffos v0.0.14
|
||||||
github.com/kataras/sitemap v0.0.5
|
github.com/kataras/sitemap v0.0.5
|
||||||
github.com/klauspost/compress v1.9.7
|
github.com/klauspost/compress v1.9.7
|
||||||
|
|
12
iris.go
12
iris.go
|
@ -641,7 +641,7 @@ func (app *Application) NewHost(srv *http.Server) *host.Supervisor {
|
||||||
srv.Addr = addr
|
srv.Addr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
app.logger.Debugf("Host: addr is %s", srv.Addr)
|
// app.logger.Debugf("Host: addr is %s", srv.Addr)
|
||||||
|
|
||||||
// create the new host supervisor
|
// create the new host supervisor
|
||||||
// bind the constructed server and return it
|
// bind the constructed server and return it
|
||||||
|
@ -657,21 +657,21 @@ func (app *Application) NewHost(srv *http.Server) *host.Supervisor {
|
||||||
app.config.vhost = netutil.ResolveVHost(srv.Addr)
|
app.config.vhost = netutil.ResolveVHost(srv.Addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.logger.Debugf("Host: virtual host is %s", app.config.vhost)
|
// app.logger.Debugf("Host: virtual host is %s", app.config.vhost)
|
||||||
|
|
||||||
// the below schedules some tasks that will run among the server
|
// the below schedules some tasks that will run among the server
|
||||||
|
|
||||||
if !app.config.DisableStartupLog {
|
if !app.config.DisableStartupLog {
|
||||||
// show the available info to exit from app.
|
// show the available info to exit from app.
|
||||||
su.RegisterOnServe(host.WriteStartupLogOnServe(app.logger.Printer.Output)) // app.logger.Writer -> Info
|
su.RegisterOnServe(host.WriteStartupLogOnServe(app.logger.Printer.Output)) // app.logger.Writer -> Info
|
||||||
app.logger.Debugf("Host: register startup notifier")
|
// app.logger.Debugf("Host: register startup notifier")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !app.config.DisableInterruptHandler {
|
if !app.config.DisableInterruptHandler {
|
||||||
// when CTRL+C/CMD+C pressed.
|
// when CTRL+C/CMD+C pressed.
|
||||||
shutdownTimeout := 5 * time.Second
|
shutdownTimeout := 5 * time.Second
|
||||||
host.RegisterOnInterrupt(host.ShutdownOnInterrupt(su, shutdownTimeout))
|
host.RegisterOnInterrupt(host.ShutdownOnInterrupt(su, shutdownTimeout))
|
||||||
app.logger.Debugf("Host: register server shutdown on interrupt(CTRL+C/CMD+C)")
|
// app.logger.Debugf("Host: register server shutdown on interrupt(CTRL+C/CMD+C)")
|
||||||
}
|
}
|
||||||
|
|
||||||
su.IgnoredErrors = append(su.IgnoredErrors, app.config.IgnoreServerErrors...)
|
su.IgnoredErrors = append(su.IgnoredErrors, app.config.IgnoreServerErrors...)
|
||||||
|
@ -1017,7 +1017,9 @@ func (app *Application) Run(serve Runner, withOrWithout ...Configurator) error {
|
||||||
app.Configure(withOrWithout...)
|
app.Configure(withOrWithout...)
|
||||||
app.tryStartTunneling()
|
app.tryStartTunneling()
|
||||||
|
|
||||||
app.logger.Debugf("Application: running using %d host(s)", len(app.Hosts)+1)
|
if len(app.Hosts) > 0 {
|
||||||
|
app.logger.Debugf("Application: running using %d host(s)", len(app.Hosts)+1 /* +1 the current */)
|
||||||
|
}
|
||||||
|
|
||||||
// this will block until an error(unless supervisor's DeferFlow called from a Task).
|
// this will block until an error(unless supervisor's DeferFlow called from a Task).
|
||||||
err := serve(app)
|
err := serve(app)
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (g GRPC) Apply(c *ControllerActivator) {
|
||||||
if route := c.Handle(http.MethodPost, path, m.Name, pre); route != nil {
|
if route := c.Handle(http.MethodPost, path, m.Name, pre); route != nil {
|
||||||
route.Description = "gRPC"
|
route.Description = "gRPC"
|
||||||
if g.Strict {
|
if g.Strict {
|
||||||
route.Description = "-only"
|
route.Description += "-only"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user