package main import ( "fmt" "io" "log" "net/http" "os" "time" ) // Example log output: // 127.0.0.1 - - [28/Oct/2016:18:35:05 -0400] "GET / HTTP/1.1" 200 13 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36" // 127.0.0.1 - - [28/Oct/2016:18:35:05 -0400] "GET /favicon.ico HTTP/1.1" 404 10 "http://localhost:8080/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36" func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.Error(w, "Not Found", http.StatusNotFound) return } fmt.Fprintln(w, "Hello World!") }) log.Println("Serving...") // Logger takes an io.Writer and an http.Handler function to wrap: http.ListenAndServe(":8080", Logger(os.Stderr, http.DefaultServeMux)) } // Logs incoming requests, including response status. func Logger(out io.Writer, h http.Handler) http.Handler { logger := log.New(out, "", 0) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { o := &responseObserver{ResponseWriter: w} h.ServeHTTP(o, r) addr := r.RemoteAddr if i := strings.LastIndex(addr, ":"); i != -1 { addr = addr[:i] } logger.Printf("%s - - [%s] %q %d %d %q %q", addr, time.Now().Format("02/Jan/2006:15:04:05 -0700"), fmt.Sprintf("%s %s %s", r.Method, r.URL, r.Proto), o.status, o.written, r.Referer(), r.UserAgent()) }) } type responseObserver struct { http.ResponseWriter status int written int64 wroteHeader bool } func (o *responseObserver) Write(p []byte) (n int, err error) { if !o.wroteHeader { o.WriteHeader(http.StatusOK) } n, err = o.ResponseWriter.Write(p) o.written += int64(n) return } func (o *responseObserver) WriteHeader(code int) { o.ResponseWriter.WriteHeader(code) if o.wroteHeader { return } o.wroteHeader = true o.status = code }