influxdb/httpd/response_logger.go

116 lines
2.2 KiB
Go
Raw Normal View History

2015-01-21 20:58:06 +00:00
package httpd
import (
"encoding/base64"
2015-01-21 20:58:06 +00:00
"fmt"
"net"
"net/http"
2015-01-21 23:14:51 +00:00
"strconv"
"strings"
2015-01-21 20:58:06 +00:00
"time"
)
type loggingResponseWriter interface {
http.ResponseWriter
Status() int
Size() int
}
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP status
// code and body size
type responseLogger struct {
w http.ResponseWriter
status int
size int
}
func (l *responseLogger) Header() http.Header {
return l.w.Header()
}
func (l *responseLogger) Write(b []byte) (int, error) {
if l.status == 0 {
2015-01-21 21:07:30 +00:00
// Set status if WriteHeader has not been called
2015-01-21 20:58:06 +00:00
l.status = http.StatusOK
}
size, err := l.w.Write(b)
l.size += size
return size, err
}
func (l *responseLogger) WriteHeader(s int) {
l.w.WriteHeader(s)
l.status = s
}
func (l *responseLogger) Status() int {
return l.status
}
func (l *responseLogger) Size() int {
return l.size
}
// Common Log Format: http://en.wikipedia.org/wiki/Common_Log_Format
2015-01-21 22:36:50 +00:00
// buildLogLine creates a common log format
// in addittion to the common fields, we also append referrer, user agent and request ID
2015-01-21 20:58:06 +00:00
func buildLogLine(l *responseLogger, r *http.Request, start time.Time) string {
2015-01-21 23:14:51 +00:00
username := parseUsername(r)
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
host = r.RemoteAddr
}
uri := r.URL.RequestURI()
fields := []string{
host,
"-",
username,
fmt.Sprintf("[%s]", start.Format("02/Jan/2006:15:04:05 -0700")),
r.Method,
uri,
r.Proto,
strconv.Itoa(l.Status()),
strconv.Itoa(l.Size()),
r.Referer(),
r.UserAgent(),
r.Header.Get("Request-Id"),
}
return strings.Join(fields, " ")
}
// parses the uesrname either from the url or auth header
func parseUsername(r *http.Request) string {
2015-01-21 20:58:06 +00:00
username := "-"
2015-01-21 23:14:51 +00:00
2015-01-21 20:58:06 +00:00
url := r.URL
// get username from the url if passed there
2015-01-21 20:58:06 +00:00
if url.User != nil {
if name := url.User.Username(); name != "" {
username = name
}
}
// Try to get it from the authorization header if set there
if username == "-" {
auth := r.Header.Get("Authorization")
fields := strings.Split(auth, " ")
if len(fields) == 2 {
bs, err := base64.StdEncoding.DecodeString(fields[1])
if err == nil {
fields = strings.Split(string(bs), ":")
if len(fields) >= 1 {
username = fields[0]
}
}
}
}
2015-01-21 23:14:51 +00:00
return username
2015-01-21 20:58:06 +00:00
}