From 447dbbba06aa1f00387d0b48f4128f5d961f3ead Mon Sep 17 00:00:00 2001 From: kisunji Date: Thu, 6 Jan 2022 14:33:35 -0500 Subject: [PATCH 1/4] Fix Windows logging to files --- command/agent/agent.go | 5 ++++- logging/logger.go | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/command/agent/agent.go b/command/agent/agent.go index 1525c2819639..90b389782869 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -162,7 +162,10 @@ func (c *cmd) run(args []string) int { // FIXME: logs should always go to stderr, but previously they were sent to // stdout, so continue to use Stdout for now, and fix this in a future release. - logGate := &logging.GatedWriter{Writer: c.ui.Stdout()} + // UiWriter is being used here so that writes to Stdout do not error (e.g. + // Windows Services are non-interactive and do not have Stdout) and inadvertently + // stop writes to other logging outputs like syslogs or log files. + logGate := &logging.GatedWriter{Writer: &mcli.UiWriter{Ui: c.ui}} loader := func(source config.Source) (config.LoadResult, error) { c.configLoadOpts.DefaultConfig = source return config.Load(c.configLoadOpts) diff --git a/logging/logger.go b/logging/logger.go index dfc05785cf45..bf8861999f39 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -27,16 +27,16 @@ type Config struct { // SyslogFacility is the destination for syslog forwarding. SyslogFacility string - //LogFilePath is the path to write the logs to the user specified file. + // LogFilePath is the path to write the logs to the user specified file. LogFilePath string - //LogRotateDuration is the user specified time to rotate logs + // LogRotateDuration is the user specified time to rotate logs LogRotateDuration time.Duration - //LogRotateBytes is the user specified byte limit to rotate logs + // LogRotateBytes is the user specified byte limit to rotate logs LogRotateBytes int - //LogRotateMaxFiles is the maximum number of past archived log files to keep + // LogRotateMaxFiles is the maximum number of past archived log files to keep LogRotateMaxFiles int } From 15b396d563d2d63aff739f37ea948371ccd0de21 Mon Sep 17 00:00:00 2001 From: kisunji Date: Thu, 6 Jan 2022 14:45:55 -0500 Subject: [PATCH 2/4] Add changelog --- .changelog/11960.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/11960.txt diff --git a/.changelog/11960.txt b/.changelog/11960.txt new file mode 100644 index 000000000000..aac5bd422e15 --- /dev/null +++ b/.changelog/11960.txt @@ -0,0 +1,3 @@ +```release-note:bug +windows: Fixes a bug with empty log files when Consul is run as a Windows Service +``` \ No newline at end of file From 2917d0e0fd6fa7c24d6ce73d07377ecf5fa28bb3 Mon Sep 17 00:00:00 2001 From: kisunji Date: Thu, 6 Jan 2022 15:32:09 -0500 Subject: [PATCH 3/4] Use a wrapper instead of UiWriter --- command/agent/agent.go | 5 +---- logging/logger.go | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/command/agent/agent.go b/command/agent/agent.go index 90b389782869..1525c2819639 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -162,10 +162,7 @@ func (c *cmd) run(args []string) int { // FIXME: logs should always go to stderr, but previously they were sent to // stdout, so continue to use Stdout for now, and fix this in a future release. - // UiWriter is being used here so that writes to Stdout do not error (e.g. - // Windows Services are non-interactive and do not have Stdout) and inadvertently - // stop writes to other logging outputs like syslogs or log files. - logGate := &logging.GatedWriter{Writer: &mcli.UiWriter{Ui: c.ui}} + logGate := &logging.GatedWriter{Writer: c.ui.Stdout()} loader := func(source config.Source) (config.LoadResult, error) { c.configLoadOpts.DefaultConfig = source return config.Load(c.configLoadOpts) diff --git a/logging/logger.go b/logging/logger.go index bf8861999f39..1d570c8a8d7f 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -45,6 +45,16 @@ const defaultRotateDuration = 24 * time.Hour type LogSetupErrorFn func(string) +// noErrorWriter is a wrapper to suppress errors when writing to w. +type noErrorWriter struct { + w io.Writer +} + +func (w noErrorWriter) Write(p []byte) (n int, err error) { + n, _ = w.w.Write(p) + return n, nil +} + // Setup logging from Config, and return an hclog Logger. // // Logs may be written to out, and optionally to syslog, and a file. @@ -55,7 +65,10 @@ func Setup(config Config, out io.Writer) (hclog.InterceptLogger, error) { allowedLogLevels) } - writers := []io.Writer{out} + // If out is os.Stdout and Consul is being run as a Windows Service, writes will + // fail silently, which may inadvertently prevent writes to other writers. + // noErrorWriter is used as a wrapper to suppress any errors when writing to out. + writers := []io.Writer{noErrorWriter{w: out}} if config.EnableSyslog { retries := 12 From 9864f9bf4f567e0dc63361da11e79fb3a148d4dd Mon Sep 17 00:00:00 2001 From: kisunji Date: Thu, 6 Jan 2022 15:49:53 -0500 Subject: [PATCH 4/4] Always return len(p) --- logging/logger.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/logging/logger.go b/logging/logger.go index 1d570c8a8d7f..9d6cff74f454 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -51,8 +51,9 @@ type noErrorWriter struct { } func (w noErrorWriter) Write(p []byte) (n int, err error) { - n, _ = w.w.Write(p) - return n, nil + _, _ = w.w.Write(p) + // We purposely return n == len(p) as if write was successful + return len(p), nil } // Setup logging from Config, and return an hclog Logger.