blob: 00f7f92fd20317d3240022697115379e8ab1e491 [file] [log] [blame]
// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package httpxtra
import (
"bufio"
"fmt"
"net"
"net/http"
"time"
)
// LoggerFunc are functions called by httpxtra.Handler at the end of each request.
type LoggerFunc func(r *http.Request, created time.Time, status, bytes int)
type LogWriter struct {
ResponseWriter http.ResponseWriter
Bytes int
Status int
}
func (lw *LogWriter) Header() http.Header {
return lw.ResponseWriter.Header()
}
func (lw *LogWriter) Write(b []byte) (int, error) {
if lw.Status == 0 {
lw.Status = http.StatusOK
}
n, err := lw.ResponseWriter.Write(b)
lw.Bytes += n
return n, err
}
func (lw *LogWriter) WriteHeader(s int) {
lw.ResponseWriter.WriteHeader(s)
lw.Status = s
}
func (lw *LogWriter) Flush() {
lw.ResponseWriter.(http.Flusher).Flush()
}
func (lw *LogWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if lw.Status == 0 {
lw.Status = http.StatusOK
}
// TODO: Check. Does it break if the server don't support hijacking?
return lw.ResponseWriter.(http.Hijacker).Hijack()
}
func (lw *LogWriter) CloseNotify() <-chan bool {
return lw.ResponseWriter.(http.CloseNotifier).CloseNotify()
}
// ApacheCommonLog returns an Apache Common access log string.
func ApacheCommonLog(r *http.Request, created time.Time, status, bytes int) string {
u := "-"
if r.URL.User != nil {
if name := r.URL.User.Username(); name != "" {
u = name
}
}
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
ip = r.RemoteAddr
}
return fmt.Sprintf("%s - %s [%s] \"%s %s %s\" %d %d",
ip,
u,
created.Format("02/Jan/2006:15:04:05 -0700"),
r.Method,
r.RequestURI,
r.Proto,
status,
bytes,
)
}