Ultimate Access log filter
This commit is contained in:
parent
f99363674b
commit
8d468925d3
24 changed files with 1722 additions and 683 deletions
|
@ -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
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue