Golang logging HTTP responses (in addition to requests)

I use Go and the Gorilla multimedia toolkit and web tool handler packages to create a complex application, some of which requires an HTTP server. The Gorilla combo and handler packages work just fine, and I can successfully start the HTTP server, and it was pretty easy to log requests.

However, I cannot determine how I can record responses. Ideally, I would like a mechanism similar to the Gorilla LoggingHandler to easily wrap the logging mechanism.

Is there a Golang package that easily wraps / logs responses? Is there a way to use the capabilities of Go or Gorilla in a way that I have not considered?

+2
source share
3 answers

Thanks for the great suggestions. I tried a few suggestions and landed on a fairly simple solution that uses a minimalist shell. Here is a solution that worked for me (feel free to suggest comments or, even better, other solutions):

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httptest"
    "net/http/httputil"
    "github.com/gorilla/mux"
)
:

func logHandler(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        x, err := httputil.DumpRequest(r, true)
        if err != nil {
            http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
            return
        }
        log.Println(fmt.Sprintf("%q", x))
        rec := httptest.NewRecorder()
        fn(rec, r)
        log.Println(fmt.Sprintf("%q", rec.Body))            
    }
}

func MessageHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "A message was received")
}

And the following code will use the above handler:

:
router := mux.NewRouter()
router.HandleFunc("/", logHandler(MessageHandler))
:

Exiting the above code will be something like lines:

:
2016/07/20 14:44:29 "GET ... HTTP/1.1\r\nHost: localhost:8088\r\nAccept: */*\r\nUser-Agent: curl/7.43.0\r\n\r\n"
2016/07/20 14:44:29 ...[response body]
:
+3
source

Sorry, I didn’t notice your mention of gorilla-mux, I only tried this with gin, but if it uses middlewares, it should work anyway.


the trick, c.Next()in blocks of the middle layer, until all subsequent secondary links return. Here's a trading solution. Put this as your first middleware:

func Logrus(logger *logrus.Logger) gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now().UTC()
        path := c.Request.URL.Path
        c.Next()
        end := time.Now().UTC()
        latency := end.Sub(start)
        logger.WithFields(logrus.Fields{
            "status":     c.Writer.Status(),
            "method":     c.Request.Method,
            "path":       path,
            "ip":         c.ClientIP(),
            "duration":   latency,
            "user_agent": c.Request.UserAgent(),
        }).Info()
    }
}
GinEngine.Use(Logrus(logrus.StandardLogger()))
+3
source

, . , :

func logHandler(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        x, err := httputil.DumpRequest(r, true)
        if err != nil {
            http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
            return
        }
        log.Println(fmt.Sprintf("%q", x))
        rec := httptest.NewRecorder()
        fn(rec, r)
        log.Println(fmt.Sprintf("%q", rec.Body))        

        // this copies the recorded response to the response writer
        for k, v := range rec.HeaderMap {
            w.Header()[k] = v
        }
        w.WriteHeader(rec.Code)
        rec.Body.WriteTo(w)
    }
}
0
source

Source: https://habr.com/ru/post/1651815/


All Articles