-
Notifications
You must be signed in to change notification settings - Fork 5.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Switch access logging to logrus #1647
Conversation
2812422
to
84a8bdc
Compare
84a8bdc
to
98523e0
Compare
@@ -544,7 +541,6 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo | |||
redirectHandlers := make(map[string]negroni.Handler) | |||
backends := map[string]http.Handler{} | |||
backendsHealthcheck := map[string]*healthcheck.BackendHealthCheck{} | |||
backend2FrontendMap := map[string]string{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why you have remove this line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the backend to frontend map was only used by the old logger. The new framework, added during a previous PR, uses accesslog.NewSaveBackend
and accesslog.NewSaveFrontend
to achieve the same thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @rjshep !
Thanks a lot for this new (smaller) PR :)
I would like to suggest a design change.
In order to remove all if l.logger != nil
from logger.go
: NewLogHandler
should return an error in case fileName
is empty. And we should not add this middleware into the chain in this use case.
Could you also remove saveBackend
& saveFrontend
middlewares from server.go
when we don't have access logs enabled?
I also made few comments/suggestions in the code :)
|
||
timestamp := entry.Data[StartUTC].(time.Time).Format(commonLogTimeFormat) | ||
elapsedMillis := entry.Data[Duration].(time.Duration).Nanoseconds() / 1000000 | ||
referer := entry.Data["request_Referer"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe there is a constant in standard lib or in lorgus ?
if referer == nil { | ||
referer = "" | ||
} | ||
userAgent := entry.Data["request_User-Agent"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe there is a constant in standard lib or in lorgus ?
} | ||
|
||
return "-" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYT of this kind of refactoring?
func toLogString(v interface{}) string {
defaultValue := "-"
if v == nil {
return defaultValue
}
switch s := v.(type) {
case string:
return quoted(s, defaultValue)
case fmt.Stringer:
return quoted(s.String(), defaultValue)
default:
return defaultValue
}
}
func quoted(s string, defaultValue string) string {
if len(s) == 0 {
return defaultValue
}
return `"` + s + `"`
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM I've added it in. It has meant that the log format is not fully backward compatible. Referer and User Agent fields are now specified as a hyphen if not present, previously they were just missing. I believe the new format is actually correct, however.
8d4399e
to
05ab100
Compare
Hi @emilevauge I've made the requested changes. Thanks for the design change, that is a better solution :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I left a few comments.
c.Assert(regexp.MustCompile(`^\d+ms$`).MatchString(tokens[12]), checker.True) | ||
c.Assert(tokens[10], checker.Equals, fmt.Sprintf("%d", i+1)) | ||
c.Assert(strings.HasPrefix(tokens[11], "frontend"), checker.True) | ||
c.Assert(strings.HasPrefix(tokens[12], "http://127.0.0.1:808"), checker.True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comprehension question: why do we have to change the indices?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Referer and User Agent fields are now specified as a hyphen if not present, previously they were just missing. I believe the new format is actually correct, however.
middlewares/accesslog/logger.go
Outdated
@@ -23,11 +29,34 @@ const ( | |||
// Note: Current implementation collects log data but does not have the facility to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this comment still valid?
middlewares/accesslog/logger.go
Outdated
} | ||
|
||
// NewLogHandler creates a new LogHandler | ||
func NewLogHandler() *LogHandler { | ||
return &LogHandler{} | ||
func NewLogHandler(fileName string) (*LogHandler, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit-pick: I'd probably call the variable filePath
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done :-)
middlewares/accesslog/logger.go
Outdated
dir := filepath.Dir(fileName) | ||
|
||
err := os.MkdirAll(dir, 0755) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be merged with previous line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
middlewares/accesslog/logger.go
Outdated
|
||
err := os.MkdirAll(dir, 0755) | ||
if err != nil { | ||
log.Errorf("Failed to create log path %s: %s", dir, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we return an error here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
middlewares/accesslog/logger.go
Outdated
|
||
file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0664) | ||
if err != nil { | ||
log.Error("Error opening file", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we return an error instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
middlewares/accesslog/logger.go
Outdated
return &LogHandler{logger: logger, file: file}, nil | ||
} | ||
|
||
return nil, errors.New("Empty file name specified for accessLogsFile") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this return at the very top of the file, right after a check for fileName == ""
. That way, we can save one level of indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
middlewares/accesslog/logger_test.go
Outdated
@@ -47,16 +42,15 @@ func TestLogger(t *testing.T) { | |||
|
|||
logfilePath := filepath.Join(tmp, logfileNameSuffix) | |||
|
|||
logger = NewLogger(logfilePath) | |||
logger, err = NewLogHandler(logfilePath) | |||
assert.NoError(t, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have added testify.require
by now. Please use it here and wherever continuation of a test does not make sense anymore in case of a failed assertion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job!!! 🎉
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One tiny thing left. :-)
middlewares/accesslog/logger.go
Outdated
dir := filepath.Dir(filePath) | ||
|
||
if err := os.MkdirAll(dir, 0755); err != nil { | ||
log.Errorf("Failed to create log path %s: %s", dir, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging an error and returning an error normally do not go together; instead, we should return an error containing sufficient context and let the caller log.
Could you please pass the (de-capitalized) log message content to an fmt.Errorf
call and just return that?
Same for lines 48:49.
974d1f0
to
147b9b0
Compare
@timoreimann change made and commits squashed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks a lot!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rjshep Just 2 minor comments :)
Other than that looks good!
middlewares/accesslog/logger.go
Outdated
@@ -85,6 +110,7 @@ func (l *LogHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next h | |||
|
|||
// Close closes the Logger (i.e. the file etc). | |||
func (l *LogHandler) Close() error { | |||
l.file.Close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be return l.file.Close()
;)
server/server.go
Outdated
server.loggerMiddleware.Close() | ||
server.accessLoggerMiddleware.Close() | ||
if server.accessLoggerMiddleware != nil { | ||
server.accessLoggerMiddleware.Close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should check the return error here.
147b9b0
to
6ee1a2b
Compare
Thanks @emilevauge. Changes made :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @rjshep for this great PR!
We really appreciate your exemplary attitude 👏 👏 👏
Building on some initial work to introduce a new access logging framework, this PR uses logrus as the log handler to write access logs using information collected in the log data table.
A logrus Formatter implements Traefik Common Log Format producing logs which are backward compatible with the current access logs.
Also includes applicable changes from #1507