From 46dc6316f9fddb81e68f580c9e9337539e7628f9 Mon Sep 17 00:00:00 2001 From: Luis Neto Date: Wed, 27 Nov 2024 03:15:15 -0800 Subject: [PATCH] TUN-8734: add log collection for kubernetes ## Summary Adds the log collector for K8s based deployments. Closes TUN-8734 --- diagnostic/log_collector_docker.go | 38 +--------------- diagnostic/log_collector_kubernetes.go | 63 ++++++++++++++++++++++++++ diagnostic/log_collector_utils.go | 47 +++++++++++++++++++ 3 files changed, 111 insertions(+), 37 deletions(-) create mode 100644 diagnostic/log_collector_kubernetes.go create mode 100644 diagnostic/log_collector_utils.go diff --git a/diagnostic/log_collector_docker.go b/diagnostic/log_collector_docker.go index b14bf41e..f87a9534 100644 --- a/diagnostic/log_collector_docker.go +++ b/diagnostic/log_collector_docker.go @@ -3,7 +3,6 @@ package diagnostic import ( "context" "fmt" - "io" "os" "os/exec" "path/filepath" @@ -44,40 +43,5 @@ func (collector *DockerLogCollector) Collect(ctx context.Context) (*LogInformati collector.containerID, ) - stdoutReader, err := command.StdoutPipe() - if err != nil { - return nil, fmt.Errorf( - "error retrieving output from command '%s': %w", - command.String(), - err, - ) - } - - if err := command.Start(); err != nil { - return nil, fmt.Errorf( - "error running command '%s': %w", - command.String(), - err, - ) - } - - _, err = io.Copy(outputHandle, stdoutReader) - if err != nil { - return nil, fmt.Errorf( - "error copying output from %s to file %s: %w", - command.String(), - outputHandle.Name(), - err, - ) - } - - if err := command.Wait(); err != nil { - return nil, fmt.Errorf( - "error waiting from command '%s': %w", - command.String(), - err, - ) - } - - return NewLogInformation(outputHandle.Name(), true, false), nil + return PipeCommandOutputToFile(command, outputHandle) } diff --git a/diagnostic/log_collector_kubernetes.go b/diagnostic/log_collector_kubernetes.go new file mode 100644 index 00000000..881a988c --- /dev/null +++ b/diagnostic/log_collector_kubernetes.go @@ -0,0 +1,63 @@ +package diagnostic + +import ( + "context" + "fmt" + "os" + "os/exec" + "path/filepath" + "time" +) + +type KubernetesLogCollector struct { + containerID string // This member identifies the container by identifier or name + pod string // This member identifies the pod where the container is deployed +} + +func NewKubernetesLogCollector(containerID, pod string) *KubernetesLogCollector { + return &KubernetesLogCollector{ + containerID, + pod, + } +} + +func (collector *KubernetesLogCollector) Collect(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() + + var command *exec.Cmd + // Calculate 2 weeks ago + since := time.Now().Add(twoWeeksOffset).Format(time.RFC3339) + if collector.containerID != "" { + command = exec.CommandContext( + ctx, + "kubectl", + "logs", + collector.pod, + "--since-time=", + since, + "--tail=", + tailMaxNumberOfLines, + "-c", + collector.containerID, + ) + } else { + command = exec.CommandContext( + ctx, + "kubectl", + "logs", + collector.pod, + "--since-time=", + since, + "--tail=", + tailMaxNumberOfLines, + ) + } + + return PipeCommandOutputToFile(command, outputHandle) +} diff --git a/diagnostic/log_collector_utils.go b/diagnostic/log_collector_utils.go new file mode 100644 index 00000000..d746cde4 --- /dev/null +++ b/diagnostic/log_collector_utils.go @@ -0,0 +1,47 @@ +package diagnostic + +import ( + "fmt" + "io" + "os" + "os/exec" +) + +func PipeCommandOutputToFile(command *exec.Cmd, outputHandle *os.File) (*LogInformation, error) { + stdoutReader, err := command.StdoutPipe() + if err != nil { + return nil, fmt.Errorf( + "error retrieving output from command '%s': %w", + command.String(), + err, + ) + } + + if err := command.Start(); err != nil { + return nil, fmt.Errorf( + "error running command '%s': %w", + command.String(), + err, + ) + } + + _, err = io.Copy(outputHandle, stdoutReader) + if err != nil { + return nil, fmt.Errorf( + "error copying output from %s to file %s: %w", + command.String(), + outputHandle.Name(), + err, + ) + } + + if err := command.Wait(); err != nil { + return nil, fmt.Errorf( + "error waiting from command '%s': %w", + command.String(), + err, + ) + } + + return NewLogInformation(outputHandle.Name(), true, false), nil +}