-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mostly copied from gorrila's LogginHandler but changed to make it not block finishing the request and to add time the request took.
- Loading branch information
Showing
9 changed files
with
258 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package app | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
) | ||
|
||
const accessLogFilePerm = 0600 | ||
|
||
// open an access log with the appropriate permissions on the file | ||
// if it isn't open yet. Return the already open otherwise | ||
func (a accessLogs) openAccessLog(file string) (io.Writer, error) { | ||
if accessLog, ok := a[file]; ok { | ||
return accessLog, nil | ||
} | ||
accessLog, err := os.OpenFile( | ||
file, | ||
os.O_CREATE|os.O_WRONLY|os.O_APPEND, | ||
accessLogFilePerm, | ||
) | ||
if err != nil { | ||
return nil, fmt.Errorf("error opening access log `%s`- %s", | ||
file, err) | ||
} | ||
a[file] = accessLog | ||
return accessLog, nil | ||
} | ||
|
||
// helper type to facilitate not opening the same access_log twice | ||
type accessLogs map[string]io.Writer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
// Copyright 2013 The Gorilla Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package app | ||
|
||
import ( | ||
"io" | ||
"net" | ||
"net/http" | ||
"net/url" | ||
"strconv" | ||
"time" | ||
"unicode/utf8" | ||
) | ||
|
||
// The file is mostly a copy of the source from gorilla's handlers.go | ||
|
||
// buildCommonLogLine builds a log entry for req in Apache Common Log Format. | ||
// ts is the timestamp with which the entry should be logged. | ||
// status and size are used to provide the response HTTP status and size. | ||
// Additionally the time since the timestamp is being written | ||
func buildCommonLogLine(req *http.Request, url url.URL, ts time.Time, status int, size int) []byte { | ||
username := "-" | ||
if url.User != nil { | ||
if name := url.User.Username(); name != "" { | ||
username = name | ||
} | ||
} | ||
|
||
host, _, err := net.SplitHostPort(req.RemoteAddr) | ||
|
||
if err != nil { | ||
host = req.RemoteAddr | ||
} | ||
|
||
uri := url.RequestURI() | ||
ranFor := int(time.Since(ts).Nanoseconds()) | ||
|
||
buf := make([]byte, 0, 3*(len(host)+len(username)+len(req.Method)+len(uri)+len(req.Proto)+50)/2) | ||
buf = append(buf, host...) | ||
buf = append(buf, " - "...) | ||
buf = append(buf, username...) | ||
buf = append(buf, " ["...) | ||
buf = append(buf, ts.Format("02/Jan/2006:15:04:05 -0700")...) | ||
buf = append(buf, `] "`...) | ||
buf = append(buf, req.Method...) | ||
buf = append(buf, " "...) | ||
buf = appendQuoted(buf, uri) | ||
buf = append(buf, " "...) | ||
buf = append(buf, req.Proto...) | ||
buf = append(buf, `" `...) | ||
buf = append(buf, strconv.Itoa(status)...) | ||
buf = append(buf, " "...) | ||
buf = append(buf, strconv.Itoa(size)...) | ||
buf = append(buf, " "...) | ||
buf = append(buf, strconv.Itoa(ranFor)...) | ||
return buf | ||
} | ||
|
||
// writeLog writes a log entry for req to w in Apache Common Log Format. | ||
// ts is the timestamp with which the entry should be logged. | ||
// status and size are used to provide the response HTTP status and size. | ||
func writeLog(w io.Writer, req *http.Request, url url.URL, ts time.Time, status, size int) { | ||
buf := buildCommonLogLine(req, url, ts, status, size) | ||
buf = append(buf, '\n') | ||
w.Write(buf) | ||
} | ||
|
||
func appendQuoted(buf []byte, s string) []byte { | ||
var runeTmp [utf8.UTFMax]byte | ||
for width := 0; len(s) > 0; s = s[width:] { | ||
r := rune(s[0]) | ||
width = 1 | ||
if r >= utf8.RuneSelf { | ||
r, width = utf8.DecodeRuneInString(s) | ||
} | ||
if width == 1 && r == utf8.RuneError { | ||
buf = append(buf, `\x`...) | ||
buf = append(buf, lowerhex[s[0]>>4]) | ||
buf = append(buf, lowerhex[s[0]&0xF]) | ||
continue | ||
} | ||
if r == rune('"') || r == '\\' { // always backslashed | ||
buf = append(buf, '\\') | ||
buf = append(buf, byte(r)) | ||
continue | ||
} | ||
if strconv.IsPrint(r) { | ||
n := utf8.EncodeRune(runeTmp[:], r) | ||
buf = append(buf, runeTmp[:n]...) | ||
continue | ||
} | ||
switch r { | ||
case '\a': | ||
buf = append(buf, `\a`...) | ||
case '\b': | ||
buf = append(buf, `\b`...) | ||
case '\f': | ||
buf = append(buf, `\f`...) | ||
case '\n': | ||
buf = append(buf, `\n`...) | ||
case '\r': | ||
buf = append(buf, `\r`...) | ||
case '\t': | ||
buf = append(buf, `\t`...) | ||
case '\v': | ||
buf = append(buf, `\v`...) | ||
default: | ||
switch { | ||
case r < ' ': | ||
buf = append(buf, `\x`...) | ||
buf = append(buf, lowerhex[s[0]>>4]) | ||
buf = append(buf, lowerhex[s[0]&0xF]) | ||
case r > utf8.MaxRune: | ||
r = 0xFFFD | ||
fallthrough | ||
case r < 0x10000: | ||
buf = append(buf, `\u`...) | ||
for s := 12; s >= 0; s -= 4 { | ||
buf = append(buf, lowerhex[r>>uint(s)&0xF]) | ||
} | ||
default: | ||
buf = append(buf, `\U`...) | ||
for s := 28; s >= 0; s -= 4 { | ||
buf = append(buf, lowerhex[r>>uint(s)&0xF]) | ||
} | ||
} | ||
} | ||
} | ||
return buf | ||
} | ||
|
||
const lowerhex = "0123456789abcdef" | ||
|
||
type responseLogger struct { | ||
http.ResponseWriter | ||
status int | ||
size int | ||
} | ||
|
||
func (l *responseLogger) Write(b []byte) (int, error) { | ||
if l.status == 0 { | ||
// The status will be StatusOK if WriteHeader has not been called yet | ||
l.status = http.StatusOK | ||
} | ||
size, err := l.ResponseWriter.Write(b) | ||
l.size += size | ||
return size, err | ||
} | ||
|
||
func (l *responseLogger) WriteHeader(s int) { | ||
l.ResponseWriter.WriteHeader(s) | ||
l.status = s | ||
} | ||
|
||
func (l *responseLogger) Status() int { | ||
return l.status | ||
} | ||
|
||
func (l *responseLogger) Size() int { | ||
return l.size | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters