Skip to content

Instantly share code, notes, and snippets.

@blinkinglight
Forked from blixt/logger_middleware.go
Created June 23, 2019 08:38
Show Gist options
  • Save blinkinglight/a8e9020c7661a4a22387daa2ce301535 to your computer and use it in GitHub Desktop.
Save blinkinglight/a8e9020c7661a4a22387daa2ce301535 to your computer and use it in GitHub Desktop.
Logger middleware for Go HTTP servers which logs every request with response status code in the Apache format.
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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment