Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨feature: print all routes message when server starts #1677

Merged
merged 6 commits into from Dec 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
74 changes: 74 additions & 0 deletions app.go
Expand Up @@ -20,10 +20,12 @@ import (
"os"
"reflect"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"sync/atomic"
"text/tabwriter"
"time"

"github.com/gofiber/fiber/v2/internal/colorable"
Expand Down Expand Up @@ -350,6 +352,10 @@ type Config struct {
// Default: []string
TrustedProxies []string `json:"trusted_proxies"`
trustedProxiesMap map[string]struct{}

//If set to true, will print all routes with their method, path and handler.
// Default: false
EnablePrintRoutes bool `json:"print_routes"`
}

// Static defines configuration options when defining static assets.
Expand Down Expand Up @@ -389,6 +395,14 @@ type Static struct {
Next func(c *Ctx) bool
}

// RouteMessage is some message need to be print when server starts
type RouteMessage struct {
name string
method string
path string
handlers string
}

// Default Config values
const (
DefaultBodyLimit = 4 * 1024 * 1024
Expand Down Expand Up @@ -713,6 +727,10 @@ func (app *App) Listener(ln net.Listener) error {
if !app.config.DisableStartupMessage {
app.startupMessage(ln.Addr().String(), getTlsConfig(ln) != nil, "")
}
// Print routes
if app.config.EnablePrintRoutes {
app.printRoutesMessage()
}
// Start listening
return app.server.Serve(ln)
}
Expand All @@ -737,6 +755,10 @@ func (app *App) Listen(addr string) error {
if !app.config.DisableStartupMessage {
app.startupMessage(ln.Addr().String(), false, "")
}
// Print routes
if app.config.EnablePrintRoutes {
app.printRoutesMessage()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget the Listener and ListenTLS method.

}
// Start listening
return app.server.Serve(ln)
}
Expand Down Expand Up @@ -777,6 +799,10 @@ func (app *App) ListenTLS(addr, certFile, keyFile string) error {
if !app.config.DisableStartupMessage {
app.startupMessage(ln.Addr().String(), true, "")
}
// Print routes
if app.config.EnablePrintRoutes {
app.printRoutesMessage()
}
// Start listening
return app.server.ServeTLS(ln, certFile, keyFile)
}
Expand Down Expand Up @@ -1198,3 +1224,51 @@ func (app *App) startupMessage(addr string, tls bool, pids string) {

_, _ = fmt.Fprintln(out, output)
}

// printRoutesMessage print all routes with method, path, name and handlers
// in a format of table, like this:
// method | path | name | handlers
// GET | / | routeName | github.com/gofiber/fiber/v2.emptyHandler
// HEAD | / | | github.com/gofiber/fiber/v2.emptyHandler
func (app *App) printRoutesMessage() {
// ignore child processes
if IsChild() {
return
}

const (
// cBlack = "\u001b[90m"
// cRed = "\u001b[91m"
cCyan = "\u001b[96m"
cGreen = "\u001b[92m"
cYellow = "\u001b[93m"
cBlue = "\u001b[94m"
// cMagenta = "\u001b[95m"
cWhite = "\u001b[97m"
// cReset = "\u001b[0m"
)
var routes []RouteMessage
for _, routeStack := range app.stack {
for _, route := range routeStack {
var newRoute = RouteMessage{}
newRoute.name = route.Name
newRoute.method = route.Method
newRoute.path = route.Path
for _, handler := range route.Handlers {
newRoute.handlers += runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name() + " "
}
routes = append(routes, newRoute)
}
}
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
// Sort routes by path
sort.Slice(routes, func(i, j int) bool {
return routes[i].path < routes[j].path
})
_, _ = fmt.Fprintf(w, "%smethod\t%s| %spath\t%s| %sname\t%s| %shandlers\n", cBlue, cWhite, cGreen, cWhite, cCyan, cWhite, cYellow)
_, _ = fmt.Fprintf(w, "%s------\t%s| %s----\t%s| %s----\t%s| %s--------\n", cBlue, cWhite, cGreen, cWhite, cCyan, cWhite, cYellow)
for _, route := range routes {
_, _ = fmt.Fprintf(w, "%s%s\t%s| %s%s\t%s| %s%s\t%s| %s%s\n", cBlue, route.method, cWhite, cGreen, route.path, cWhite, cCyan, route.name, cWhite, cYellow, route.handlers)
}
_ = w.Flush()
}
37 changes: 37 additions & 0 deletions app_test.go
Expand Up @@ -1576,3 +1576,40 @@ func Test_App_UseMountedErrorHandlerForBestPrefixMatch(t *testing.T) {
utils.AssertEqual(t, nil, err, "iotuil.ReadAll()")
utils.AssertEqual(t, "hi, i'm a custom sub sub fiber error", string(b), "Third fiber Response body")
}

func emptyHandler(c *Ctx) error {
return nil
}
func Test_App_print_Route(t *testing.T) {
app := New(Config{EnablePrintRoutes: true})
app.Get("/", emptyHandler).Name("routeName")
printRoutesMessage := captureOutput(func() {
app.printRoutesMessage()
})
fmt.Println(printRoutesMessage)
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "GET"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "/"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "emptyHandler"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "routeName"))
}

func Test_App_print_Route_with_group(t *testing.T) {
app := New(Config{EnablePrintRoutes: true})
app.Get("/", emptyHandler)
v1 := app.Group("v1")
v1.Get("/test", emptyHandler).Name("v1")
v1.Post("/test/fiber", emptyHandler)
v1.Put("/test/fiber/*", emptyHandler)
printRoutesMessage := captureOutput(func() {
app.printRoutesMessage()
})
fmt.Println(printRoutesMessage)
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "GET"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "/"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "emptyHandler"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "/v1/test"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "POST"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "/v1/test/fiber"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "PUT"))
utils.AssertEqual(t, true, strings.Contains(printRoutesMessage, "/v1/test/fiber/*"))
}
1 change: 1 addition & 0 deletions internal/colorable/colorable_appengine.go
@@ -1,3 +1,4 @@
//go:build appengine
// +build appengine

package colorable
Expand Down
4 changes: 2 additions & 2 deletions internal/colorable/colorable_others.go
@@ -1,5 +1,5 @@
// +build !windows
// +build !appengine
//go:build !windows && !appengine
// +build !windows,!appengine

package colorable

Expand Down
4 changes: 2 additions & 2 deletions internal/colorable/colorable_windows.go
@@ -1,5 +1,5 @@
// +build windows
// +build !appengine
//go:build windows && !appengine
// +build windows,!appengine

package colorable

Expand Down
1 change: 1 addition & 0 deletions internal/fasttemplate/unsafe.go
@@ -1,3 +1,4 @@
//go:build !appengine
// +build !appengine

package fasttemplate
Expand Down
1 change: 1 addition & 0 deletions internal/fasttemplate/unsafe_gae.go
@@ -1,3 +1,4 @@
//go:build appengine
// +build appengine

package fasttemplate
Expand Down
1 change: 1 addition & 0 deletions internal/fwd/writer_appengine.go
@@ -1,3 +1,4 @@
//go:build appengine
// +build appengine

package fwd
Expand Down
1 change: 1 addition & 0 deletions internal/fwd/writer_unsafe.go
@@ -1,3 +1,4 @@
//go:build !appengine
// +build !appengine

package fwd
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/com.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/com_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/error_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/error_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iconnectionpoint_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iconnectionpoint_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iconnectionpointcontainer_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iconnectionpointcontainer_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/idispatch_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/idispatch_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/ienumvariant_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/ienumvariant_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iinspectable_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iinspectable_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iprovideclassinfo_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iprovideclassinfo_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/itypeinfo_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/itypeinfo_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iunknown_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/iunknown_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/oleutil/connection.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package oleutil
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/oleutil/connection_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package oleutil
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/oleutil/connection_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package oleutil
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/oleutil/go-get.go
@@ -1,6 +1,7 @@
// This file is here so go get succeeds as without it errors with:
// no buildable Go source files in ...
//
//go:build !windows
// +build !windows

package oleutil
1 change: 1 addition & 0 deletions internal/go-ole/safearray_func.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/safearray_windows.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/safearrayslices.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/variables.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/variant_386.go
@@ -1,3 +1,4 @@
//go:build 386
// +build 386

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/variant_amd64.go
@@ -1,3 +1,4 @@
//go:build amd64
// +build amd64

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/variant_date_386.go
@@ -1,3 +1,4 @@
//go:build windows && 386
// +build windows,386

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/variant_date_amd64.go
@@ -1,3 +1,4 @@
//go:build windows && amd64
// +build windows,amd64

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/variant_ppc64le.go
@@ -1,3 +1,4 @@
//go:build ppc64le
// +build ppc64le

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/variant_s390x.go
@@ -1,3 +1,4 @@
//go:build s390x
// +build s390x

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/winrt.go
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/go-ole/winrt_doc.go
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows

package ole
Expand Down
1 change: 1 addition & 0 deletions internal/gopsutil/common/common_darwin.go
@@ -1,3 +1,4 @@
//go:build darwin
// +build darwin

package common
Expand Down
1 change: 1 addition & 0 deletions internal/gopsutil/common/common_freebsd.go
@@ -1,3 +1,4 @@
//go:build freebsd || openbsd
// +build freebsd openbsd

package common
Expand Down