Skip to content

Instantly share code, notes, and snippets.

@steevehook
Forked from blixt/logger_middleware.go
Created April 3, 2019 08:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steevehook/8fbe94d57f59fe22890dd3fc127e4e42 to your computer and use it in GitHub Desktop.
Save steevehook/8fbe94d57f59fe22890dd3fc127e4e42 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