mirror of
https://github.com/zeromicro/go-zero.git
synced 2025-01-23 09:00:20 +08:00
feat: logx with color (#1872)
* feat: logx with color * chore: update logs * fix test error * chore: change colors of http codes * chore: add comments * chore: use faith/color instead of ascii code color * chore: update colors * chore: update colors * chore: fix duplicated slowcall text * chore: remove slowcall colors
This commit is contained in:
parent
5383e29ce6
commit
69c2bad410
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,6 +18,7 @@
|
|||||||
# for test purpose
|
# for test purpose
|
||||||
**/adhoc
|
**/adhoc
|
||||||
go.work
|
go.work
|
||||||
|
go.work.sum
|
||||||
|
|
||||||
# gitlab ci
|
# gitlab ci
|
||||||
.cache
|
.cache
|
||||||
|
73
core/color/color.go
Normal file
73
core/color/color.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package color
|
||||||
|
|
||||||
|
import "github.com/fatih/color"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NoColor is no color for both foreground and background.
|
||||||
|
NoColor Color = iota
|
||||||
|
// FgBlack is the foreground color black.
|
||||||
|
FgBlack
|
||||||
|
// FgRed is the foreground color red.
|
||||||
|
FgRed
|
||||||
|
// FgGreen is the foreground color green.
|
||||||
|
FgGreen
|
||||||
|
// FgYellow is the foreground color yellow.
|
||||||
|
FgYellow
|
||||||
|
// FgBlue is the foreground color blue.
|
||||||
|
FgBlue
|
||||||
|
// FgMagenta is the foreground color magenta.
|
||||||
|
FgMagenta
|
||||||
|
// FgCyan is the foreground color cyan.
|
||||||
|
FgCyan
|
||||||
|
// FgWhite is the foreground color white.
|
||||||
|
FgWhite
|
||||||
|
|
||||||
|
// BgBlack is the background color black.
|
||||||
|
BgBlack
|
||||||
|
// BgRed is the background color red.
|
||||||
|
BgRed
|
||||||
|
// BgGreen is the background color green.
|
||||||
|
BgGreen
|
||||||
|
// BgYellow is the background color yellow.
|
||||||
|
BgYellow
|
||||||
|
// BgBlue is the background color blue.
|
||||||
|
BgBlue
|
||||||
|
// BgMagenta is the background color magenta.
|
||||||
|
BgMagenta
|
||||||
|
// BgCyan is the background color cyan.
|
||||||
|
BgCyan
|
||||||
|
// BgWhite is the background color white.
|
||||||
|
BgWhite
|
||||||
|
)
|
||||||
|
|
||||||
|
var colors = map[Color][]color.Attribute{
|
||||||
|
FgBlack: {color.FgBlack, color.Bold},
|
||||||
|
FgRed: {color.FgRed, color.Bold},
|
||||||
|
FgGreen: {color.FgGreen, color.Bold},
|
||||||
|
FgYellow: {color.FgYellow, color.Bold},
|
||||||
|
FgBlue: {color.FgBlue, color.Bold},
|
||||||
|
FgMagenta: {color.FgMagenta, color.Bold},
|
||||||
|
FgCyan: {color.FgCyan, color.Bold},
|
||||||
|
FgWhite: {color.FgWhite, color.Bold},
|
||||||
|
BgBlack: {color.BgBlack, color.FgHiWhite, color.Bold},
|
||||||
|
BgRed: {color.BgRed, color.FgHiWhite, color.Bold},
|
||||||
|
BgGreen: {color.BgGreen, color.FgHiWhite, color.Bold},
|
||||||
|
BgYellow: {color.BgHiYellow, color.FgHiBlack, color.Bold},
|
||||||
|
BgBlue: {color.BgBlue, color.FgHiWhite, color.Bold},
|
||||||
|
BgMagenta: {color.BgMagenta, color.FgHiWhite, color.Bold},
|
||||||
|
BgCyan: {color.BgCyan, color.FgHiWhite, color.Bold},
|
||||||
|
BgWhite: {color.BgHiWhite, color.FgHiBlack, color.Bold},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Color uint32
|
||||||
|
|
||||||
|
// WithColor returns a string with the given color applied.
|
||||||
|
func WithColor(text string, colour Color) string {
|
||||||
|
c := color.New(colors[colour]...)
|
||||||
|
return c.Sprint(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithColorPadding returns a string with the given color applied with leading and trailing spaces.
|
||||||
|
func WithColorPadding(text string, colour Color) string {
|
||||||
|
return WithColor(" "+text+" ", colour)
|
||||||
|
}
|
17
core/color/color_test.go
Normal file
17
core/color/color_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWithColor(t *testing.T) {
|
||||||
|
output := WithColor("Hello", BgRed)
|
||||||
|
assert.Equal(t, "Hello", output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithColorPadding(t *testing.T) {
|
||||||
|
output := WithColorPadding("Hello", BgRed)
|
||||||
|
assert.Equal(t, " Hello ", output)
|
||||||
|
}
|
26
core/logx/color.go
Normal file
26
core/logx/color.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithColor is a helper function to add color to a string, only in plain encoding.
|
||||||
|
func WithColor(text string, colour color.Color) string {
|
||||||
|
if atomic.LoadUint32(&encoding) == plainEncodingType {
|
||||||
|
return color.WithColor(text, colour)
|
||||||
|
}
|
||||||
|
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithColorPadding is a helper function to add color to a string with leading and trailing spaces,
|
||||||
|
// only in plain encoding.
|
||||||
|
func WithColorPadding(text string, colour color.Color) string {
|
||||||
|
if atomic.LoadUint32(&encoding) == plainEncodingType {
|
||||||
|
return color.WithColorPadding(text, colour)
|
||||||
|
}
|
||||||
|
|
||||||
|
return text
|
||||||
|
}
|
33
core/logx/color_test.go
Normal file
33
core/logx/color_test.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/zeromicro/go-zero/core/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWithColor(t *testing.T) {
|
||||||
|
old := atomic.SwapUint32(&encoding, plainEncodingType)
|
||||||
|
defer atomic.StoreUint32(&encoding, old)
|
||||||
|
|
||||||
|
output := WithColor("hello", color.BgBlue)
|
||||||
|
assert.Equal(t, "hello", output)
|
||||||
|
|
||||||
|
atomic.StoreUint32(&encoding, jsonEncodingType)
|
||||||
|
output = WithColor("hello", color.BgBlue)
|
||||||
|
assert.Equal(t, "hello", output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithColorPadding(t *testing.T) {
|
||||||
|
old := atomic.SwapUint32(&encoding, plainEncodingType)
|
||||||
|
defer atomic.StoreUint32(&encoding, old)
|
||||||
|
|
||||||
|
output := WithColorPadding("hello", color.BgBlue)
|
||||||
|
assert.Equal(t, " hello ", output)
|
||||||
|
|
||||||
|
atomic.StoreUint32(&encoding, jsonEncodingType)
|
||||||
|
output = WithColorPadding("hello", color.BgBlue)
|
||||||
|
assert.Equal(t, "hello", output)
|
||||||
|
}
|
@ -223,13 +223,13 @@ func SetUp(c LogConf) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch c.Mode {
|
switch c.Mode {
|
||||||
case consoleMode:
|
case fileMode:
|
||||||
setupWithConsole()
|
return setupWithFiles(c)
|
||||||
return nil
|
|
||||||
case volumeMode:
|
case volumeMode:
|
||||||
return setupWithVolume(c)
|
return setupWithVolume(c)
|
||||||
default:
|
default:
|
||||||
return setupWithFiles(c)
|
setupWithConsole()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +210,12 @@ func (l *RotateLogger) maybeCompressFile(file string) {
|
|||||||
ErrorStack(r)
|
ErrorStack(r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
if _, err := os.Stat(file); err != nil {
|
||||||
|
// file not exists or other error, ignore compression
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
compressLogFile(file)
|
compressLogFile(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +298,7 @@ func compressLogFile(file string) {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
Infof("compressing log file: %s", file)
|
Infof("compressing log file: %s", file)
|
||||||
if err := gzipFile(file); err != nil {
|
if err := gzipFile(file); err != nil {
|
||||||
ErrorStackf("compress error: %s", err)
|
Errorf("compress error: %s", err)
|
||||||
} else {
|
} else {
|
||||||
Infof("compressed log file: %s, took %s", file, time.Since(start))
|
Infof("compressed log file: %s, took %s", file, time.Since(start))
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ const (
|
|||||||
statFilename = "stat.log"
|
statFilename = "stat.log"
|
||||||
|
|
||||||
consoleMode = "console"
|
consoleMode = "console"
|
||||||
|
fileMode = "file"
|
||||||
volumeMode = "volume"
|
volumeMode = "volume"
|
||||||
|
|
||||||
levelAlert = "alert"
|
levelAlert = "alert"
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -239,6 +241,7 @@ func output(writer io.Writer, level string, val interface{}, fields ...LogField)
|
|||||||
|
|
||||||
switch atomic.LoadUint32(&encoding) {
|
switch atomic.LoadUint32(&encoding) {
|
||||||
case plainEncodingType:
|
case plainEncodingType:
|
||||||
|
level = wrapLevelWithColor(level)
|
||||||
writePlainAny(writer, level, val, buildFields(fields...)...)
|
writePlainAny(writer, level, val, buildFields(fields...)...)
|
||||||
default:
|
default:
|
||||||
entry := make(logEntryWithFields)
|
entry := make(logEntryWithFields)
|
||||||
@ -252,6 +255,30 @@ func output(writer io.Writer, level string, val interface{}, fields ...LogField)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wrapLevelWithColor(level string) string {
|
||||||
|
var colour color.Color
|
||||||
|
switch level {
|
||||||
|
case levelAlert:
|
||||||
|
colour = color.FgRed
|
||||||
|
case levelError:
|
||||||
|
colour = color.FgRed
|
||||||
|
case levelFatal:
|
||||||
|
colour = color.FgRed
|
||||||
|
case levelInfo:
|
||||||
|
colour = color.FgBlue
|
||||||
|
case levelSlow:
|
||||||
|
colour = color.FgYellow
|
||||||
|
case levelStat:
|
||||||
|
colour = color.FgGreen
|
||||||
|
}
|
||||||
|
|
||||||
|
if colour == color.NoColor {
|
||||||
|
return level
|
||||||
|
}
|
||||||
|
|
||||||
|
return color.WithColorPadding(level, colour)
|
||||||
|
}
|
||||||
|
|
||||||
func writeJson(writer io.Writer, info interface{}) {
|
func writeJson(writer io.Writer, info interface{}) {
|
||||||
if content, err := json.Marshal(info); err != nil {
|
if content, err := json.Marshal(info); err != nil {
|
||||||
log.Println(err.Error())
|
log.Println(err.Error())
|
||||||
|
8
go.mod
8
go.mod
@ -6,6 +6,7 @@ require (
|
|||||||
github.com/ClickHouse/clickhouse-go v1.5.1
|
github.com/ClickHouse/clickhouse-go v1.5.1
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.0
|
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||||
github.com/alicebob/miniredis/v2 v2.17.0
|
github.com/alicebob/miniredis/v2 v2.17.0
|
||||||
|
github.com/fatih/color v1.10.0
|
||||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
|
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
|
||||||
github.com/go-redis/redis/v8 v8.11.4
|
github.com/go-redis/redis/v8 v8.11.4
|
||||||
github.com/go-sql-driver/mysql v1.6.0
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
@ -15,11 +16,11 @@ require (
|
|||||||
github.com/justinas/alice v1.2.0
|
github.com/justinas/alice v1.2.0
|
||||||
github.com/lib/pq v1.10.4
|
github.com/lib/pq v1.10.4
|
||||||
github.com/olekukonko/tablewriter v0.0.5
|
github.com/olekukonko/tablewriter v0.0.5
|
||||||
github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang v1.11.1
|
||||||
github.com/spaolacci/murmur3 v1.1.0
|
github.com/spaolacci/murmur3 v1.1.0
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
go.etcd.io/etcd/api/v3 v3.5.2
|
go.etcd.io/etcd/api/v3 v3.5.4
|
||||||
go.etcd.io/etcd/client/v3 v3.5.2
|
go.etcd.io/etcd/client/v3 v3.5.4
|
||||||
go.mongodb.org/mongo-driver v1.9.0
|
go.mongodb.org/mongo-driver v1.9.0
|
||||||
go.opentelemetry.io/otel v1.3.0
|
go.opentelemetry.io/otel v1.3.0
|
||||||
go.opentelemetry.io/otel/exporters/jaeger v1.3.0
|
go.opentelemetry.io/otel/exporters/jaeger v1.3.0
|
||||||
@ -42,7 +43,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.10.0 // indirect
|
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
15
go.sum
15
go.sum
@ -353,8 +353,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
|
||||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||||
|
github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
|
||||||
|
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
@ -418,12 +419,12 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
|||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg=
|
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg=
|
||||||
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
|
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.2 h1:tXok5yLlKyuQ/SXSjtqHc4uzNaMqZi2XsoSPr/LlJXI=
|
go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
|
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.2 h1:4hzqQ6hIb3blLyQ8usCU4h3NghkqcsohEQ3o3VetYxE=
|
go.etcd.io/etcd/client/pkg/v3 v3.5.4 h1:lrneYvz923dvC14R54XcA7FXoZ3mlGZAgmwhfm7HqOg=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||||
go.etcd.io/etcd/client/v3 v3.5.2 h1:WdnejrUtQC4nCxK0/dLTMqKOB+U5TP/2Ya0BJL+1otA=
|
go.etcd.io/etcd/client/v3 v3.5.4 h1:p83BUL3tAYS0OT/r0qglgc3M1JjhM0diV8DSWAhVXv4=
|
||||||
go.etcd.io/etcd/client/v3 v3.5.2/go.mod h1:kOOaWFFgHygyT0WlSmL8TJiXmMysO/nNUlEsSsN6W4o=
|
go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
|
||||||
go.mongodb.org/mongo-driver v1.9.0 h1:f3aLGJvQmBl8d9S40IL+jEyBC6hfLPbJjv9t5hEM9ck=
|
go.mongodb.org/mongo-driver v1.9.0 h1:f3aLGJvQmBl8d9S40IL+jEyBC6hfLPbJjv9t5hEM9ck=
|
||||||
go.mongodb.org/mongo-driver v1.9.0/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
|
go.mongodb.org/mongo-driver v1.9.0/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
@ -11,9 +11,11 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/color"
|
||||||
"github.com/zeromicro/go-zero/core/iox"
|
"github.com/zeromicro/go-zero/core/iox"
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
"github.com/zeromicro/go-zero/core/syncx"
|
"github.com/zeromicro/go-zero/core/syncx"
|
||||||
@ -157,15 +159,21 @@ func dumpRequest(r *http.Request) string {
|
|||||||
return string(reqContent)
|
return string(reqContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isOkResponse(code int) bool {
|
||||||
|
// not server error
|
||||||
|
return code < http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
|
||||||
func logBrief(r *http.Request, code int, timer *utils.ElapsedTimer, logs *internal.LogCollector) {
|
func logBrief(r *http.Request, code int, timer *utils.ElapsedTimer, logs *internal.LogCollector) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
duration := timer.Duration()
|
duration := timer.Duration()
|
||||||
logger := logx.WithContext(r.Context()).WithDuration(duration)
|
logger := logx.WithContext(r.Context()).WithDuration(duration)
|
||||||
buf.WriteString(fmt.Sprintf("[HTTP] %s - %d - %s - %s - %s",
|
buf.WriteString(fmt.Sprintf("[HTTP] %s - %s %s - %s - %s",
|
||||||
r.Method, code, r.RequestURI, httpx.GetRemoteAddr(r), r.UserAgent()))
|
wrapStatusCode(code), wrapMethod(r.Method), r.RequestURI, httpx.GetRemoteAddr(r), r.UserAgent()))
|
||||||
if duration > slowThreshold.Load() {
|
if duration > slowThreshold.Load() {
|
||||||
logger.Slowf("[HTTP] %s - %d - %s - %s - %s - slowcall(%s)",
|
logger.Slowf("[HTTP] %s - %s - %s %s - %s - slowcall(%s)",
|
||||||
r.Method, code, r.RequestURI, httpx.GetRemoteAddr(r), r.UserAgent(), timex.ReprOfDuration(duration))
|
wrapStatusCode(code), wrapMethod(r.Method), r.RequestURI, httpx.GetRemoteAddr(r), r.UserAgent(),
|
||||||
|
fmt.Sprintf("slowcall(%s)", timex.ReprOfDuration(duration)))
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := isOkResponse(code)
|
ok := isOkResponse(code)
|
||||||
@ -201,8 +209,8 @@ func logDetails(r *http.Request, response *detailLoggedResponseWriter, timer *ut
|
|||||||
buf.WriteString(fmt.Sprintf("[HTTP] %s - %d - %s - %s\n=> %s\n",
|
buf.WriteString(fmt.Sprintf("[HTTP] %s - %d - %s - %s\n=> %s\n",
|
||||||
r.Method, code, r.RemoteAddr, timex.ReprOfDuration(duration), dumpRequest(r)))
|
r.Method, code, r.RemoteAddr, timex.ReprOfDuration(duration), dumpRequest(r)))
|
||||||
if duration > defaultSlowThreshold {
|
if duration > defaultSlowThreshold {
|
||||||
logger.Slowf("[HTTP] %s - %d - %s - slowcall(%s)\n=> %s\n",
|
logger.Slowf("[HTTP] %s - %d - %s - slowcall(%s)\n=> %s\n", r.Method, code, r.RemoteAddr,
|
||||||
r.Method, code, r.RemoteAddr, timex.ReprOfDuration(duration), dumpRequest(r))
|
fmt.Sprintf("slowcall(%s)", timex.ReprOfDuration(duration)), dumpRequest(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
body := logs.Flush()
|
body := logs.Flush()
|
||||||
@ -222,7 +230,44 @@ func logDetails(r *http.Request, response *detailLoggedResponseWriter, timer *ut
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isOkResponse(code int) bool {
|
func wrapMethod(method string) string {
|
||||||
// not server error
|
var colour color.Color
|
||||||
return code < http.StatusInternalServerError
|
switch method {
|
||||||
|
case http.MethodGet:
|
||||||
|
colour = color.BgBlue
|
||||||
|
case http.MethodPost:
|
||||||
|
colour = color.BgCyan
|
||||||
|
case http.MethodPut:
|
||||||
|
colour = color.BgYellow
|
||||||
|
case http.MethodDelete:
|
||||||
|
colour = color.BgRed
|
||||||
|
case http.MethodPatch:
|
||||||
|
colour = color.BgGreen
|
||||||
|
case http.MethodHead:
|
||||||
|
colour = color.BgMagenta
|
||||||
|
case http.MethodOptions:
|
||||||
|
colour = color.BgWhite
|
||||||
|
}
|
||||||
|
|
||||||
|
if colour == color.NoColor {
|
||||||
|
return method
|
||||||
|
}
|
||||||
|
|
||||||
|
return logx.WithColorPadding(method, colour)
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapStatusCode(code int) string {
|
||||||
|
var colour color.Color
|
||||||
|
switch {
|
||||||
|
case code >= http.StatusOK && code < http.StatusMultipleChoices:
|
||||||
|
colour = color.BgGreen
|
||||||
|
case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
|
||||||
|
colour = color.BgBlue
|
||||||
|
case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
|
||||||
|
colour = color.BgMagenta
|
||||||
|
default:
|
||||||
|
colour = color.BgYellow
|
||||||
|
}
|
||||||
|
|
||||||
|
return logx.WithColorPadding(strconv.Itoa(code), colour)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
@ -11,11 +12,16 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/zeromicro/go-zero/core/conf"
|
"github.com/zeromicro/go-zero/core/conf"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
"github.com/zeromicro/go-zero/rest/router"
|
"github.com/zeromicro/go-zero/rest/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewServer(t *testing.T) {
|
func TestNewServer(t *testing.T) {
|
||||||
|
writer := logx.Reset()
|
||||||
|
defer logx.SetWriter(writer)
|
||||||
|
logx.SetWriter(logx.NewWriter(ioutil.Discard))
|
||||||
|
|
||||||
const configYaml = `
|
const configYaml = `
|
||||||
Name: foo
|
Name: foo
|
||||||
Port: 54321
|
Port: 54321
|
||||||
@ -31,7 +37,6 @@ Port: 54321
|
|||||||
{
|
{
|
||||||
c: RestConf{},
|
c: RestConf{},
|
||||||
opts: []RunOption{WithRouter(mockedRouter{}), WithCors()},
|
opts: []RunOption{WithRouter(mockedRouter{}), WithCors()},
|
||||||
fail: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: cnf,
|
c: cnf,
|
||||||
|
Loading…
Reference in New Issue
Block a user