github.com/segakazzz/buffalo@v0.16.22-0.20210119082501-1f52048d3feb/request_logger.go (about)

     1  package buffalo
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/hex"
     6  	"net/http"
     7  	"time"
     8  
     9  	humanize "github.com/dustin/go-humanize"
    10  	"github.com/segakazzz/buffalo/internal/httpx"
    11  )
    12  
    13  // RequestLogger can be be overridden to a user specified
    14  // function that can be used to log the request.
    15  var RequestLogger = RequestLoggerFunc
    16  
    17  func randString(i int) (string, error) {
    18  	if i == 0 {
    19  		i = 64
    20  	}
    21  	b := make([]byte, i)
    22  	_, err := rand.Read(b)
    23  	return hex.EncodeToString(b), err
    24  }
    25  
    26  // RequestLoggerFunc is the default implementation of the RequestLogger.
    27  // By default it will log a uniq "request_id", the HTTP Method of the request,
    28  // the path that was requested, the duration (time) it took to process the
    29  // request, the size of the response (and the "human" size), and the status
    30  // code of the response.
    31  func RequestLoggerFunc(h Handler) Handler {
    32  	return func(c Context) error {
    33  		rs, err := randString(10)
    34  		if err != nil {
    35  			return err
    36  		}
    37  		var irid interface{}
    38  		if irid = c.Session().Get("requestor_id"); irid == nil {
    39  			rs, err := randString(10)
    40  			if err != nil {
    41  				return err
    42  			}
    43  			irid = rs
    44  			c.Session().Set("requestor_id", irid)
    45  			c.Session().Save()
    46  		}
    47  
    48  		rid := irid.(string) + "-" + rs
    49  		c.Set("request_id", rid)
    50  		c.LogField("request_id", rid)
    51  
    52  		start := time.Now()
    53  		defer func() {
    54  			ws, ok := c.Response().(*Response)
    55  			if !ok {
    56  				ws = &Response{ResponseWriter: c.Response()}
    57  				ws.Status = http.StatusOK
    58  			}
    59  			req := c.Request()
    60  			ct := httpx.ContentType(req)
    61  			if ct != "" {
    62  				c.LogField("content_type", ct)
    63  			}
    64  			c.LogFields(map[string]interface{}{
    65  				"method":     req.Method,
    66  				"path":       req.URL.String(),
    67  				"duration":   time.Since(start),
    68  				"size":       ws.Size,
    69  				"human_size": humanize.Bytes(uint64(ws.Size)),
    70  				"status":     ws.Status,
    71  			})
    72  			c.Logger().Info(req.URL.String())
    73  		}()
    74  		return h(c)
    75  	}
    76  }