From 4dec17afdff48e8018c83618fbbe69fceeb2b41d Mon Sep 17 00:00:00 2001 From: ljz <641390597@qq.com> Date: Sun, 5 Oct 2025 11:23:57 +0800 Subject: [PATCH] feat(logger): color latency (#4146) Co-authored-by: lizhao --- logger.go | 38 +++++++++++++++++++++++++++++++++----- logger_test.go | 25 +++++++++++++++++++++---- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/logger.go b/logger.go index 47827787..6441f7ea 100644 --- a/logger.go +++ b/logger.go @@ -103,6 +103,27 @@ func (p *LogFormatterParams) StatusCodeColor() string { } } +// LatencyColor is the ANSI color for latency +func (p *LogFormatterParams) LatencyColor() string { + latency := p.Latency + switch { + case latency < time.Millisecond*100: + return white + case latency < time.Millisecond*200: + return green + case latency < time.Millisecond*300: + return cyan + case latency < time.Millisecond*500: + return blue + case latency < time.Second: + return yellow + case latency < time.Second*2: + return magenta + default: + return red + } +} + // MethodColor is the ANSI color for appropriately logging http method to a terminal. func (p *LogFormatterParams) MethodColor() string { method := p.Method @@ -139,20 +160,27 @@ func (p *LogFormatterParams) IsOutputColor() bool { // defaultLogFormatter is the default log format function Logger middleware uses. var defaultLogFormatter = func(param LogFormatterParams) string { - var statusColor, methodColor, resetColor string + var statusColor, methodColor, resetColor, latencyColor string if param.IsOutputColor() { statusColor = param.StatusCodeColor() methodColor = param.MethodColor() resetColor = param.ResetColor() + latencyColor = param.LatencyColor() } - if param.Latency > time.Minute { - param.Latency = param.Latency.Truncate(time.Second) + switch { + case param.Latency > time.Minute: + param.Latency = param.Latency.Truncate(time.Second * 10) + case param.Latency > time.Second: + param.Latency = param.Latency.Truncate(time.Millisecond * 10) + case param.Latency > time.Millisecond: + param.Latency = param.Latency.Truncate(time.Microsecond * 10) } - return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s", + + return fmt.Sprintf("[GIN] %v |%s %3d %s|%s %8v %s| %15s |%s %-7s %s %#v\n%s", param.TimeStamp.Format("2006/01/02 - 15:04:05"), statusColor, param.StatusCode, resetColor, - param.Latency, + latencyColor, param.Latency, resetColor, param.ClientIP, methodColor, param.Method, resetColor, param.Path, diff --git a/logger_test.go b/logger_test.go index 8a542e97..335b0e31 100644 --- a/logger_test.go +++ b/logger_test.go @@ -277,11 +277,11 @@ func TestDefaultLogFormatter(t *testing.T) { isTerm: false, } - assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 | 200 | 5s | 20.20.20.20 | GET \"/\"\n", defaultLogFormatter(termFalseParam)) - assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 | 200 | 2743h29m3s | 20.20.20.20 | GET \"/\"\n", defaultLogFormatter(termFalseLongDurationParam)) + assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 | 200 | 5s | 20.20.20.20 | GET \"/\"\n", defaultLogFormatter(termFalseParam)) + assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 | 200 | 2743h29m0s | 20.20.20.20 | GET \"/\"\n", defaultLogFormatter(termFalseLongDurationParam)) - assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 5s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueParam)) - assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 2743h29m3s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueLongDurationParam)) + assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m|\x1b[97;41m 5s \x1b[0m| 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueParam)) + assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m|\x1b[97;41m 2743h29m0s \x1b[0m| 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueLongDurationParam)) } func TestColorForMethod(t *testing.T) { @@ -317,6 +317,23 @@ func TestColorForStatus(t *testing.T) { assert.Equal(t, red, colorForStatus(2), "other things should be red") } +func TestColorForLatency(t *testing.T) { + colorForLantency := func(latency time.Duration) string { + p := LogFormatterParams{ + Latency: latency, + } + return p.LatencyColor() + } + + assert.Equal(t, white, colorForLantency(time.Duration(0)), "0 should be white") + assert.Equal(t, white, colorForLantency(time.Millisecond*20), "20ms should be white") + assert.Equal(t, green, colorForLantency(time.Millisecond*150), "150ms should be green") + assert.Equal(t, cyan, colorForLantency(time.Millisecond*250), "250ms should be cyan") + assert.Equal(t, yellow, colorForLantency(time.Millisecond*600), "600ms should be yellow") + assert.Equal(t, magenta, colorForLantency(time.Millisecond*1500), "1.5s should be magenta") + assert.Equal(t, red, colorForLantency(time.Second*3), "other things should be red") +} + func TestResetColor(t *testing.T) { p := LogFormatterParams{} assert.Equal(t, string([]byte{27, 91, 48, 109}), p.ResetColor())