1
0
Fork 0

enable logging to stdout for access logs

This commit is contained in:
Marco Jantke 2017-05-30 12:06:49 +02:00 committed by Ludovic Fernandez
parent f275e4ad3c
commit 885b9f371c
6 changed files with 138 additions and 93 deletions

View file

@ -9,6 +9,7 @@ import (
"net/url"
"os"
"path/filepath"
"regexp"
"testing"
"github.com/containous/traefik/types"
@ -18,9 +19,8 @@ import (
)
var (
logger *LogHandler
logFileNameSuffix = "/traefik/logger/test.log"
helloWorld = "Hello, World"
testContent = "Hello, World"
testBackendName = "http://127.0.0.1/testBackend"
testFrontendName = "testFrontend"
testStatus = 123
@ -36,32 +36,27 @@ var (
)
func TestLoggerCLF(t *testing.T) {
tmpDir, logFilePath := doLogging(t, CommonFormat)
tmpDir := createTempDir(t, CommonFormat)
defer os.RemoveAll(tmpDir)
logFilePath := filepath.Join(tmpDir, logFileNameSuffix)
config := &types.AccessLog{FilePath: logFilePath, Format: CommonFormat}
doLogging(t, config)
logData, err := ioutil.ReadFile(logFilePath)
require.NoError(t, err)
tokens, err := shellwords.Parse(string(logData))
require.NoError(t, err)
assert.Equal(t, 14, len(tokens), printLogData(logData))
assert.Equal(t, testHostname, tokens[0], printLogData(logData))
assert.Equal(t, testUsername, tokens[2], printLogData(logData))
assert.Equal(t, fmt.Sprintf("%s %s %s", testMethod, testPath, testProto), tokens[5], printLogData(logData))
assert.Equal(t, fmt.Sprintf("%d", testStatus), tokens[6], printLogData(logData))
assert.Equal(t, fmt.Sprintf("%d", len(helloWorld)), tokens[7], printLogData(logData))
assert.Equal(t, testReferer, tokens[8], printLogData(logData))
assert.Equal(t, testUserAgent, tokens[9], printLogData(logData))
assert.Equal(t, "1", tokens[10], printLogData(logData))
assert.Equal(t, testFrontendName, tokens[11], printLogData(logData))
assert.Equal(t, testBackendName, tokens[12], printLogData(logData))
assertValidLogData(t, logData)
}
func TestLoggerJSON(t *testing.T) {
tmpDir, logFilePath := doLogging(t, JSONFormat)
tmpDir := createTempDir(t, JSONFormat)
defer os.RemoveAll(tmpDir)
logFilePath := filepath.Join(tmpDir, logFileNameSuffix)
config := &types.AccessLog{FilePath: logFilePath, Format: JSONFormat}
doLogging(t, config)
logData, err := ioutil.ReadFile(logFilePath)
require.NoError(t, err)
@ -121,9 +116,9 @@ func TestLoggerJSON(t *testing.T) {
assertCount++
assert.Equal(t, fmt.Sprintf("%d ", testStatus), jsonData[DownstreamStatusLine])
assertCount++
assert.Equal(t, float64(len(helloWorld)), jsonData[DownstreamContentSize])
assert.Equal(t, float64(len(testContent)), jsonData[DownstreamContentSize])
assertCount++
assert.Equal(t, float64(len(helloWorld)), jsonData[OriginContentSize])
assert.Equal(t, float64(len(testContent)), jsonData[OriginContentSize])
assertCount++
assert.Equal(t, float64(testStatus), jsonData[OriginStatus])
assertCount++
@ -165,6 +160,90 @@ func TestLoggerJSON(t *testing.T) {
assert.Equal(t, len(jsonData), assertCount, string(logData))
}
func TestNewLogHandlerOutputStdout(t *testing.T) {
file, restoreStdout := captureStdout(t)
defer restoreStdout()
config := &types.AccessLog{FilePath: "", Format: CommonFormat}
doLogging(t, config)
written, err := ioutil.ReadFile(file.Name())
require.NoError(t, err, "unable to read captured stdout from file")
require.NotZero(t, len(written), "expected access log message on stdout")
assertValidLogData(t, written)
}
func assertValidLogData(t *testing.T, logData []byte) {
tokens, err := shellwords.Parse(string(logData))
require.NoError(t, err)
formatErrMessage := fmt.Sprintf(`
Expected: TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 1 "testFrontend" "http://127.0.0.1/testBackend" 1ms
Actual: %s
`,
string(logData))
require.Equal(t, 14, len(tokens), formatErrMessage)
assert.Equal(t, testHostname, tokens[0], formatErrMessage)
assert.Equal(t, testUsername, tokens[2], formatErrMessage)
assert.Equal(t, fmt.Sprintf("%s %s %s", testMethod, testPath, testProto), tokens[5], formatErrMessage)
assert.Equal(t, fmt.Sprintf("%d", testStatus), tokens[6], formatErrMessage)
assert.Equal(t, fmt.Sprintf("%d", len(testContent)), tokens[7], formatErrMessage)
assert.Equal(t, testReferer, tokens[8], formatErrMessage)
assert.Equal(t, testUserAgent, tokens[9], formatErrMessage)
assert.Regexp(t, regexp.MustCompile("[0-9]*"), tokens[10], formatErrMessage)
assert.Equal(t, testFrontendName, tokens[11], formatErrMessage)
assert.Equal(t, testBackendName, tokens[12], formatErrMessage)
}
func captureStdout(t *testing.T) (out *os.File, restoreStdout func()) {
file, err := ioutil.TempFile("", "testlogger")
require.NoError(t, err, "failed to create temp file")
original := os.Stdout
os.Stdout = file
restoreStdout = func() {
os.Stdout = original
}
return file, restoreStdout
}
func createTempDir(t *testing.T, prefix string) string {
tmpDir, err := ioutil.TempDir("", prefix)
require.NoError(t, err, "failed to create temp dir")
return tmpDir
}
func doLogging(t *testing.T, config *types.AccessLog) {
logger, err := NewLogHandler(config)
defer logger.Close()
require.NoError(t, err)
if config.FilePath != "" {
_, err = os.Stat(config.FilePath)
require.NoError(t, err, fmt.Sprintf("logger should create %s", config.FilePath))
}
req := &http.Request{
Header: map[string][]string{
"User-Agent": {testUserAgent},
"Referer": {testReferer},
},
Proto: testProto,
Host: testHostname,
Method: testMethod,
RemoteAddr: fmt.Sprintf("%s:%d", testHostname, testPort),
URL: &url.URL{
User: url.UserPassword(testUsername, ""),
Path: testPath,
},
}
logger.ServeHTTP(httptest.NewRecorder(), req, logWriterTestHandlerFunc)
}
func containsKeys(t *testing.T, expectedKeys []string, data map[string]interface{}) {
for key, value := range data {
if !contains(expectedKeys, key) {
@ -187,54 +266,8 @@ func contains(values []string, value string) bool {
return false
}
func doLogging(t *testing.T, format string) (string, string) {
tmp, err := ioutil.TempDir("", format)
if err != nil {
t.Fatalf("failed to create temp dir: %s", err)
}
logFilePath := filepath.Join(tmp, logFileNameSuffix)
config := types.AccessLog{FilePath: logFilePath, Format: format}
logger, err = NewLogHandler(&config)
defer logger.Close()
require.NoError(t, err)
if _, err := os.Stat(logFilePath); os.IsNotExist(err) {
t.Fatalf("logger should create %s", logFilePath)
}
req := &http.Request{
Header: map[string][]string{
"User-Agent": {testUserAgent},
"Referer": {testReferer},
},
Proto: testProto,
Host: testHostname,
Method: testMethod,
RemoteAddr: fmt.Sprintf("%s:%d", testHostname, testPort),
URL: &url.URL{
User: url.UserPassword(testUsername, ""),
Path: testPath,
},
}
rw := httptest.NewRecorder()
logger.ServeHTTP(rw, req, logWriterTestHandlerFunc)
return tmp, logFilePath
}
func printLogData(logdata []byte) string {
return fmt.Sprintf(`
Expected: TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 1 "testFrontend" "http://127.0.0.1/testBackend" 1ms
Actual: %s
`,
string(logdata))
}
func logWriterTestHandlerFunc(rw http.ResponseWriter, r *http.Request) {
rw.Write([]byte(helloWorld))
rw.Write([]byte(testContent))
rw.WriteHeader(testStatus)
logDataTable := GetLogDataTable(r)