Skip to content
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

Fix traefik logs to behave like configured #2176

Merged
merged 5 commits into from
Oct 11, 2017

Conversation

m3co-code
Copy link
Contributor

@m3co-code m3co-code commented Sep 26, 2017

This PR accomplishes two things:

  1. it makes sure that all traefik logs are written in the specified format. Before the first log messages were written in text, even when you specified JSON as the format. This is because some log output was produced before configuring the logs.
  2. it makes sure that all traefik logs are written to the traefik logs file. This is implemented by using logrus.Exit() and by closing the file in a logrus.RegisterExitHandler.

I also changed that errors from http.Serve and http.ServeTLS are not logged anymore, in the case they are regular http.ErrServerClosed errors, which is expected and the normal case. Those methods will never return a non-nil error.

This fixes #2156.

@timoreimann
Copy link
Contributor

Do we know why simply deferring isn't enough? Is this possibly related to a missed flush or a missing close? (I don't know if flushing stdout is even possible, just throwing around wild guesses here.)

@m3co-code
Copy link
Contributor Author

Yes, I checked that deferring is not enough. This is basically the first example I have written in the description above (# sample of log output with closing log file).

Frankly speaking, I also don't understand yet why this does not work. AFAICS the run function is executed in the main go routine and thus when it exits, everything should exit. So my understanding of go. The output that is printed to stdout, given we close the log file in a defer of run is from other goroutines like listenSignals. I am currently digging deeper to find the reason for this.

@m3co-code
Copy link
Contributor Author

m3co-code commented Sep 26, 2017

@timoreimann I was able to build a solution that captures all output by using logrus.RegisterExitHandler. This way we can close the files properly and still catch all the output.

After having implemented this, there was surprisingly still output written to the stdout. Namely this: {"level":"error","msg":"Error creating server: http: Server closed","time":"2017-09-26T09:57:15+02:00"}. I had a look into the code and this is actually confusing in my opinion. This is the error returned from the http.Serve or http.ServeTLS which always return a non-nil error. I changed the logic in 20e4471 to output only real errors in order to avoid confusion and this way, we now have no more output on the stdout 🎉

Updating PR description right now.

@ldez
Copy link
Contributor

ldez commented Sep 26, 2017

Please undo the refactoring. (We can speak about this on Slack)
If it's a bug fix move the PR to 1.4 branch. (maybe split your PR in two)

@m3co-code
Copy link
Contributor Author

@ldez and @juliens I changed and rebased the PR now according to our discussion. This was basically to keep the run method agnostic of the traefikConfiguration. PR is ready for review.

Copy link
Member

@juliens juliens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😉

// Try to fallback to traefik config file in case the file provider is enabled
// but it has no file name configured.
if fileProviderEnabled && len(globalConfiguration.File.Filename) == 0 && traefikConfigFileExists {
globalConfiguration.File.Filename = traefikConfiguration.ConfigFile
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move this code in the run func, and use the "new" config file param

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went one step further and pushed it down to SetEffectiveConfiguration as it fits there best IMO.


if globalConfiguration.Debug {
globalConfiguration.LogLevel = "DEBUG"
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code should be in setEffectiveConfiguration ? WDYT

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about that. The docs of SetEffectiveConfiguration states:

SetEffectiveConfiguration adds missing configuration parameters derived from existing ones. It also takes care of maintaining backwards compatibility.

In my perception, this is actually not the case. LogLevel is not a missing configuration parameter. It's meant to be this way.

Additionally SetEffectiveConfiguration is called after configureLogging, and that is for the good reason that the logging configuration should happen as first thing in order to achieve what this PR tries to achieve. Log all messages in the desired format and write them to a file if it is configured.

logFile := globalConfiguration.TraefikLogsFile
if len(logFile) > 0 {
log.Warn("top-level traefiklogsfile has been deprecated -- please use traefiklog.filepath")
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code should be in setEffectiveConfiguration and change the globalConfiguration.TraefikLog value ? WDYT

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, for the same reasons stated it in #2176 (comment).

@m3co-code
Copy link
Contributor Author

@juliens I commented/addressed all your comments. PTAL again :-)

@ldez
Copy link
Contributor

ldez commented Oct 2, 2017

configuration/configuration_test.go:244:32: not enough arguments in call to gc.SetEffectiveConfiguration
	have ()
	want (string)

@m3co-code
Copy link
Contributor Author

Ups. Will fix Wednesday morning probably. Holiday :D

@m3co-code
Copy link
Contributor Author

m3co-code commented Oct 4, 2017

@ldez @juliens PTAL again. I fixed the test failure and while doing this I realized it would be valuable to add a new test case for SetEffectiveConfiguration. So I did that.

Copy link
Contributor

@nmengin nmengin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👏 🗞️

Copy link
Contributor

@ldez ldez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -223,8 +211,23 @@ Complete documentation is available at https://traefik.io`,
os.Exit(0)
}

func run(globalConfiguration *configuration.GlobalConfiguration) {
fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags)
func run(traefikConfiguration *TraefikConfiguration) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use high order function (and rename):

func runTraefikCmd(traefikConfiguration *TraefikConfiguration) func() error {
        return func() error {
	    globalConfiguration := &traefikConfiguration.GlobalConfiguration
           // ...
     }
}
	traefikConfiguration := NewTraefikConfiguration()
	traefikPointersConfiguration := NewTraefikDefaultPointersConfiguration()
	//traefik Command init
	traefikCmd := &flaeg.Command{
		Name: "traefik",
		Description: `traefik is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
Complete documentation is available at https://traefik.io`,
		Config:                traefikConfiguration,
		DefaultPointersConfig: traefikPointersConfiguration,
		Run: runTraefikCmd(traefikConfiguration),
	}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something I should address in a follow-up PR?

Also, can you explain a bit the benefit you see in this? We were discussing with @juliens that you want to keep run function to not know anything about the traefikConfiguration, because of a future feature you were working on. Is this still aligned with this effort?

The functions http.Serve and http.ServeTLS always return a non-nil
error. In the "success" case, when the server is closed normally, they
return ErrServerClosed. So we should only log when it is not that error.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Capture all Traefik Log output in file
6 participants