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"
)
// 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

View File

@ -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"))