summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/labstack/echo/middleware/logger.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/labstack/echo/middleware/logger.go')
-rw-r--r--vendor/github.com/labstack/echo/middleware/logger.go191
1 files changed, 191 insertions, 0 deletions
diff --git a/vendor/github.com/labstack/echo/middleware/logger.go b/vendor/github.com/labstack/echo/middleware/logger.go
new file mode 100644
index 00000000..e26b5496
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/logger.go
@@ -0,0 +1,191 @@
+package middleware
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/labstack/echo"
+ "github.com/labstack/gommon/color"
+ "github.com/valyala/fasttemplate"
+)
+
+type (
+ // LoggerConfig defines the config for Logger middleware.
+ LoggerConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Tags to constructed the logger format.
+ //
+ // - time_unix
+ // - time_unix_nano
+ // - time_rfc3339
+ // - time_rfc3339_nano
+ // - id (Request ID - Not implemented)
+ // - remote_ip
+ // - uri
+ // - host
+ // - method
+ // - path
+ // - referer
+ // - user_agent
+ // - status
+ // - latency (In nanoseconds)
+ // - latency_human (Human readable)
+ // - bytes_in (Bytes received)
+ // - bytes_out (Bytes sent)
+ // - header:<NAME>
+ // - query:<NAME>
+ // - form:<NAME>
+ //
+ // Example "${remote_ip} ${status}"
+ //
+ // Optional. Default value DefaultLoggerConfig.Format.
+ Format string `json:"format"`
+
+ // Output is a writer where logs in JSON format are written.
+ // Optional. Default value os.Stdout.
+ Output io.Writer
+
+ template *fasttemplate.Template
+ colorer *color.Color
+ pool *sync.Pool
+ }
+)
+
+var (
+ // DefaultLoggerConfig is the default Logger middleware config.
+ DefaultLoggerConfig = LoggerConfig{
+ Skipper: DefaultSkipper,
+ Format: `{"time":"${time_rfc3339_nano}","remote_ip":"${remote_ip}","host":"${host}",` +
+ `"method":"${method}","uri":"${uri}","status":${status}, "latency":${latency},` +
+ `"latency_human":"${latency_human}","bytes_in":${bytes_in},` +
+ `"bytes_out":${bytes_out}}` + "\n",
+ Output: os.Stdout,
+ colorer: color.New(),
+ }
+)
+
+// Logger returns a middleware that logs HTTP requests.
+func Logger() echo.MiddlewareFunc {
+ return LoggerWithConfig(DefaultLoggerConfig)
+}
+
+// LoggerWithConfig returns a Logger middleware with config.
+// See: `Logger()`.
+func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultLoggerConfig.Skipper
+ }
+ if config.Format == "" {
+ config.Format = DefaultLoggerConfig.Format
+ }
+ if config.Output == nil {
+ config.Output = DefaultLoggerConfig.Output
+ }
+
+ config.template = fasttemplate.New(config.Format, "${", "}")
+ config.colorer = color.New()
+ config.colorer.SetOutput(config.Output)
+ config.pool = &sync.Pool{
+ New: func() interface{} {
+ return bytes.NewBuffer(make([]byte, 256))
+ },
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) (err error) {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ res := c.Response()
+ start := time.Now()
+ if err = next(c); err != nil {
+ c.Error(err)
+ }
+ stop := time.Now()
+ buf := config.pool.Get().(*bytes.Buffer)
+ buf.Reset()
+ defer config.pool.Put(buf)
+
+ if _, err = config.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 "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 "referer":
+ return buf.WriteString(req.Referer())
+ case "user_agent":
+ return buf.WriteString(req.UserAgent())
+ case "status":
+ n := res.Status
+ s := config.colorer.Green(n)
+ switch {
+ case n >= 500:
+ s = config.colorer.Red(n)
+ case n >= 400:
+ s = config.colorer.Yellow(n)
+ case n >= 300:
+ s = config.colorer.Cyan(n)
+ }
+ return buf.WriteString(s)
+ 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:])))
+ }
+ }
+ return 0, nil
+ }); err != nil {
+ return
+ }
+
+ _, err = config.Output.Write(buf.Bytes())
+ return
+ }
+ }
+}