Skip to content

Instantly share code, notes, and snippets.

@neilco
Forked from cespare/log.go
Last active February 5, 2016 23:23
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 neilco/9186a8945604379cecc8 to your computer and use it in GitHub Desktop.
Save neilco/9186a8945604379cecc8 to your computer and use it in GitHub Desktop.
Golang apache logging
package main
import (
"fmt"
"io"
"net/http"
"strings"
"time"
)
const (
ApacheLogFormat = "%s - - [%s] \"%s\" %d %d %.0f\n"
ApacheLogCombinedFormat = "%s - - [%s] \"%s\" %d %d %.0f %s \"%s\"\n"
)
type LogRecord struct {
http.ResponseWriter
ip string
time time.Time
method, uri, protocol string
status int
responseBytes int64
elapsedTime time.Duration
referrer string
userAgent string
}
func (r *LogRecord) Log(out io.Writer, format string) {
timeFormatted := r.time.Format("02/Jan/2006 15:04:05")
requestLine := fmt.Sprintf("%s %s %s", r.method, r.uri, r.protocol)
switch format {
case ApacheLogFormat:
fmt.Fprintf(out, ApacheLogFormat, r.ip, timeFormatted, requestLine, r.status, r.responseBytes,
r.elapsedTime.Seconds()*1000)
break
case ApacheLogCombinedFormat:
fmt.Fprintf(out, ApacheLogCombinedFormat, r.ip, timeFormatted, requestLine, r.status, r.responseBytes,
r.elapsedTime.Seconds()*1000, r.referrer, r.userAgent)
break
}
}
func (r *LogRecord) Write(p []byte) (int, error) {
written, err := r.ResponseWriter.Write(p)
r.responseBytes += int64(written)
return written, err
}
func (r *LogRecord) WriteHeader(status int) {
r.status = status
r.ResponseWriter.WriteHeader(status)
}
type ApacheLogHandler struct {
handler http.Handler
out io.Writer
}
func NewApacheLoggingHandler(handler http.Handler, out io.Writer) http.Handler {
return &ApacheLogHandler{
handler: handler,
out: out,
}
}
func (h *ApacheLogHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
// Use the real client IP address if beyond a proxy or load balancer
if len(r.Header["X-Forwarded-For"]) > 0 {
clientIP = r.Header.Get("X-Forwarded-For")
}
if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
clientIP = clientIP[:colon]
}
referrer := "-"
if r.Header.Get("Referer") != "" {
referrer = fmt.Sprintf("\"%s\"", r.Header.Get("Referer"))
}
record := &LogRecord{
ResponseWriter: rw,
ip: clientIP,
time: time.Time{},
method: r.Method,
uri: r.RequestURI,
protocol: r.Proto,
status: http.StatusOK,
elapsedTime: time.Duration(0),
referrer: referrer,
userAgent: r.Header.Get("User-Agent"),
}
startTime := time.Now()
h.handler.ServeHTTP(record, r)
finishTime := time.Now()
record.time = finishTime.UTC()
record.elapsedTime = finishTime.Sub(startTime)
record.Log(h.out, ApacheLogCombinedFormat)
}
func main() {
mux := http.DefaultServeMux
mux.HandleFunc("/", indexHandler)
loggingHandler := NewApacheLoggingHandler(mux, os.Stderr)
server := &http.Server{
Addr: fmt.Sprintf(":%s", 2345),
Handler: loggingHandler,
}
server.ListenAndServe()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment