Former-commit-id: 12b75f1e54ebf3d7f78a09b8d5594859a344422d
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-04-30 16:16:43 +03:00
parent 3fbf15d576
commit c3543528cf
6 changed files with 105 additions and 55 deletions

View File

@ -48,5 +48,7 @@ func newApp() *iris.Application {
func main() {
app := newApp()
app.Logger().SetLevel("debug")
app.Listen(":8080")
}

View File

@ -84,7 +84,7 @@ func BenchmarkAPIBuilder(b *testing.B) {
paths := genPaths(routesLength, 15, 42)
api := NewAPIBuilder()
requestHandler := NewDefaultHandler(nil)
requestHandler := NewDefaultHandler(nil, nil)
b.ReportAllocs()
b.ResetTimer()

View File

@ -1,6 +1,7 @@
package router
import (
"fmt"
"net/http"
"sort"
"strings"
@ -11,6 +12,7 @@ import (
macroHandler "github.com/kataras/iris/v12/macro/handler"
"github.com/kataras/golog"
"github.com/kataras/pio"
)
// RequestHandler the middle man between acquiring a context and releasing it.
@ -25,13 +27,24 @@ type RequestHandler interface {
}
type routerHandler struct {
config context.ConfigurationReadOnly
logger *golog.Logger
trees []*trie
hosts bool // true if at least one route contains a Subdomain.
config context.ConfigurationReadOnly
}
var _ RequestHandler = &routerHandler{}
// NewDefaultHandler returns the handler which is responsible
// to map the request with a route (aka mux implementation).
func NewDefaultHandler(config context.ConfigurationReadOnly, logger *golog.Logger) RequestHandler {
return &routerHandler{
config: config,
logger: logger,
}
}
func (h *routerHandler) getTree(method, subdomain string) *trie {
for i := range h.trees {
t := h.trees[i]
@ -66,14 +79,6 @@ func (h *routerHandler) AddRoute(r *Route) error {
return nil
}
// NewDefaultHandler returns the handler which is responsible
// to map the request with a route (aka mux implementation).
func NewDefaultHandler(config context.ConfigurationReadOnly) RequestHandler {
return &routerHandler{
config: config,
}
}
// RoutesProvider should be implemented by
// iteral which contains the registered routes.
type RoutesProvider interface { // api builder
@ -155,13 +160,13 @@ func (h *routerHandler) Build(provider RoutesProvider) error {
}
}
if golog.Default.Level == golog.DebugLevel {
tr := "routes"
if logger := h.logger; logger != nil && logger.Level == golog.DebugLevel {
tr := "Routes"
if len(registeredRoutes) == 1 {
tr = tr[0 : len(tr)-1]
}
golog.Debugf("API: %d registered %s", len(registeredRoutes), tr)
// logger.Debugf("%s: %d", tr, len(registeredRoutes))
// group routes by method and print them without the [DBUG] and time info,
// the route logs are colorful.
@ -177,26 +182,59 @@ func (h *routerHandler) Build(provider RoutesProvider) error {
return
}
bckpTimeFormat := golog.Default.TimeFormat
defer golog.SetTimeFormat(bckpTimeFormat)
golog.SetTimeFormat("")
// bckpTimeFormat := logger.TimeFormat
// defer logger.SetTimeFormat(bckpTimeFormat)
// logger.SetTimeFormat("")
newLine := []byte("\n")
type methodCount struct {
method string
count int
}
for _, method := range append(AllMethods, MethodNone) {
allMethods := append(AllMethods, MethodNone)
routeMethodCounts := make([]methodCount, 0, len(allMethods))
for i, method := range allMethods {
methodRoutes := collect(method)
if len(methodRoutes) == 0 {
continue
}
routeMethodCounts = append(routeMethodCounts, methodCount{method, len(methodRoutes)})
for _, r := range methodRoutes {
r.Trace(golog.Default.Printer)
r.Trace(logger.Printer)
}
golog.Default.Printer.Write(newLine)
if i != len(allMethods)-1 {
logger.Printer.Write(pio.NewLine)
}
}
if n := len(routeMethodCounts); n > 0 {
tr := "routes"
if len(registeredRoutes) == 1 {
tr = tr[0 : len(tr)-1]
}
fmt.Fprintf(logger.Printer, "%s API: %d registered %s (", golog.GetTextForLevel(golog.DebugLevel, true), len(registeredRoutes), tr)
for i, mc := range routeMethodCounts {
// @method: @count
if i > 0 {
if i == n-1 {
fmt.Fprint(logger.Printer, " and ")
} else {
fmt.Fprint(logger.Printer, ", ")
}
}
fmt.Fprintf(logger.Printer, "%d ", mc.count)
pio.WriteRich(logger.Printer, mc.method, traceMethodColor(mc.method))
}
fmt.Fprint(logger.Printer, ")\n")
}
}
return errgroup.Check(rp)
}

View File

@ -349,7 +349,28 @@ func traceHandlerFile(method, name, line string, number int) string {
}
space := strings.Repeat(" ", len(method)+1)
return fmt.Sprintf("\n%s ⬝ %s %s", space, name, file)
return fmt.Sprintf("\n%s • %s %s", space, name, file)
}
var methodColors = map[string]int{
http.MethodGet: pio.Green,
http.MethodPost: pio.Magenta,
http.MethodPut: pio.Blue,
http.MethodDelete: pio.Red,
http.MethodConnect: pio.Green,
http.MethodHead: 23,
http.MethodPatch: pio.Blue,
http.MethodOptions: pio.Gray,
http.MethodTrace: pio.Yellow,
MethodNone: 203, // orange-red.
}
func traceMethodColor(method string) int {
if color, ok := methodColors[method]; ok {
return color
}
return pio.Black
}
// Trace prints some debug info about the Route to the "w".
@ -361,39 +382,18 @@ func traceHandlerFile(method, name, line string, number int) string {
// If route and handler line:number locations are equal then the second is ignored.
func (r *Route) Trace(w io.Writer) {
// 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 = 23
case http.MethodPatch:
color = pio.Blue
case http.MethodOptions:
color = pio.Gray
case http.MethodTrace:
color = pio.Yellow
case MethodNone:
color = 203 // orange-red.
}
color := traceMethodColor(r.Method)
// @method: @path
// space := strings.Repeat(" ", len(http.MethodConnect)-len(r.Method))
// s := fmt.Sprintf("%s: %s", pio.Rich(r.Method, color), path)
pio.WriteRich(w, r.Method, color)
path := r.Tmpl().Src
if path == "" {
path = "/"
}
// @method: @path
// space := strings.Repeat(" ", len(http.MethodConnect)-len(r.Method))
// s := fmt.Sprintf("%s: %s", pio.Rich(r.Method, color), path)
pio.WriteRich(w, r.Method, color)
fmt.Fprintf(w, ": %s", path)
// (@description)

View File

@ -248,6 +248,13 @@ func parsePath(m *Matcher, path string) int {
return -1
}
func reverseStrings(s []string) []string {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return s
}
func parseLanguage(path string) (language.Tag, bool) {
if idx := strings.LastIndexByte(path, '.'); idx > 0 {
path = path[0:idx]
@ -259,6 +266,8 @@ func parseLanguage(path string) (language.Tag, bool) {
return r == '_' || r == os.PathSeparator || r == '/' || r == '.'
})
names = reverseStrings(names) // see https://github.com/kataras/i18n/issues/1
for _, s := range names {
t, err := language.Parse(s)
if err != nil {
@ -303,7 +312,7 @@ func (i *I18n) Tr(lang, format string, args ...interface{}) string {
return msg
}
return fmt.Sprintf(format, args...)
return ""
}
const acceptLanguageHeaderKey = "Accept-Language"
@ -372,6 +381,7 @@ func (i *I18n) GetLocale(ctx context.Context) context.Locale {
}
// GetMessage returns the localized text message for this "r" request based on the key "format".
// It returns an empty string if locale or format not found.
func (i *I18n) GetMessage(ctx context.Context, format string, args ...interface{}) string {
loc := i.GetLocale(ctx)
if loc != nil {
@ -382,7 +392,7 @@ func (i *I18n) GetMessage(ctx context.Context, format string, args ...interface{
}
}
return fmt.Sprintf(format, args...)
return ""
}
// Wrapper returns a new router wrapper.

View File

@ -731,7 +731,7 @@ func (app *Application) Build() error {
if app.builded {
return nil
}
start := time.Now()
// start := time.Now()
app.builded = true // even if fails.
rp := errgroup.New("Application Builder")
@ -803,7 +803,7 @@ func (app *Application) Build() error {
}
// create the request handler, the default routing handler
routerHandler := router.NewDefaultHandler(app.config)
routerHandler := router.NewDefaultHandler(app.config, app.logger)
err := app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder, false)
if err != nil {
rp.Err(err)
@ -813,7 +813,7 @@ func (app *Application) Build() error {
}
// if end := time.Since(start); end.Seconds() > 5 {
app.logger.Debugf("Application: build took %s", time.Since(start))
// app.logger.Debugf("Application: build took %s", time.Since(start))
return errgroup.Check(rp)
}
@ -1172,7 +1172,7 @@ func (app *Application) tryStartTunneling() {
// to make subdomains resolution still based on this new remote, public addresses.
app.config.vhost = publicAddr[strings.Index(publicAddr, "://")+3:]
directLog := []byte(fmt.Sprintf(" Public Address: %s\n", publicAddr))
directLog := []byte(fmt.Sprintf(" Public Address: %s\n", publicAddr))
app.Logger().Printer.Output.Write(directLog)
}
})