From db0556b062ef365e6d25e6ec416d3f0ce7b20e9f Mon Sep 17 00:00:00 2001 From: Rodolfo Olivieri Date: Thu, 3 Aug 2023 15:29:39 -0300 Subject: [PATCH 1/3] Add setup for sos report SOS Report needs a special file in the /etc/sos.extras.d/ folder to be able to collect the log files for the worker. Since it won't have a special plugin in sosreport due to RHEL 7 being in maintenance mode, we will be using this strategy to make sure that sosreport will be able to collect our logs. Signed-off-by: Rodolfo Olivieri --- src/logger.go | 28 +++++++++++++++++++++++++++- src/logger_test.go | 29 +++++++++++++++++++++++++++++ src/main.go | 11 ++++++++--- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/logger.go b/src/logger.go index 5cfbbc3..3e71cf2 100644 --- a/src/logger.go +++ b/src/logger.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "io" "os" "path" @@ -22,8 +23,9 @@ func setupLogger(logFolder string, fileName string) *os.File { } } + logFilePath := path.Join(logFolder, fileName) // open log file - logFile, err := os.Create(path.Join(logFolder, fileName)) + logFile, err := os.Create(logFilePath) if err != nil { log.Error(err) } @@ -52,3 +54,27 @@ func setupLogger(logFolder string, fileName string) *os.File { return logFile } + +// setupSosExtrasReport sets up the sos report file for the sos_extra plugin to +// collect the logs for the worker, which is a special file that points out to +// the current path of the logfile for the worker. +func setupSosExtrasReport(logFolder string, logFileName string, fileContent string) { + // Check if path exists, if not, create it. + if _, err := os.Stat(logFolder); err != nil { + if err := os.Mkdir(logFolder, os.ModePerm); err != nil { + log.Error(err) + } + } + + // open sosreport file + logFile, err := os.Create(path.Join(logFolder, logFileName)) + if err != nil { + log.Error(err) + } + defer logFile.Close() + + content := fmt.Sprintf(":%s", fileContent) + if _, err := logFile.WriteString(content); err != nil { + log.Error(err) + } +} diff --git a/src/logger_test.go b/src/logger_test.go index ea2de56..511868c 100644 --- a/src/logger_test.go +++ b/src/logger_test.go @@ -1,7 +1,9 @@ package main import ( + "fmt" "os" + "path" "path/filepath" "testing" @@ -81,3 +83,30 @@ func TestSetupLogger(t *testing.T) { }) } } + +func TestSetupSosExtrasReport(t *testing.T) { + // Create a temporary directory for the log folder + logFolder := t.TempDir() + logFileName := "log-file" + fileContent := path.Join(logFolder, logFileName, "test-file") + expectedFileContent := fmt.Sprintf(":%s", fileContent) + // defer os.RemoveAll(logFolder) + + setupSosExtrasReport(logFolder, logFileName, fileContent) + if _, err := os.Stat(logFolder); os.IsNotExist(err) { + t.Errorf("Log folder not created: %v", err) + } + + logFilePath := filepath.Join(logFolder, logFileName) + if _, err := os.Stat(logFilePath); os.IsNotExist(err) { + t.Errorf("SOS report file not created: %v", err) + } + + logFile, err := os.ReadFile(logFilePath) + if err != nil { + t.Errorf("Failed to read file: %v", err) + } + if string(logFile) != expectedFileContent { + t.Errorf("File content does not match") + } +} diff --git a/src/main.go b/src/main.go index 6556087..25aa8d9 100644 --- a/src/main.go +++ b/src/main.go @@ -4,6 +4,7 @@ import ( "context" "net" "os" + "path" "time" "git.sr.ht/~spc/go-log" @@ -17,13 +18,16 @@ import ( const configFilePath = "/etc/rhc/workers/rhc-worker-bash.yml" const logDir = "/var/log/rhc-worker-bash" const logFileName = "rhc-worker-bash.log" +const sosReportFolder = "/etc/sos.extras.d" +const sosReportFile = "rhc-worker-logs" var yggdDispatchSocketAddr string var config *Config -// main is the entry point of the application. It initializes values from the environment, -// sets up the logger, establishes a connection with the dispatcher, registers as a handler, -// listens for incoming messages, and starts accepting connections as a Worker service. +// main is the entry point of the application. It initializes values from the +// environment, sets up the logger, establishes a connection with the +// dispatcher, registers as a handler, listens for incoming messages, and +// starts accepting connections as a Worker service. // Note: The function blocks and runs indefinitely until the server is stopped. func main() { var yggSocketAddrExists bool // Has to be separately declared otherwise grpc.Dial doesn't work @@ -37,6 +41,7 @@ func main() { logFile := setupLogger(logDir, logFileName) defer logFile.Close() + setupSosExtrasReport(sosReportFolder, sosReportFile, path.Join(logDir, logFileName)) // Dial the dispatcher on its well-known address. conn, err := grpc.Dial( From 5f82d1185d154c031626248d8521c1b6c9031813 Mon Sep 17 00:00:00 2001 From: Rodolfo Olivieri Date: Fri, 4 Aug 2023 09:59:18 -0300 Subject: [PATCH 2/3] Add suggestions from review Signed-off-by: Rodolfo Olivieri --- src/logger.go | 24 ++++++++++++------------ src/logger_test.go | 16 ++++++++-------- src/main.go | 4 ---- src/util.go | 14 ++++++++++++++ 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/logger.go b/src/logger.go index 3e71cf2..fc4bfa1 100644 --- a/src/logger.go +++ b/src/logger.go @@ -9,6 +9,9 @@ import ( "git.sr.ht/~spc/go-log" ) +var sosReportFolder = "/etc/sos.extras.d" +var sosReportFile = "rhc-worker-logs" + // SetupLogger sets up the logger for the application and returns the log file. // It creates a log folder if it doesn't exist, opens a log file, sets the log level // based on the "YGG_LOG_LEVEL" environment variable, configures the log output to @@ -16,11 +19,8 @@ import ( // such as date-time, filename, and line number. // Returns a pointer to an os.File representing the opened log file. func setupLogger(logFolder string, fileName string) *os.File { - // Check if path exists, if not, create it. - if _, err := os.Stat(logFolder); err != nil { - if err := os.Mkdir(logFolder, os.ModePerm); err != nil { - log.Error(err) - } + if err := checkAndCreateDirectory(logFolder); err != nil { + log.Error(err) } logFilePath := path.Join(logFolder, fileName) @@ -45,6 +45,9 @@ func setupLogger(logFolder string, fileName string) *os.File { log.SetLevel(log.LevelInfo) } + // Initialization for the sosreport extras plugin + setupSosExtrasReport(logFilePath) + // set log output multWriter := io.MultiWriter(os.Stdout, logFile) log.SetOutput(multWriter) @@ -58,16 +61,13 @@ func setupLogger(logFolder string, fileName string) *os.File { // setupSosExtrasReport sets up the sos report file for the sos_extra plugin to // collect the logs for the worker, which is a special file that points out to // the current path of the logfile for the worker. -func setupSosExtrasReport(logFolder string, logFileName string, fileContent string) { - // Check if path exists, if not, create it. - if _, err := os.Stat(logFolder); err != nil { - if err := os.Mkdir(logFolder, os.ModePerm); err != nil { - log.Error(err) - } +func setupSosExtrasReport(fileContent string) { + if err := checkAndCreateDirectory(sosReportFolder); err != nil { + log.Error(err) } // open sosreport file - logFile, err := os.Create(path.Join(logFolder, logFileName)) + logFile, err := os.Create(path.Join(sosReportFolder, sosReportFile)) if err != nil { log.Error(err) } diff --git a/src/logger_test.go b/src/logger_test.go index 511868c..139303e 100644 --- a/src/logger_test.go +++ b/src/logger_test.go @@ -85,19 +85,19 @@ func TestSetupLogger(t *testing.T) { } func TestSetupSosExtrasReport(t *testing.T) { - // Create a temporary directory for the log folder - logFolder := t.TempDir() - logFileName := "log-file" - fileContent := path.Join(logFolder, logFileName, "test-file") + // FIXME: We are overriding the globals for the below variables, not the + // best approach, but works for now. + sosReportFile = "log-file" + sosReportFolder = t.TempDir() + fileContent := path.Join(sosReportFolder, sosReportFile, "test-file") expectedFileContent := fmt.Sprintf(":%s", fileContent) - // defer os.RemoveAll(logFolder) - setupSosExtrasReport(logFolder, logFileName, fileContent) - if _, err := os.Stat(logFolder); os.IsNotExist(err) { + setupSosExtrasReport(fileContent) + if _, err := os.Stat(sosReportFolder); os.IsNotExist(err) { t.Errorf("Log folder not created: %v", err) } - logFilePath := filepath.Join(logFolder, logFileName) + logFilePath := filepath.Join(sosReportFolder, sosReportFile) if _, err := os.Stat(logFilePath); os.IsNotExist(err) { t.Errorf("SOS report file not created: %v", err) } diff --git a/src/main.go b/src/main.go index 25aa8d9..13c828f 100644 --- a/src/main.go +++ b/src/main.go @@ -4,7 +4,6 @@ import ( "context" "net" "os" - "path" "time" "git.sr.ht/~spc/go-log" @@ -18,8 +17,6 @@ import ( const configFilePath = "/etc/rhc/workers/rhc-worker-bash.yml" const logDir = "/var/log/rhc-worker-bash" const logFileName = "rhc-worker-bash.log" -const sosReportFolder = "/etc/sos.extras.d" -const sosReportFile = "rhc-worker-logs" var yggdDispatchSocketAddr string var config *Config @@ -41,7 +38,6 @@ func main() { logFile := setupLogger(logDir, logFileName) defer logFile.Close() - setupSosExtrasReport(sosReportFolder, sosReportFile, path.Join(logDir, logFileName)) // Dial the dispatcher on its well-known address. conn, err := grpc.Dial( diff --git a/src/util.go b/src/util.go index fca3471..85f302d 100644 --- a/src/util.go +++ b/src/util.go @@ -156,3 +156,17 @@ func loadConfigOrDefault(filePath string) *Config { setDefaultValues(config) return config } + +// Helper function to check if a directory exists, if not, create the +// directory, otherwise, return nil. If it fails to create the directory, the +// function will return the error raised by `os.Mkdir` to the caller. +func checkAndCreateDirectory(folder string) error { + // Check if path exists, if not, create it. + if _, err := os.Stat(folder); err != nil { + if err := os.Mkdir(folder, os.ModePerm); err != nil { + return err + } + } + + return nil +} From 4fe7c2eaed8e7852e5dd1a2b6baf5cb649bbf6ab Mon Sep 17 00:00:00 2001 From: Rodolfo Olivieri Date: Mon, 7 Aug 2023 10:53:19 -0300 Subject: [PATCH 3/3] Update setupSosExtrasReport * Update parameter for setupSosExtrasReport to match what is being passed to the function. * Include a comment to specify what is the expected format for the sosreport file Signed-off-by: Rodolfo Olivieri --- src/logger.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/logger.go b/src/logger.go index fc4bfa1..4cdc017 100644 --- a/src/logger.go +++ b/src/logger.go @@ -61,19 +61,21 @@ func setupLogger(logFolder string, fileName string) *os.File { // setupSosExtrasReport sets up the sos report file for the sos_extra plugin to // collect the logs for the worker, which is a special file that points out to // the current path of the logfile for the worker. -func setupSosExtrasReport(fileContent string) { +func setupSosExtrasReport(logFilePath string) { if err := checkAndCreateDirectory(sosReportFolder); err != nil { log.Error(err) } - // open sosreport file logFile, err := os.Create(path.Join(sosReportFolder, sosReportFile)) if err != nil { log.Error(err) } defer logFile.Close() - content := fmt.Sprintf(":%s", fileContent) + // sosreport expects that the file content will be in the following format: + // ":/path/to/your/log/file.{log,txt,...}", this will trigger sosreport to + // collect the file without the need to have a special plugin in sosreport. + content := fmt.Sprintf(":%s", logFilePath) if _, err := logFile.WriteString(content); err != nil { log.Error(err) }