diff --git a/listen.go b/listen.go index d3ab216a..1ecaa873 100644 --- a/listen.go +++ b/listen.go @@ -24,6 +24,14 @@ import ( "github.com/mattn/go-isatty" ) +// Figlet text to show Fiber ASCII art on startup message +var figletFiberText = ` + _______ __ + / ____(_) /_ ___ _____ + / /_ / / __ \/ _ \/ ___/ + / __/ / / /_/ / __/ / +/_/ /_/_.___/\___/_/ %s` + // ListenConfig is a struct to customize startup of Fiber. // // TODO: Add timeout for graceful shutdown. @@ -279,52 +287,6 @@ func (app *App) startupMessage(addr string, tls bool, pids string, cfg ListenCon // Alias colors colors := app.config.ColorScheme - value := func(s string, width int) string { - pad := width - len(s) - str := "" - for i := 0; i < pad; i++ { - str += "." - } - if s == "Disabled" { - str += " " + s - } else { - str += fmt.Sprintf(" %s%s%s", colors.Cyan, s, colors.Black) - } - return str - } - - center := func(s string, width int) string { - pad := strconv.Itoa((width - len(s)) / 2) - str := fmt.Sprintf("%"+pad+"s", " ") - str += s - str += fmt.Sprintf("%"+pad+"s", " ") - if len(str) < width { - str += " " - } - return str - } - - centerValue := func(s string, width int) string { - pad := strconv.Itoa((width - len([]rune(s))) / 2) - str := fmt.Sprintf("%"+pad+"s", " ") - str += fmt.Sprintf("%s%s%s", colors.Cyan, s, colors.Black) - str += fmt.Sprintf("%"+pad+"s", " ") - if len([]rune(s))-10 < width && len([]rune(s))%2 == 0 { - // add an ending space if the length of str is even and str is not too long - str += " " - } - return str - } - - pad := func(s string, width int) (str string) { - toAdd := width - len(s) - str += s - for i := 0; i < toAdd; i++ { - str += " " - } - return - } - host, port := parseAddr(addr) if host == "" { if cfg.ListenerNetwork == NetworkTCP6 { @@ -349,41 +311,39 @@ func (app *App) startupMessage(addr string, tls bool, pids string, cfg ListenCon procs = "1" } - mainLogo := colors.Black + " ┌───────────────────────────────────────────────────┐\n" - if app.config.AppName != "" { - mainLogo += " │ " + centerValue(app.config.AppName, 49) + " │\n" + out := colorable.NewColorableStdout() + if os.Getenv("TERM") == "dumb" || os.Getenv("NO_COLOR") == "1" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) { + out = colorable.NewNonColorable(os.Stdout) } - mainLogo += " │ " + centerValue("Fiber v"+Version, 49) + " │\n" + + _, _ = fmt.Fprintf(out, "%s\n", fmt.Sprintf(figletFiberText, colors.Red+"v"+Version+colors.Reset)) + _, _ = fmt.Fprintf(out, strings.Repeat("-", 50)+"\n") if host == "0.0.0.0" { - mainLogo += - " │ " + center(fmt.Sprintf("%s://127.0.0.1:%s", scheme, port), 49) + " │\n" + - " │ " + center(fmt.Sprintf("(bound on host 0.0.0.0 and port %s)", port), 49) + " │\n" + _, _ = fmt.Fprintf(out, + "%sINFO%s Server started on %s%s://127.0.0.1:%s%s (bound on host 0.0.0.0 and port %s)\n", + colors.Green, colors.Reset, colors.Blue, scheme, port, colors.Reset, port) } else { - mainLogo += - " │ " + center(fmt.Sprintf("%s://%s:%s", scheme, host, port), 49) + " │\n" + _, _ = fmt.Fprintf(out, + "%sINFO%s Server started on %s%s%s\n", + colors.Green, colors.Reset, colors.Blue, fmt.Sprintf("%s://%s:%s", scheme, host, port), colors.Reset) } - mainLogo += fmt.Sprintf( - " │ │\n"+ - " │ Handlers %s Processes %s │\n"+ - " │ Prefork .%s PID ....%s │\n"+ - " └───────────────────────────────────────────────────┘"+ - colors.Reset, - value(strconv.Itoa(int(app.handlersCount)), 14), value(procs, 12), - value(isPrefork, 14), value(strconv.Itoa(os.Getpid()), 14), - ) + if app.config.AppName != "" { + _, _ = fmt.Fprintf(out, "%sINFO%s Application name: %s%s%s\n", colors.Green, colors.Reset, colors.Blue, app.config.AppName, colors.Reset) + } + _, _ = fmt.Fprintf(out, + "%sINFO%s Total handlers count: %s%s%s\n", + colors.Green, colors.Reset, colors.Blue, strconv.Itoa(int(app.handlersCount)), colors.Reset) + if isPrefork == "Enabled" { + _, _ = fmt.Fprintf(out, "%sINFO%s Prefork: %s%s%s\n", colors.Green, colors.Reset, colors.Blue, isPrefork, colors.Reset) + } else { + _, _ = fmt.Fprintf(out, "%sINFO%s Prefork: %s%s%s\n", colors.Green, colors.Reset, colors.Red, isPrefork, colors.Reset) + } + _, _ = fmt.Fprintf(out, "%sINFO%s PID: %s%v%s\n", colors.Green, colors.Reset, colors.Blue, os.Getpid(), colors.Reset) + _, _ = fmt.Fprintf(out, "%sINFO%s Total process count: %s%s%s\n", colors.Green, colors.Reset, colors.Blue, procs, colors.Reset) - var childPidsLogo string if cfg.EnablePrefork { - var childPidsTemplate string - childPidsTemplate += "%s" - childPidsTemplate += " ┌───────────────────────────────────────────────────┐\n%s" - childPidsTemplate += " └───────────────────────────────────────────────────┘" - childPidsTemplate += "%s" - - newLine := " │ %s%s%s │" - // Turn the `pids` variable (in the form ",a,b,c,d,e,f,etc") into a slice of PIDs var pidSlice []string for _, v := range strings.Split(pids, ",") { @@ -392,77 +352,24 @@ func (app *App) startupMessage(addr string, tls bool, pids string, cfg ListenCon } } - var lines []string - thisLine := "Child PIDs ... " - var itemsOnThisLine []string - - addLine := func() { - lines = append(lines, - fmt.Sprintf( - newLine, - colors.Black, - thisLine+colors.Cyan+pad(strings.Join(itemsOnThisLine, ", "), 49-len(thisLine)), - colors.Black, - ), - ) - } - - for _, pid := range pidSlice { - if len(thisLine+strings.Join(append(itemsOnThisLine, pid), ", ")) > 49 { - addLine() - thisLine = "" - itemsOnThisLine = []string{pid} - } else { - itemsOnThisLine = append(itemsOnThisLine, pid) + _, _ = fmt.Fprintf(out, "%sINFO%s Child PIDs: %s", colors.Green, colors.Reset, colors.Blue) + totalPids := len(pidSlice) + rowTotalPidCount := 10 + for i := 0; i < totalPids; i += rowTotalPidCount { + start := i + end := i + rowTotalPidCount + if end > totalPids { + end = totalPids } - } - - // Add left over items to their own line - if len(itemsOnThisLine) != 0 { - addLine() - } - - // Form logo - childPidsLogo = fmt.Sprintf(childPidsTemplate, - colors.Black, - strings.Join(lines, "\n")+"\n", - colors.Reset, - ) - } - - // Combine both the child PID logo and the main Fiber logo - - // Pad the shorter logo to the length of the longer one - splitMainLogo := strings.Split(mainLogo, "\n") - splitChildPidsLogo := strings.Split(childPidsLogo, "\n") - - mainLen := len(splitMainLogo) - childLen := len(splitChildPidsLogo) - - if mainLen > childLen { - diff := mainLen - childLen - for i := 0; i < diff; i++ { - splitChildPidsLogo = append(splitChildPidsLogo, "") - } - } else { - diff := childLen - mainLen - for i := 0; i < diff; i++ { - splitMainLogo = append(splitMainLogo, "") + for n, pid := range pidSlice[start:end] { + _, _ = fmt.Fprintf(out, "%s", pid) + if n+1 != len(pidSlice[start:end]) { + _, _ = fmt.Fprintf(out, ", ") + } + } + _, _ = fmt.Fprintf(out, "\n%s", colors.Reset) } } - - // Combine the two logos, line by line - output := "\n" - for i := range splitMainLogo { - output += colors.Black + splitMainLogo[i] + " " + splitChildPidsLogo[i] + "\n" - } - - out := colorable.NewColorableStdout() - if os.Getenv("TERM") == "dumb" || os.Getenv("NO_COLOR") == "1" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) { - out = colorable.NewNonColorable(os.Stdout) - } - - _, _ = fmt.Fprintln(out, output) } // printRoutesMessage print all routes with method, path, name and handlers diff --git a/listen_test.go b/listen_test.go index 09ddc096..de482e43 100644 --- a/listen_test.go +++ b/listen_test.go @@ -349,12 +349,13 @@ func Test_Listen_Master_Process_Show_Startup_Message(t *testing.T) { New(). startupMessage(":3000", true, strings.Repeat(",11111,22222,33333,44444,55555,60000", 10), cfg) }) + colors := Colors{} fmt.Println(startupMessage) require.True(t, strings.Contains(startupMessage, "https://127.0.0.1:3000")) require.True(t, strings.Contains(startupMessage, "(bound on host 0.0.0.0 and port 3000)")) require.True(t, strings.Contains(startupMessage, "Child PIDs")) require.True(t, strings.Contains(startupMessage, "11111, 22222, 33333, 44444, 55555, 60000")) - require.True(t, strings.Contains(startupMessage, "Prefork ........ Enabled")) + require.True(t, strings.Contains(startupMessage, fmt.Sprintf("Prefork: %sEnabled%s", colors.Blue, colors.Reset))) } // go test -run Test_Listen_Master_Process_Show_Startup_MessageWithAppName @@ -372,17 +373,49 @@ func Test_Listen_Master_Process_Show_Startup_MessageWithAppName(t *testing.T) { require.True(t, strings.Contains(startupMessage, app.Config().AppName)) } +// go test -run Test_Listen_Master_Process_Show_Startup_MessageWithAppNameNonAscii +func Test_Listen_Master_Process_Show_Startup_MessageWithAppNameNonAscii(t *testing.T) { + cfg := ListenConfig{ + EnablePrefork: true, + } + + appName := "Serveur de vérification des données" + app := New(Config{AppName: appName}) + + startupMessage := captureOutput(func() { + app.startupMessage(":3000", false, "", cfg) + }) + fmt.Println(startupMessage) + require.True(t, strings.Contains(startupMessage, "Serveur de vérification des données")) +} + +// go test -run Test_Listen_Master_Process_Show_Startup_MessageWithDisabledPreforkAndCustomEndpoint +func Test_Listen_Master_Process_Show_Startup_MessageWithDisabledPreforkAndCustomEndpoint(t *testing.T) { + cfg := ListenConfig{ + EnablePrefork: false, + } + + appName := "Fiber Example Application" + app := New(Config{AppName: appName}) + startupMessage := captureOutput(func() { + app.startupMessage("server.com:8081", true, strings.Repeat(",11111,22222,33333,44444,55555,60000", 5), cfg) + }) + colors := Colors{} + fmt.Println(startupMessage) + require.True(t, strings.Contains(startupMessage, fmt.Sprintf("%sINFO%s", colors.Green, colors.Reset))) + require.True(t, strings.Contains(startupMessage, fmt.Sprintf("%s%s%s", colors.Blue, appName, colors.Reset))) + require.True(t, strings.Contains(startupMessage, fmt.Sprintf("%s%s%s", colors.Blue, "https://server.com:8081", colors.Reset))) + require.True(t, strings.Contains(startupMessage, fmt.Sprintf("Prefork: %sDisabled%s", colors.Red, colors.Reset))) +} + // go test -run Test_Listen_Print_Route func Test_Listen_Print_Route(t *testing.T) { app := New() app.Get("/", emptyHandler).Name("routeName") - printRoutesMessage := captureOutput(func() { app.printRoutesMessage() }) - fmt.Println(printRoutesMessage) - require.True(t, strings.Contains(printRoutesMessage, "GET")) require.True(t, strings.Contains(printRoutesMessage, "/")) require.True(t, strings.Contains(printRoutesMessage, "emptyHandler")) @@ -403,8 +436,6 @@ func Test_Listen_Print_Route_With_Group(t *testing.T) { app.printRoutesMessage() }) - fmt.Println(printRoutesMessage) - require.True(t, strings.Contains(printRoutesMessage, "GET")) require.True(t, strings.Contains(printRoutesMessage, "/")) require.True(t, strings.Contains(printRoutesMessage, "emptyHandler"))