diff --git a/codebase/app/rest_server/middleware.go b/codebase/app/rest_server/middleware.go index 82ec9b0b..01562368 100644 --- a/codebase/app/rest_server/middleware.go +++ b/codebase/app/rest_server/middleware.go @@ -18,12 +18,10 @@ import ( "github.com/golangid/candi/tracer" "github.com/golangid/candi/wrapper" "github.com/labstack/echo" - "github.com/labstack/gommon/color" - "github.com/valyala/fasttemplate" ) -// echoRestTracerMiddleware for wrap from http inbound (request from client) -func (h *restServer) echoRestTracerMiddleware(next echo.HandlerFunc) echo.HandlerFunc { +// tracerMiddleware for wrap from http inbound (request from client) +func (h *restServer) tracerMiddleware(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { req := c.Request() @@ -47,6 +45,11 @@ func (h *restServer) echoRestTracerMiddleware(next echo.HandlerFunc) echo.Handle logger.LogGreen("rest_api > trace_url: " + tracer.GetTraceURL(ctx)) }() + httpDump, _ := httputil.DumpRequest(req, false) + trace.SetTag("http.url_path", req.URL.Path) + trace.SetTag("http.method", req.Method) + trace.Log("http.request", httpDump) + body, _ := io.ReadAll(req.Body) if len(body) < h.opt.jaegerMaxPacketSize { // limit request body size to 65000 bytes (if higher tracer cannot show root span) trace.Log("request.body", body) @@ -55,11 +58,6 @@ func (h *restServer) echoRestTracerMiddleware(next echo.HandlerFunc) echo.Handle } req.Body = io.NopCloser(bytes.NewBuffer(body)) // reuse body - httpDump, _ := httputil.DumpRequest(req, false) - trace.SetTag("http.request", string(httpDump)) - trace.SetTag("http.url_path", req.URL.Path) - trace.SetTag("http.method", req.Method) - resBody := new(bytes.Buffer) mw := io.MultiWriter(c.Response().Writer, resBody) c.Response().Writer = wrapper.NewWrapHTTPResponseWriter(mw, c.Response().Writer) @@ -81,7 +79,8 @@ func (h *restServer) echoRestTracerMiddleware(next echo.HandlerFunc) echo.Handle } } -func defaultCORS() echo.MiddlewareFunc { +// EchoDefaultCORSMiddleware middleware +func EchoDefaultCORSMiddleware() echo.MiddlewareFunc { allowMethods := strings.Join(env.BaseEnv().CORSAllowMethods, ",") allowHeaders := strings.Join(env.BaseEnv().CORSAllowHeaders, ",") exposeHeaders := "" @@ -135,14 +134,8 @@ func defaultCORS() echo.MiddlewareFunc { } } -func echoLogger() echo.MiddlewareFunc { - format := `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}",` + - `"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` + - `"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` + - `,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n" - template := fasttemplate.New(format, "${", "}") - colorer := color.New() - colorer.SetOutput(os.Stdout) +// EchoLoggerMiddleware middleware +func EchoLoggerMiddleware() echo.MiddlewareFunc { bPool := &sync.Pool{ New: func() interface{} { return bytes.NewBuffer(make([]byte, 256)) @@ -163,92 +156,67 @@ func echoLogger() echo.MiddlewareFunc { buf.Reset() defer bPool.Put(buf) - if _, err = template.ExecuteFunc(buf, func(w io.Writer, tag string) (int, error) { - switch tag { - case "time_unix": - return buf.WriteString(strconv.FormatInt(time.Now().Unix(), 10)) - case "time_unix_nano": - return buf.WriteString(strconv.FormatInt(time.Now().UnixNano(), 10)) - case "time_rfc3339": - return buf.WriteString(time.Now().Format(time.RFC3339)) - case "time_rfc3339_nano": - return buf.WriteString(time.Now().Format(time.RFC3339Nano)) - case "time_custom": - return buf.WriteString(time.Now().Format(candihelper.TimeFormatLogger)) - case "id": - id := req.Header.Get(echo.HeaderXRequestID) - if id == "" { - id = res.Header().Get(echo.HeaderXRequestID) - } - return buf.WriteString(id) - case "remote_ip": - return buf.WriteString(c.RealIP()) - case "host": - return buf.WriteString(req.Host) - case "uri": - return buf.WriteString(req.RequestURI) - case "method": - return buf.WriteString(req.Method) - case "path": - p := req.URL.Path - if p == "" { - p = "/" - } - return buf.WriteString(p) - case "protocol": - return buf.WriteString(req.Proto) - case "referer": - return buf.WriteString(req.Referer()) - case "user_agent": - return buf.WriteString(req.UserAgent()) - case "status": - n := res.Status - s := colorer.Green(n) - switch { - case n >= 500: - s = colorer.Red(n) - case n >= 400: - s = colorer.Yellow(n) - case n >= 300: - s = colorer.Cyan(n) - } - return buf.WriteString(s) - case "error": - if err != nil { - return buf.WriteString(err.Error()) - } - case "latency": - l := stop.Sub(start) - return buf.WriteString(strconv.FormatInt(int64(l), 10)) - case "latency_human": - return buf.WriteString(stop.Sub(start).String()) - case "bytes_in": - cl := req.Header.Get(echo.HeaderContentLength) - if cl == "" { - cl = "0" - } - return buf.WriteString(cl) - case "bytes_out": - return buf.WriteString(strconv.FormatInt(res.Size, 10)) - default: - switch { - case strings.HasPrefix(tag, "header:"): - return buf.Write([]byte(c.Request().Header.Get(tag[7:]))) - case strings.HasPrefix(tag, "query:"): - return buf.Write([]byte(c.QueryParam(tag[6:]))) - case strings.HasPrefix(tag, "form:"): - return buf.Write([]byte(c.FormValue(tag[5:]))) - case strings.HasPrefix(tag, "cookie:"): - cookie, err := c.Cookie(tag[7:]) - if err == nil { - return buf.Write([]byte(cookie.Value)) - } - } - } - return 0, nil - }); err != nil { - return + buf.WriteString(`{"time":"`) + buf.WriteString(time.Now().Format(time.RFC3339Nano)) + + buf.WriteString(`","id":"`) + id := req.Header.Get(echo.HeaderXRequestID) + if id == "" { + id = res.Header().Get(echo.HeaderXRequestID) } + buf.WriteString(id) + + buf.WriteString(`","remote_ip":"`) + buf.WriteString(c.RealIP()) + + buf.WriteString(`","host":"`) + buf.WriteString(req.Host) + + buf.WriteString(`","method":"`) + buf.WriteString(req.Method) + + buf.WriteString(`","uri":"`) + buf.WriteString(req.RequestURI) + + buf.WriteString(`","user_agent":"`) + buf.WriteString(req.UserAgent()) + + buf.WriteString(`","status":`) + n := res.Status + s := logger.GreenColor(n) + switch { + case n >= 500: + s = logger.RedColor(n) + case n >= 400: + s = logger.YellowColor(n) + case n >= 300: + s = logger.CyanColor(n) + } + buf.WriteString(s) + + buf.WriteString(`,"error":"`) + if err != nil { + buf.WriteString(err.Error()) + } + + buf.WriteString(`","latency":`) + l := stop.Sub(start) + buf.WriteString(strconv.FormatInt(int64(l), 10)) + + buf.WriteString(`,"latency_human":"`) + buf.WriteString(stop.Sub(start).String()) + + buf.WriteString(`","bytes_in":`) + cl := req.Header.Get(echo.HeaderContentLength) + if cl == "" { + cl = "0" + } + buf.WriteString(cl) + + buf.WriteString(`,"bytes_out":`) + buf.WriteString(strconv.FormatInt(res.Size, 10)) + + buf.WriteString("}\n") _, err = os.Stdout.Write(buf.Bytes()) return diff --git a/codebase/app/rest_server/option.go b/codebase/app/rest_server/option.go index 58496809..ccf5c890 100644 --- a/codebase/app/rest_server/option.go +++ b/codebase/app/rest_server/option.go @@ -34,7 +34,7 @@ func getDefaultOption() option { httpPort: ":8000", rootPath: "", debugMode: true, - rootMiddlewares: []echo.MiddlewareFunc{defaultCORS()}, + rootMiddlewares: []echo.MiddlewareFunc{EchoDefaultCORSMiddleware()}, rootHandler: http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { rw.Write([]byte("REST Server up and running")) }), diff --git a/codebase/app/rest_server/rest_server.go b/codebase/app/rest_server/rest_server.go index d163a556..f7de5103 100644 --- a/codebase/app/rest_server/rest_server.go +++ b/codebase/app/rest_server/rest_server.go @@ -55,9 +55,9 @@ func NewServer(service factory.ServiceFactory, opts ...OptionFunc) factory.AppSe echo.WrapMiddleware(service.GetDependency().GetMiddleware().HTTPBasicAuth), ) - restRootPath := server.serverEngine.Group(server.opt.rootPath, server.echoRestTracerMiddleware) + restRootPath := server.serverEngine.Group(server.opt.rootPath, server.tracerMiddleware) if server.opt.debugMode { - restRootPath.Use(echoLogger()) + restRootPath.Use(EchoLoggerMiddleware()) } for _, m := range service.GetModules() { if h := m.RESTHandler(); h != nil { diff --git a/logger/logger.go b/logger/logger.go index db90ace9..71314adf 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -27,20 +27,40 @@ func LogWithDefer(str string) (deferFunc func()) { // LogYellow log with yellow color func LogYellow(str string) { if env.BaseEnv().DebugMode { - fmt.Printf("\x1b[33;5m%s\x1b[0m\n", str) + fmt.Printf("%s\n", YellowColor(str)) } } // LogRed log with red color func LogRed(str string) { if env.BaseEnv().DebugMode { - fmt.Printf("\x1b[31;5m%s\x1b[0m\n", str) + fmt.Printf("%s\n", RedColor(str)) } } // LogGreen log with green color func LogGreen(str string) { if env.BaseEnv().DebugMode { - fmt.Printf("\x1b[32;5m%s\x1b[0m\n", str) + fmt.Printf("%s\n", GreenColor(str)) } } + +// RedColor func +func RedColor(str interface{}) string { + return fmt.Sprintf("\x1b[31;5m%v\x1b[0m", str) +} + +// GreenColor func +func GreenColor(str interface{}) string { + return fmt.Sprintf("\x1b[32;5m%v\x1b[0m", str) +} + +// YellowColor func +func YellowColor(str interface{}) string { + return fmt.Sprintf("\x1b[33;5m%v\x1b[0m", str) +} + +// CyanColor func +func CyanColor(str interface{}) string { + return fmt.Sprintf("\x1b[36;5m%v\x1b[0m", str) +}