8

I'm trying to catch and log http error 400 that happens when url params are not encoded properly.

My server implementation looks like:

router := http.NewServeMux()
router.HandleFunc("/", requestHandler)

s := &http.Server{
    Addr:           ":8080",
    Handler:        router,
    ErrorLog:       myLogger,
}
log.Fatal(s.ListenAndServe())

The request never reaches requestHandler, and having ErrorLog: myLogger makes no difference.

1
  • 3
    github.com/gorilla/handlers provides middleware that can do this for you - wrap the router in http.ListenAndServe(":8000", handlers.LoggingHandler(os.Stdout, r)) where r is a http.NewServeMux. Commented Aug 23, 2014 at 0:37

2 Answers 2

8

You need to create a custom Wrapper around the requestHandler that records the StatusCode and inspects it after the requestCall has been processed.

Notice how we wrap the main router itself. with WrapHandler(router)

package main

import (
    "log"
    "net/http"
)

type LogRecord struct {
    http.ResponseWriter
    status int
}

func (r *LogRecord) Write(p []byte) (int, error) {
    return r.ResponseWriter.Write(p)
}

func (r *LogRecord) WriteHeader(status int) {
    r.status = status
    r.ResponseWriter.WriteHeader(status)
}

func WrapHandler(f http.Handler) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        record := &LogRecord{
            ResponseWriter: w,
        }

        f.ServeHTTP(record, r)

        log.Println("Bad Request ", record.status)

        if record.status == http.StatusBadRequest {
            log.Println("Bad Request ", r)
        }
    }
}

func main() {
    router := http.NewServeMux()

    s := &http.Server{
        Addr:    ":8080",
        Handler: WrapHandler(router),
    }
    log.Fatal(s.ListenAndServe())
}
Sign up to request clarification or add additional context in comments.

10 Comments

Thanks, looks like you are on the right track, only I'm getting these exceptions: func(http.ResponseWriter, *http.Request) does not implement http.Handler (missing ServeHTTP method), and cannot call non-function f (type http.Handler)
sorry the type is http.HandlerFunc not http.Handler. look at the diff: stackoverflow.com/posts/25456451/revisions
That solved the exception, but still doesn't log 400. I put logging at the very beginning of this wrapper and it never gets called for 400 requests (for regular requests it is logged fine). Also for regular requests record.status is 0 (shouldn't it be somethign like 200?)
then we have to wrap the router itself. The Mux was not even calling the handler function. this will log everything.
Here is what I use for testing: python -c "import urllib2; urllib2.urlopen(\"http://127.0.0.1:8080/?a=b c\").read()"
|
1

Just for anyone else finding this, you can't intercept a 400 error using net/http in Go. See this answer for more details:

How can I customize Golang http 400 responses for parse errors?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.