1
0
Fork 0

Ultimate Access log filter

This commit is contained in:
Michael 2018-03-14 14:12:04 +01:00 committed by Traefiker Bot
parent f99363674b
commit 8d468925d3
24 changed files with 1722 additions and 683 deletions

View file

@ -12,6 +12,7 @@ import (
"sync/atomic"
"time"
"github.com/containous/traefik/log"
"github.com/containous/traefik/types"
"github.com/sirupsen/logrus"
)
@ -32,10 +33,12 @@ const (
// LogHandler will write each request and its response to the access log.
type LogHandler struct {
logger *logrus.Logger
file *os.File
filePath string
mu sync.Mutex
logger *logrus.Logger
file *os.File
filePath string
mu sync.Mutex
httpCodeRanges types.HTTPCodeRanges
fields *types.AccessLogFields
}
// NewLogHandler creates a new LogHandler
@ -66,7 +69,24 @@ func NewLogHandler(config *types.AccessLog) (*LogHandler, error) {
Hooks: make(logrus.LevelHooks),
Level: logrus.InfoLevel,
}
return &LogHandler{logger: logger, file: file, filePath: config.FilePath}, nil
logHandler := &LogHandler{
logger: logger,
file: file,
filePath: config.FilePath,
fields: config.Fields,
}
if config.Filters != nil {
httpCodeRanges, err := types.NewHTTPCodeRanges(config.Filters.StatusCodes)
if err != nil {
log.Errorf("Failed to create new HTTP code ranges: %s", err)
} else if httpCodeRanges != nil {
logHandler.httpCodeRanges = httpCodeRanges
}
}
return logHandler, nil
}
func openAccessLogFile(filePath string) (*os.File, error) {
@ -198,45 +218,65 @@ func (l *LogHandler) logTheRoundTrip(logDataTable *LogData, crr *captureRequestR
}
core[DownstreamStatus] = crw.Status()
core[DownstreamStatusLine] = fmt.Sprintf("%03d %s", crw.Status(), http.StatusText(crw.Status()))
core[DownstreamContentSize] = crw.Size()
if original, ok := core[OriginContentSize]; ok {
o64 := original.(int64)
if o64 != crw.Size() && 0 != crw.Size() {
core[GzipRatio] = float64(o64) / float64(crw.Size())
if l.keepAccessLog(crw.Status()) {
core[DownstreamStatusLine] = fmt.Sprintf("%03d %s", crw.Status(), http.StatusText(crw.Status()))
core[DownstreamContentSize] = crw.Size()
if original, ok := core[OriginContentSize]; ok {
o64 := original.(int64)
if o64 != crw.Size() && 0 != crw.Size() {
core[GzipRatio] = float64(o64) / float64(crw.Size())
}
}
// n.b. take care to perform time arithmetic using UTC to avoid errors at DST boundaries
total := time.Now().UTC().Sub(core[StartUTC].(time.Time))
core[Duration] = total
core[Overhead] = total
if origin, ok := core[OriginDuration]; ok {
core[Overhead] = total - origin.(time.Duration)
}
fields := logrus.Fields{}
for k, v := range logDataTable.Core {
if l.fields.Keep(k) {
fields[k] = v
}
}
l.redactHeaders(logDataTable.Request, fields, "request_")
l.redactHeaders(logDataTable.OriginResponse, fields, "origin_")
l.redactHeaders(logDataTable.DownstreamResponse, fields, "downstream_")
l.mu.Lock()
defer l.mu.Unlock()
l.logger.WithFields(fields).Println()
}
}
func (l *LogHandler) redactHeaders(headers http.Header, fields logrus.Fields, prefix string) {
for k := range headers {
v := l.fields.KeepHeader(k)
if v == types.AccessLogKeep {
fields[prefix+k] = headers.Get(k)
} else if v == types.AccessLogRedact {
fields[prefix+k] = "REDACTED"
}
}
}
// n.b. take care to perform time arithmetic using UTC to avoid errors at DST boundaries
total := time.Now().UTC().Sub(core[StartUTC].(time.Time))
core[Duration] = total
if origin, ok := core[OriginDuration]; ok {
core[Overhead] = total - origin.(time.Duration)
} else {
core[Overhead] = total
func (l *LogHandler) keepAccessLog(status int) bool {
if l.httpCodeRanges == nil {
return true
}
fields := logrus.Fields{}
for k, v := range logDataTable.Core {
fields[k] = v
for _, block := range l.httpCodeRanges {
if status >= block[0] && status <= block[1] {
return true
}
}
for k := range logDataTable.Request {
fields["request_"+k] = logDataTable.Request.Get(k)
}
for k := range logDataTable.OriginResponse {
fields["origin_"+k] = logDataTable.OriginResponse.Get(k)
}
for k := range logDataTable.DownstreamResponse {
fields["downstream_"+k] = logDataTable.DownstreamResponse.Get(k)
}
l.mu.Lock()
defer l.mu.Unlock()
l.logger.WithFields(fields).Println()
return false
}
//-------------------------------------------------------------------------------------------------