v3: Change startup message (#2041)

* Add figlet text for Fiber startup message

* Fiber figlet text is added to beginning of the startup message.

Signed-off-by: Gökhan Özeloğlu <gokhan.ozeloglu@deliveryhero.com>

* Refactor startup message

* Table is removed. Logs are added.

* Test cases refactored.

Signed-off-by: Gökhan Özeloğlu <gokhan.ozeloglu@deliveryhero.com>

* Add colorful log messages

* Used custom color codes to make logs colorful.

* Added a new test case.

* Fixed broken test case after changes.

* Added some color codes as a variable.

* Handled Windows case with init() function. Color codes are set empty string.

Signed-off-by: Gökhan Özeloğlu <gokhan.ozeloglu@deliveryhero.com>

* Change color text logic

* Color codes are taken from config.

* Version is added to figlet text.

* Reordered "server started on" message.

* Test cases are refactored.

Signed-off-by: Gökhan Özeloğlu <gokhan.ozeloglu@deliveryhero.com>

* Add if condition for Windows

* OS checked in tests for Windows machines.

Signed-off-by: Gökhan Özeloğlu <gokhan.ozeloglu@deliveryhero.com>

* some improvements

* Fix startup message tests

Signed-off-by: Gökhan Özeloğlu <gokhan.ozeloglu@deliveryhero.com>

* colorize PIDs

Signed-off-by: Gökhan Özeloğlu <gokhan.ozeloglu@deliveryhero.com>
Co-authored-by: Muhammed Efe Çetin <efectn@protonmail.com>
pull/2130/head
Gökhan Özeloğlu 2022-09-15 10:53:07 +03:00 committed by GitHub
parent 281e2f0046
commit 1a7f7ed8a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 147 deletions

189
listen.go
View File

@ -24,6 +24,14 @@ import (
"github.com/mattn/go-isatty" "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. // ListenConfig is a struct to customize startup of Fiber.
// //
// TODO: Add timeout for graceful shutdown. // TODO: Add timeout for graceful shutdown.
@ -279,52 +287,6 @@ func (app *App) startupMessage(addr string, tls bool, pids string, cfg ListenCon
// Alias colors // Alias colors
colors := app.config.ColorScheme 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) host, port := parseAddr(addr)
if host == "" { if host == "" {
if cfg.ListenerNetwork == NetworkTCP6 { if cfg.ListenerNetwork == NetworkTCP6 {
@ -349,41 +311,39 @@ func (app *App) startupMessage(addr string, tls bool, pids string, cfg ListenCon
procs = "1" procs = "1"
} }
mainLogo := colors.Black + " ┌───────────────────────────────────────────────────┐\n" out := colorable.NewColorableStdout()
if app.config.AppName != "" { if os.Getenv("TERM") == "dumb" || os.Getenv("NO_COLOR") == "1" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) {
mainLogo += " │ " + centerValue(app.config.AppName, 49) + " │\n" 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" { if host == "0.0.0.0" {
mainLogo += _, _ = fmt.Fprintf(out,
" │ " + center(fmt.Sprintf("%s://127.0.0.1:%s", scheme, port), 49) + " │\n" + "%sINFO%s Server started on %s%s://127.0.0.1:%s%s (bound on host 0.0.0.0 and port %s)\n",
" │ " + center(fmt.Sprintf("(bound on host 0.0.0.0 and port %s)", port), 49) + " │\n" colors.Green, colors.Reset, colors.Blue, scheme, port, colors.Reset, port)
} else { } else {
mainLogo += _, _ = fmt.Fprintf(out,
" │ " + center(fmt.Sprintf("%s://%s:%s", scheme, host, port), 49) + " │\n" "%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( if app.config.AppName != "" {
" │ │\n"+ _, _ = fmt.Fprintf(out, "%sINFO%s Application name: %s%s%s\n", colors.Green, colors.Reset, colors.Blue, app.config.AppName, colors.Reset)
" │ Handlers %s Processes %s │\n"+ }
" │ Prefork .%s PID ....%s │\n"+ _, _ = fmt.Fprintf(out,
" └───────────────────────────────────────────────────┘"+ "%sINFO%s Total handlers count: %s%s%s\n",
colors.Reset, colors.Green, colors.Reset, colors.Blue, strconv.Itoa(int(app.handlersCount)), colors.Reset)
value(strconv.Itoa(int(app.handlersCount)), 14), value(procs, 12), if isPrefork == "Enabled" {
value(isPrefork, 14), value(strconv.Itoa(os.Getpid()), 14), _, _ = 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 { 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 // Turn the `pids` variable (in the form ",a,b,c,d,e,f,etc") into a slice of PIDs
var pidSlice []string var pidSlice []string
for _, v := range strings.Split(pids, ",") { 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 _, _ = fmt.Fprintf(out, "%sINFO%s Child PIDs: %s", colors.Green, colors.Reset, colors.Blue)
thisLine := "Child PIDs ... " totalPids := len(pidSlice)
var itemsOnThisLine []string rowTotalPidCount := 10
for i := 0; i < totalPids; i += rowTotalPidCount {
addLine := func() { start := i
lines = append(lines, end := i + rowTotalPidCount
fmt.Sprintf( if end > totalPids {
newLine, end = totalPids
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)
} }
} for n, pid := range pidSlice[start:end] {
_, _ = fmt.Fprintf(out, "%s", pid)
// Add left over items to their own line if n+1 != len(pidSlice[start:end]) {
if len(itemsOnThisLine) != 0 { _, _ = fmt.Fprintf(out, ", ")
addLine() }
} }
_, _ = fmt.Fprintf(out, "\n%s", colors.Reset)
// 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, "")
} }
} }
// 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 // printRoutesMessage print all routes with method, path, name and handlers

View File

@ -349,12 +349,13 @@ func Test_Listen_Master_Process_Show_Startup_Message(t *testing.T) {
New(). New().
startupMessage(":3000", true, strings.Repeat(",11111,22222,33333,44444,55555,60000", 10), cfg) startupMessage(":3000", true, strings.Repeat(",11111,22222,33333,44444,55555,60000", 10), cfg)
}) })
colors := Colors{}
fmt.Println(startupMessage) fmt.Println(startupMessage)
require.True(t, strings.Contains(startupMessage, "https://127.0.0.1:3000")) 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, "(bound on host 0.0.0.0 and port 3000)"))
require.True(t, strings.Contains(startupMessage, "Child PIDs")) 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, "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 // 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)) 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 // go test -run Test_Listen_Print_Route
func Test_Listen_Print_Route(t *testing.T) { func Test_Listen_Print_Route(t *testing.T) {
app := New() app := New()
app.Get("/", emptyHandler).Name("routeName") app.Get("/", emptyHandler).Name("routeName")
printRoutesMessage := captureOutput(func() { printRoutesMessage := captureOutput(func() {
app.printRoutesMessage() app.printRoutesMessage()
}) })
fmt.Println(printRoutesMessage) fmt.Println(printRoutesMessage)
require.True(t, strings.Contains(printRoutesMessage, "GET")) require.True(t, strings.Contains(printRoutesMessage, "GET"))
require.True(t, strings.Contains(printRoutesMessage, "/")) require.True(t, strings.Contains(printRoutesMessage, "/"))
require.True(t, strings.Contains(printRoutesMessage, "emptyHandler")) require.True(t, strings.Contains(printRoutesMessage, "emptyHandler"))
@ -403,8 +436,6 @@ func Test_Listen_Print_Route_With_Group(t *testing.T) {
app.printRoutesMessage() app.printRoutesMessage()
}) })
fmt.Println(printRoutesMessage)
require.True(t, strings.Contains(printRoutesMessage, "GET")) require.True(t, strings.Contains(printRoutesMessage, "GET"))
require.True(t, strings.Contains(printRoutesMessage, "/")) require.True(t, strings.Contains(printRoutesMessage, "/"))
require.True(t, strings.Contains(printRoutesMessage, "emptyHandler")) require.True(t, strings.Contains(printRoutesMessage, "emptyHandler"))