From 29f0cf354ca4cb6df2e41a5810d579c98831e768 Mon Sep 17 00:00:00 2001 From: Luis Neto Date: Tue, 10 Dec 2024 09:53:13 -0800 Subject: [PATCH] TUN-8783: fix log collectors for the diagnostic procedure ## Summary * The host log collector now verifies if the OS is linux and has systemd if so it will use journalctl to get the logs * In linux systems docker will write the output of the command logs to the stderr therefore the function that handles the execution of the process will copy both the contents of stdout and stderr; this also affect the k8s collector Closes TUN-8783 --- diagnostic/log_collector_host.go | 36 +++++++++++++++++++++++++++++-- diagnostic/log_collector_utils.go | 23 ++++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/diagnostic/log_collector_host.go b/diagnostic/log_collector_host.go index cd50c87d..5218e975 100644 --- a/diagnostic/log_collector_host.go +++ b/diagnostic/log_collector_host.go @@ -4,13 +4,16 @@ import ( "context" "fmt" "os" + "os/exec" "path/filepath" "runtime" ) const ( - linuxManagedLogsPath = "/var/log/cloudflared.err" - darwinManagedLogsPath = "/Library/Logs/com.cloudflare.cloudflared.err.log" + linuxManagedLogsPath = "/var/log/cloudflared.err" + darwinManagedLogsPath = "/Library/Logs/com.cloudflare.cloudflared.err.log" + linuxServiceConfigurationPath = "/etc/systemd/system/cloudflared.service" + linuxSystemdPath = "/run/systemd/system" ) type HostLogCollector struct { @@ -23,6 +26,28 @@ func NewHostLogCollector(client HTTPClient) *HostLogCollector { } } +func extractLogsFromJournalCtl(ctx context.Context) (*LogInformation, error) { + tmp := os.TempDir() + + outputHandle, err := os.Create(filepath.Join(tmp, logFilename)) + if err != nil { + return nil, fmt.Errorf("error opening output file: %w", err) + } + + defer outputHandle.Close() + + command := exec.CommandContext( + ctx, + "journalctl", + "--since", + "2 weeks ago", + "-u", + "cloudflared.service", + ) + + return PipeCommandOutputToFile(command, outputHandle) +} + func getServiceLogPath() (string, error) { switch runtime.GOOS { case "darwin": @@ -55,6 +80,13 @@ func (collector *HostLogCollector) Collect(ctx context.Context) (*LogInformation } if logConfiguration.uid == 0 { + _, statSystemdErr := os.Stat(linuxServiceConfigurationPath) + + _, statServiceConfigurationErr := os.Stat(linuxServiceConfigurationPath) + if statSystemdErr == nil && statServiceConfigurationErr == nil && runtime.GOOS == "linux" { + return extractLogsFromJournalCtl(ctx) + } + path, err := getServiceLogPath() if err != nil { return nil, err diff --git a/diagnostic/log_collector_utils.go b/diagnostic/log_collector_utils.go index 889ca30a..728b5298 100644 --- a/diagnostic/log_collector_utils.go +++ b/diagnostic/log_collector_utils.go @@ -12,7 +12,16 @@ func PipeCommandOutputToFile(command *exec.Cmd, outputHandle *os.File) (*LogInfo stdoutReader, err := command.StdoutPipe() if err != nil { return nil, fmt.Errorf( - "error retrieving output from command '%s': %w", + "error retrieving stdout from command '%s': %w", + command.String(), + err, + ) + } + + stderrReader, err := command.StderrPipe() + if err != nil { + return nil, fmt.Errorf( + "error retrieving stderr from command '%s': %w", command.String(), err, ) @@ -29,7 +38,17 @@ func PipeCommandOutputToFile(command *exec.Cmd, outputHandle *os.File) (*LogInfo _, err = io.Copy(outputHandle, stdoutReader) if err != nil { return nil, fmt.Errorf( - "error copying output from %s to file %s: %w", + "error copying stdout from %s to file %s: %w", + command.String(), + outputHandle.Name(), + err, + ) + } + + _, err = io.Copy(outputHandle, stderrReader) + if err != nil { + return nil, fmt.Errorf( + "error copying stderr from %s to file %s: %w", command.String(), outputHandle.Name(), err,