serg
serg

Reputation: 111365

How to log http server errors in golang?

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.

Upvotes: 8

Views: 13478

Answers (2)

Kenny Grant
Kenny Grant

Reputation: 9653

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?

Upvotes: 1

fabmilo
fabmilo

Reputation: 48330

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())
}

Upvotes: 8

Related Questions