85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
package middleware
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/go-logfmt/logfmt"
|
|
http "github.com/valyala/fasthttp"
|
|
)
|
|
|
|
type LogFmtConfig struct {
|
|
// Skipper defines a function to skip middleware.
|
|
Skipper Skipper
|
|
|
|
// TODO(toby3d): allow select some tags
|
|
|
|
// Output is a writer where logs in JSON format are written.
|
|
// Optional. Default value os.Stdout.
|
|
Output io.Writer
|
|
}
|
|
|
|
var DefaultLogFmtConfig = LogFmtConfig{
|
|
Skipper: DefaultSkipper,
|
|
Output: os.Stdout,
|
|
}
|
|
|
|
func LogFmt() Interceptor {
|
|
c := DefaultLogFmtConfig
|
|
|
|
return LogFmtWithConfig(c)
|
|
}
|
|
|
|
func LogFmtWithConfig(config LogFmtConfig) Interceptor {
|
|
if config.Skipper == nil {
|
|
config.Skipper = DefaultLogFmtConfig.Skipper
|
|
}
|
|
|
|
if config.Output == nil {
|
|
config.Output = DefaultLogFmtConfig.Output
|
|
}
|
|
|
|
encoder := logfmt.NewEncoder(config.Output)
|
|
|
|
return func(ctx *http.RequestCtx, next http.RequestHandler) {
|
|
next(ctx)
|
|
|
|
encoder.EncodeKeyvals(
|
|
"bytes_in", len(ctx.Request.Body()),
|
|
"bytes_out", len(ctx.Response.Body()),
|
|
"error", ctx.Err(),
|
|
"host", ctx.Host(),
|
|
"id", ctx.ID(),
|
|
"latency", ctx.Time().Sub(ctx.ConnTime()).Nanoseconds(),
|
|
"latency_human", ctx.Time().Sub(ctx.ConnTime()).String(),
|
|
"method", ctx.Method(),
|
|
"path", ctx.Path(),
|
|
"protocol", ctx.Request.Header.Protocol(),
|
|
"referer", ctx.Referer(),
|
|
"remote_ip", ctx.RemoteIP(),
|
|
"status", ctx.Response.StatusCode(),
|
|
"time_rfc3339", ctx.Time().Format(time.RFC3339),
|
|
"time_rfc3339_nano", ctx.Time().Format(time.RFC3339Nano),
|
|
"time_unix", ctx.Time().Unix(),
|
|
"time_unix_nano", ctx.Time().UnixNano(),
|
|
"uri", ctx.URI(),
|
|
"user_agent", ctx.UserAgent(),
|
|
)
|
|
ctx.Request.Header.VisitAllInOrder(func(key, value []byte) {
|
|
encoder.EncodeKeyval(strings.ReplaceAll(strings.ToLower("header_"+string(key)), "-", "_"), value)
|
|
})
|
|
ctx.QueryArgs().VisitAll(func(key, value []byte) {
|
|
encoder.EncodeKeyval(strings.ReplaceAll(strings.ToLower("query_"+string(key)), "-", "_"), value)
|
|
})
|
|
|
|
if form, err := ctx.MultipartForm(); err == nil {
|
|
for k, v := range form.Value {
|
|
encoder.EncodeKeyval(strings.ReplaceAll(strings.ToLower("form_"+k), "-", "_"), v)
|
|
}
|
|
}
|
|
|
|
encoder.EndRecord()
|
|
}
|
|
}
|