From bd8191c2d25b3ba2b4d8e0abdf2b61fb147f33fa Mon Sep 17 00:00:00 2001 From: Anilkumar18 Date: Mon, 4 Aug 2025 15:53:41 +0530 Subject: [PATCH] lcpex enhancements - modified json log file format --- src/lcpex/liblcpex.cpp | 94 ++++++++++++++++++++------------- src/lcpex/liblcpex.h | 8 ++- src/lcpex/vpty/libclpex_tty.cpp | 85 ++++++++++++++++------------- src/lcpex/vpty/libclpex_tty.h | 4 +- src/logger/Logger.cpp | 22 ++++++-- src/logger/Logger.h | 3 +- src/plan/Task.cpp | 12 +++-- 7 files changed, 141 insertions(+), 87 deletions(-) diff --git a/src/lcpex/liblcpex.cpp b/src/lcpex/liblcpex.cpp index db79c19..dc88d49 100644 --- a/src/lcpex/liblcpex.cpp +++ b/src/lcpex/liblcpex.cpp @@ -13,6 +13,10 @@ static Logger logger(E_INFO, "lcpex"); std::string user = logger.get_user_name(); std::string group = logger.get_group_name(); +// Global variables for signal handler context +static std::string g_task_context = ""; +static std::string g_log_directory = ""; + void signal_handler(int sig) { std::string command = "signal_handler"; // Command context @@ -20,20 +24,24 @@ void signal_handler(int sig) { // Log the signal handling if (sig == SIGCHLD) { // Log that SIGCHLD was received, but leave the exit status to the parent - logger.log_to_json_file("E_INFO", "SIGCHLD received. A child process ended.", user, group, command); + logger.log_to_json_file("E_INFO", "SIGCHLD received. A child process ended.", user, group, command, g_task_context, g_log_directory); } else if (sig == SIGINT) { - logger.log_to_json_file("E_FATAL", "SIGINT received. Gracefully terminating...", user, group, command); + logger.log_to_json_file("E_FATAL", "SIGINT received. Gracefully terminating...", user, group, command, g_task_context, g_log_directory); } else if (sig == SIGTERM) { - logger.log_to_json_file("E_FATAL", "SIGTERM received. Terminating...", user, group, command); + logger.log_to_json_file("E_FATAL", "SIGTERM received. Terminating...", user, group, command, g_task_context, g_log_directory); } else if (sig == SIGSEGV) { - logger.log_to_json_file("E_FATAL", "SIGSEGV received. Possible segmentation fault.", user, group, command); + logger.log_to_json_file("E_FATAL", "SIGSEGV received. Possible segmentation fault.", user, group, command, g_task_context, g_log_directory); } else { - logger.log_to_json_file("E_FATAL", "Unhandled signal received", user, group, command); + logger.log_to_json_file("E_FATAL", "Unhandled signal received", user, group, command, g_task_context, g_log_directory); } } // Setup signal registrations -void setup_signal_handlers() { +void setup_signal_handlers(std::string task_context = "", std::string log_directory = "") { + // Set global variables for signal handler context + g_task_context = task_context; + g_log_directory = log_directory; + struct sigaction sa; sa.sa_handler = signal_handler; // <-- handler function sigemptyset(&sa.sa_mask); @@ -43,25 +51,25 @@ void setup_signal_handlers() { // SIGCHLD if (sigaction(SIGCHLD, &sa, nullptr) == -1) { std::string error_message = "Failed to set SIGCHLD handler: " + std::string(strerror(errno)); - logger.log_to_json_file("E_FATAL", error_message, user, group, command); // Log to JSON file + logger.log_to_json_file("E_FATAL", error_message, user, group, command, task_context, log_directory); // Log to JSON file } // SIGINT if (sigaction(SIGINT, &sa, nullptr) == -1) { std::string error_message = "Failed to set SIGINT handler: " + std::string(strerror(errno)); - logger.log_to_json_file("E_FATAL", error_message, user, group, command); // Log to JSON file + logger.log_to_json_file("E_FATAL", error_message, user, group, command, task_context, log_directory); // Log to JSON file } // SIGTERM if (sigaction(SIGTERM, &sa, nullptr) == -1) { std::string error_message = "Failed to set SIGTERM handler: " + std::string(strerror(errno)); - logger.log_to_json_file("E_FATAL", error_message, user, group, command); // Log to JSON file + logger.log_to_json_file("E_FATAL", error_message, user, group, command, task_context, log_directory); // Log to JSON file } // SIGSEGV if (sigaction(SIGSEGV, &sa, nullptr) == -1) { std::string error_message = "Failed to set SIGSEGV handler: " + std::string(strerror(errno)); - logger.log_to_json_file("E_FATAL", error_message, user, group, command); // Log to JSON file + logger.log_to_json_file("E_FATAL", error_message, user, group, command, task_context, log_directory); // Log to JSON file } } @@ -72,7 +80,9 @@ std::string prefix_generator( std::string shell_execution_arg, bool supply_environment, std::string shell_source_subcommand, - std::string environment_file_path + std::string environment_file_path, + std::string task_context, + std::string log_directory ) { std::string prefix = ""; if ( is_shell_command ) { @@ -103,7 +113,7 @@ std::string prefix_generator( } // Log the message to JSON file - logger.log_to_json_file("E_INFO", "LAUNCHER: " + prefix, user, group, command); + logger.log_to_json_file("E_INFO", "LAUNCHER: " + prefix, user, group, command, task_context, log_directory); //logger.log(E_INFO, "LAUNCHER: " + prefix); return prefix; @@ -123,7 +133,9 @@ int lcpex( std::string shell_execution_arg, bool supply_environment, std::string shell_source_subcommand, - std::string environment_file_path + std::string environment_file_path, + std::string task_context, + std::string log_directory ) { // generate the prefix @@ -134,19 +146,21 @@ int lcpex( shell_execution_arg, supply_environment, shell_source_subcommand, - environment_file_path + environment_file_path, + task_context, + log_directory ); command = prefix; - setup_signal_handlers(); + setup_signal_handlers(task_context, log_directory); // if we are forcing a pty, then we will use the vpty library if( force_pty ) { - return exec_pty( command, stdout_log_fh, stderr_log_fh, context_override, context_user, context_group, supply_environment ); + return exec_pty( command, stdout_log_fh, stderr_log_fh, context_override, context_user, context_group, supply_environment, task_context, log_directory ); } // otherwise, we will use the execute function - return execute( command, stdout_log_fh, stderr_log_fh, context_override, context_user, context_group, supply_environment ); + return execute( command, stdout_log_fh, stderr_log_fh, context_override, context_user, context_group, supply_environment, task_context, log_directory ); } /** @@ -158,14 +172,14 @@ int lcpex( * * @param fd The file descriptor for which to set the close-on-exec flag */ -void set_cloexec_flag(int fd) +void set_cloexec_flag(int fd, std::string task_context = "", std::string log_directory = "") { std::string command = "set_cloexec_flag"; if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { std::string error_message = "fcntl(F_SETFD) failed for fd " + std::to_string(fd); - logger.log_to_json_file("E_FATAL", error_message, user, group, command); + logger.log_to_json_file("E_FATAL", error_message, user, group, command, task_context, log_directory); throw std::runtime_error("fcntl(F_SETFD) failed for fd " + std::to_string(fd)); } @@ -195,7 +209,7 @@ void set_cloexec_flag(int fd) * Finally, the child process calls execvp() with the processed_command to run the shell command. * If the execvp() function fails, an error message is displayed. */ -void run_child_process(bool context_override, const char* context_user, const char* context_group, char* processed_command[], int fd_child_stdout_pipe[], int fd_child_stderr_pipe[]) { +void run_child_process(bool context_override, const char* context_user, const char* context_group, char* processed_command[], int fd_child_stdout_pipe[], int fd_child_stderr_pipe[], std::string task_context = "", std::string log_directory = "") { while ((dup2(fd_child_stdout_pipe[WRITE_END], STDOUT_FILENO) == -1) && (errno == EINTR)) {} while ((dup2(fd_child_stderr_pipe[WRITE_END], STDERR_FILENO) == -1) && (errno == EINTR)) {} // Close unused pipe ends to avoid leaks @@ -213,33 +227,33 @@ void run_child_process(bool context_override, const char* context_user, const ch break; case IDENTITY_CONTEXT_ERRORS::ERROR_NO_SUCH_USER: logger.log(E_FATAL, "Aborting: context user not found: " + std::string(context_user)); - logger.log_to_json_file("E_FATAL", "Aborting: context user not found: " + std::string(context_user), user, group, command); + logger.log_to_json_file("E_FATAL", "Aborting: context user not found: " + std::string(context_user), user, group, command, task_context, log_directory); _exit(1); break; case IDENTITY_CONTEXT_ERRORS::ERROR_NO_SUCH_GROUP: logger.log(E_FATAL, "Aborting: context group not found: " + std::string(context_group)); - logger.log_to_json_file("E_FATAL", "Aborting: context group not found: " + std::string(context_group), user, group, command); + logger.log_to_json_file("E_FATAL", "Aborting: context group not found: " + std::string(context_group), user, group, command, task_context, log_directory); _exit(1); break; case IDENTITY_CONTEXT_ERRORS::ERROR_SETGID_FAILED: logger.log(E_FATAL, "Aborting: Setting GID failed: " + std::string(context_user) + "/" + std::string(context_group)); - logger.log_to_json_file("E_FATAL", "Aborting: Setting GID failed: " + std::string(context_user) + "/" + std::string(context_group), user, group, command); + logger.log_to_json_file("E_FATAL", "Aborting: Setting GID failed: " + std::string(context_user) + "/" + std::string(context_group), user, group, command, task_context, log_directory); _exit(1); break; case IDENTITY_CONTEXT_ERRORS::ERROR_SETUID_FAILED: logger.log(E_FATAL, "Aborting: Setting UID failed: " + std::string(context_user) + "/" + std::string(context_group)); - logger.log_to_json_file("E_FATAL", "Aborting: Setting UID failed: " + std::string(context_user) + "/" + std::string(context_group), user, group, command); + logger.log_to_json_file("E_FATAL", "Aborting: Setting UID failed: " + std::string(context_user) + "/" + std::string(context_group), user, group, command, task_context, log_directory); _exit(1); break; default: logger.log(E_FATAL, "Aborting: Unknown error while setting identity context."); - logger.log_to_json_file("E_FATAL", "Aborting: Unknown error while setting identity context.", user, group, command); + logger.log_to_json_file("E_FATAL", "Aborting: Unknown error while setting identity context.", user, group, command, task_context, log_directory); _exit(1); break; } } int exit_code = execvp(processed_command[0], processed_command); - logger.log_to_json_file("E_FATAL", "failed on execvp in child", user, group, command); + logger.log_to_json_file("E_FATAL", "failed on execvp in child", user, group, command, task_context, log_directory); logger.log(E_FATAL, "failed on execvp in child"); _Exit(exit_code); } @@ -251,7 +265,9 @@ int execute( bool context_override, std::string context_user, std::string context_group, - bool environment_supplied + bool environment_supplied, + std::string task_context, + std::string log_directory ){ try { @@ -286,10 +302,10 @@ int execute( } // using O_CLOEXEC to ensure that the child process closes the file descriptors - set_cloexec_flag( fd_child_stdout_pipe[READ_END] ); - set_cloexec_flag( fd_child_stderr_pipe[READ_END] ); - set_cloexec_flag( fd_child_stdout_pipe[WRITE_END] ); - set_cloexec_flag( fd_child_stderr_pipe[WRITE_END] ); + set_cloexec_flag( fd_child_stdout_pipe[READ_END], task_context, log_directory ); + set_cloexec_flag( fd_child_stderr_pipe[READ_END], task_context, log_directory ); + set_cloexec_flag( fd_child_stdout_pipe[WRITE_END], task_context, log_directory ); + set_cloexec_flag( fd_child_stderr_pipe[WRITE_END], task_context, log_directory ); // status result basket for the parent process to capture the child's exit status int status; @@ -300,7 +316,7 @@ int execute( { // fork failed logger.log(E_FATAL, "fork failure: " + std::string(strerror(errno))); - logger.log_to_json_file("E_FATAL", "fork failure: " + std::string(strerror(errno)), user, group, command); + logger.log_to_json_file("E_FATAL", "fork failure: " + std::string(strerror(errno)), user, group, command, task_context, log_directory); close(fd_child_stdout_pipe[0]); // Pipe Leaks on Error Paths close(fd_child_stdout_pipe[1]); // Pipe Leaks on Error Paths close(fd_child_stderr_pipe[0]); // Pipe Leaks on Error Paths @@ -317,7 +333,9 @@ int execute( context_group.c_str(), processed_command, fd_child_stdout_pipe, - fd_child_stderr_pipe + fd_child_stderr_pipe, + task_context, + log_directory ); } @@ -376,7 +394,7 @@ int execute( if (num_files_readable == -1) { // error occurred in poll() logger.log(E_FATAL, "poll() failed: " + std::string(strerror(errno))); - logger.log_to_json_file("E_FATAL", "poll() failed", user, group, command); + logger.log_to_json_file("E_FATAL", "poll() failed", user, group, command, task_context, log_directory); throw std::runtime_error("poll() failed"); } if (num_files_readable == 0) { @@ -393,7 +411,7 @@ int execute( if (errno == EAGAIN) { continue; } else { // error reading from pipe logger.log(E_FATAL, "Error while reading: " + std::string(strerror(errno))); - logger.log_to_json_file("E_FATAL", "Error while reading from pipe", user, group, command); + logger.log_to_json_file("E_FATAL", "Error while reading from pipe", user, group, command, task_context, log_directory); stdout_read_guard.reset(-1); stderr_read_guard.reset(-1); exit(EXIT_FAILURE); @@ -457,13 +475,13 @@ int execute( if (WIFEXITED(status)) { int exit_code = WEXITSTATUS(status); logger.log(E_INFO, "Child exited with status " + std::to_string(exit_code)); - logger.log_to_json_file("E_INFO", "Child exited with status " + std::to_string(exit_code), user, group, command); + logger.log_to_json_file("E_INFO", "Child exited with status " + std::to_string(exit_code), user, group, command, task_context, log_directory); } // Check if the child process was terminated by a signal else if (WIFSIGNALED(status)) { int signal_number = WTERMSIG(status); logger.log(E_FATAL, "Process terminated by signal: " + std::to_string(signal_number)); - logger.log_to_json_file("E_FATAL", "Process terminated by signal: " + std::to_string(signal_number), user, group, command); + logger.log_to_json_file("E_FATAL", "Process terminated by signal: " + std::to_string(signal_number), user, group, command, task_context, log_directory); // Reset signal handler to default before exiting signal(signal_number, SIG_DFL); // Return 128 + signal number as the exit code for signal termination @@ -472,7 +490,7 @@ int execute( // Handle unexpected exit conditions else { logger.log(E_WARN, "Unknown child exit condition."); - logger.log_to_json_file("E_WARN", "Unknown child exit condition", user, group, command); + logger.log_to_json_file("E_WARN", "Unknown child exit condition", user, group, command, task_context, log_directory); } } } diff --git a/src/lcpex/liblcpex.h b/src/lcpex/liblcpex.h index f958661..7e7d147 100644 --- a/src/lcpex/liblcpex.h +++ b/src/lcpex/liblcpex.h @@ -44,7 +44,9 @@ int execute( bool context_override, std::string context_user, std::string context_group, - bool environment_supplied + bool environment_supplied, + std::string task_context = "", + std::string log_directory = "" ); @@ -87,7 +89,9 @@ int lcpex( std::string shell_execution_arg, bool supply_environment, std::string shell_source_subcommand, - std::string environment_file_path + std::string environment_file_path, + std::string task_context = "", + std::string log_directory = "" ); /** diff --git a/src/lcpex/vpty/libclpex_tty.cpp b/src/lcpex/vpty/libclpex_tty.cpp index 72f47bf..f1b3fd0 100644 --- a/src/lcpex/vpty/libclpex_tty.cpp +++ b/src/lcpex/vpty/libclpex_tty.cpp @@ -12,6 +12,9 @@ static Logger tty_logger(E_INFO, "lcpex_tty"); std::string tty_user = tty_logger.get_user_name(); std::string tty_group = tty_logger.get_group_name(); +// Global variables for signal handler context +static std::string g_tty_task_context = ""; +static std::string g_tty_log_directory = ""; void tty_signal_handler(int sig) { std::string command = "tty_signal_handler"; // Command context @@ -19,19 +22,23 @@ void tty_signal_handler(int sig) { // Log the signal handling if (sig == SIGCHLD) { // Log that SIGCHLD was received, but leave the exit status to the parent - tty_logger.log_to_json_file("E_INFO", "SIGCHLD received. A child process ended.", tty_user, tty_group, command); + tty_logger.log_to_json_file("E_INFO", "SIGCHLD received. A child process ended.", tty_user, tty_group, command, g_tty_task_context, g_tty_log_directory); } else if (sig == SIGINT) { - tty_logger.log_to_json_file("E_FATAL", "SIGINT received. Gracefully terminating...", tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "SIGINT received. Gracefully terminating...", tty_user, tty_group, command, g_tty_task_context, g_tty_log_directory); } else if (sig == SIGTERM) { - tty_logger.log_to_json_file("E_FATAL", "SIGTERM received. Terminating...", tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "SIGTERM received. Terminating...", tty_user, tty_group, command, g_tty_task_context, g_tty_log_directory); } else if (sig == SIGSEGV) { - tty_logger.log_to_json_file("E_FATAL", "SIGSEGV received. Possible segmentation fault.", tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "SIGSEGV received. Possible segmentation fault.", tty_user, tty_group, command, g_tty_task_context, g_tty_log_directory); } else { - tty_logger.log_to_json_file("E_FATAL", "Unhandled signal received", tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "Unhandled signal received", tty_user, tty_group, command, g_tty_task_context, g_tty_log_directory); } } // Setup signal registrations -void setup_tty_signal_handlers() { +void setup_tty_signal_handlers(std::string task_context = "", std::string log_directory = "") { + // Set global variables for signal handler context + g_tty_task_context = task_context; + g_tty_log_directory = log_directory; + struct sigaction sa; sa.sa_handler = tty_signal_handler; // <-- handler function sigemptyset(&sa.sa_mask); @@ -41,25 +48,25 @@ void setup_tty_signal_handlers() { // SIGCHLD if (sigaction(SIGCHLD, &sa, nullptr) == -1) { std::string error_message = "Failed to set SIGCHLD handler: " + std::string(strerror(errno)); - tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command); // Log to JSON file + tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command, task_context, log_directory); // Log to JSON file } // SIGINT if (sigaction(SIGINT, &sa, nullptr) == -1) { std::string error_message = "Failed to set SIGINT handler: " + std::string(strerror(errno)); - tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command); // Log to JSON file + tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command, task_context, log_directory); // Log to JSON file } // SIGTERM if (sigaction(SIGTERM, &sa, nullptr) == -1) { std::string error_message = "Failed to set SIGTERM handler: " + std::string(strerror(errno)); - tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command); // Log to JSON file + tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command, task_context, log_directory); // Log to JSON file } // SIGSEGV if (sigaction(SIGSEGV, &sa, nullptr) == -1) { std::string error_message = "Failed to set SIGSEGV handler: " + std::string(strerror(errno)); - tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command); // Log to JSON file + tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command, task_context, log_directory); // Log to JSON file } } @@ -75,21 +82,21 @@ void setup_tty_signal_handlers() { * Finally, the function exits the program with exit code 1. */ -void set_tty_cloexec_flag(int fd) +void set_tty_cloexec_flag(int fd, std::string task_context = "", std::string log_directory = "") { std::string command = "set_tty_cloexec_flag"; if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { std::string error_message = "fcntl(F_SETFD) failed for fd " + std::to_string(fd); - tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, command, task_context, log_directory); throw std::runtime_error("fcntl(F_SETFD) failed for fd " + std::to_string(fd)); } } -void safe_perror( const char * msg, struct termios * ttyOrig ) +void safe_perror( const char * msg, struct termios * ttyOrig, std::string task_context = "", std::string log_directory = "" ) { std::string command = "safe_perror"; // Command context - tty_logger.log_to_json_file("E_FATAL", msg, tty_user, tty_group, command); // Log the message before exiting + tty_logger.log_to_json_file("E_FATAL", msg, tty_user, tty_group, command, task_context, log_directory); // Log the message before exiting std::cerr << msg << std::endl; ttyResetExit( ttyOrig ); throw std::runtime_error(std::string("TTY Error: ") + msg); @@ -118,7 +125,7 @@ void safe_perror( const char * msg, struct termios * ttyOrig ) * Finally, the function executes the command specified in `processed_command` using `execvp()`. * If the execution of `execvp()` fails, the function calls `safe_perror()` to print a message and exit the program. */ -void run_child_process( int fd_child_stderr_pipe[2], char * processed_command[], struct termios * ttyOrig, bool context_override, std::string context_user, std::string context_group ) +void run_child_process( int fd_child_stderr_pipe[2], char * processed_command[], struct termios * ttyOrig, bool context_override, std::string context_user, std::string context_group, std::string task_context = "", std::string log_directory = "" ) { std::string command = "run_child_process_tty"; // Command context // redirect stderr to the write end of the stderr pipe @@ -138,27 +145,27 @@ void run_child_process( int fd_child_stderr_pipe[2], char * processed_command[], break; case IDENTITY_CONTEXT_ERRORS::ERROR_NO_SUCH_USER: tty_logger.log(E_FATAL, "Aborting: context user not found: " + context_user); - tty_logger.log_to_json_file("E_FATAL", "Context user not found: " + context_user, tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "Context user not found: " + context_user, tty_user, tty_group, command, task_context, log_directory); _exit(1); break; case IDENTITY_CONTEXT_ERRORS::ERROR_NO_SUCH_GROUP: tty_logger.log(E_FATAL, "Aborting: context group not found: " + context_group); - tty_logger.log_to_json_file("E_FATAL", "Context group not found: " + context_group, tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "Context group not found: " + context_group, tty_user, tty_group, command, task_context, log_directory); _exit(1); break; case IDENTITY_CONTEXT_ERRORS::ERROR_SETGID_FAILED: tty_logger.log(E_FATAL, "Aborting: Setting GID failed: " + context_user + "/" + context_group); - tty_logger.log_to_json_file("E_FATAL", "Setting GID failed for: " + context_user + "/" + context_group, tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "Setting GID failed for: " + context_user + "/" + context_group, tty_user, tty_group, command, task_context, log_directory); _exit(1); break; case IDENTITY_CONTEXT_ERRORS::ERROR_SETUID_FAILED: tty_logger.log(E_FATAL, "Aborting: Setting UID failed: " + context_user + "/" + context_group); - tty_logger.log_to_json_file("E_FATAL", "Setting UID failed for: " + context_user + "/" + context_group, tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "Setting UID failed for: " + context_user + "/" + context_group, tty_user, tty_group, command, task_context, log_directory); _exit(1); break; default: tty_logger.log(E_FATAL, "Aborting: Unknown error while setting identity context."); - tty_logger.log_to_json_file("E_FATAL", "Unknown error while setting identity context.", tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "Unknown error while setting identity context.", tty_user, tty_group, command, task_context, log_directory); _exit(1); break; } @@ -167,7 +174,7 @@ void run_child_process( int fd_child_stderr_pipe[2], char * processed_command[], // execute the dang command, print to stdout, stderr (of parent), and dump to file for each!!!! // (and capture exit code in parent) int exit_code = execvp( processed_command[0], processed_command ); - tty_logger.log_to_json_file("E_FATAL", "failed on execvp in child", tty_user, tty_group, command); + tty_logger.log_to_json_file("E_FATAL", "failed on execvp in child", tty_user, tty_group, command, task_context, log_directory); tty_logger.log(E_FATAL, "failed on execvp in child"); _Exit(exit_code); @@ -184,13 +191,15 @@ int exec_pty( bool context_override, std::string context_user, std::string context_group, - bool environment_supplied + bool environment_supplied, + std::string task_context, + std::string log_directory ) { try { std::string exec_command = "exec_pty"; // Command context - tty_logger.log_to_json_file("E_INFO", "TTY LAUNCHER: " + command, tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_INFO", "TTY LAUNCHER: " + command, tty_user, tty_group, exec_command, task_context, log_directory); // Setup signal handlers - setup_tty_signal_handlers(); + setup_tty_signal_handlers(task_context, log_directory); // initialize the terminal settings obj struct termios ttyOrig; @@ -205,12 +214,12 @@ int exec_pty( char ** processed_command = expand_env( command ); if ( stdout_log_fh == NULL ) { - tty_logger.log_to_json_file("E_FATAL", "Error opening STDOUT log file. Aborting.", tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_FATAL", "Error opening STDOUT log file. Aborting.", tty_user, tty_group, exec_command, task_context, log_directory); throw std::runtime_error("Error opening STDOUT log file"); } if ( stderr_log_fh == NULL ) { - tty_logger.log_to_json_file("E_FATAL", "Error opening STDERR log file. Aborting.", tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_FATAL", "Error opening STDERR log file. Aborting.", tty_user, tty_group, exec_command, task_context, log_directory); throw std::runtime_error("Error opening STDERR log file"); } @@ -220,12 +229,12 @@ int exec_pty( if ( pipe( fd_child_stderr_pipe ) == -1 ) { std::string error_message = "Failed to create stderr pipe: " + std::string(strerror(errno)); - tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_FATAL", error_message, tty_user, tty_group, exec_command, task_context, log_directory); throw std::runtime_error("Failed to create stderr pipe"); } // using O_CLOEXEC to ensure that the child process closes the file descriptors - set_tty_cloexec_flag( fd_child_stderr_pipe[READ_END] ); - set_tty_cloexec_flag( fd_child_stderr_pipe[WRITE_END] ); + set_tty_cloexec_flag( fd_child_stderr_pipe[READ_END], task_context, log_directory ); + set_tty_cloexec_flag( fd_child_stderr_pipe[WRITE_END], task_context, log_directory ); // status result basket for the parent process to capture the child's exit status int status = 616; @@ -236,14 +245,14 @@ int exec_pty( /* Retrieve the attributes of terminal on which we are started */ if (tcgetattr(STDIN_FILENO, &ttyOrig) == -1){ - tty_logger.log_to_json_file("E_FATAL", "tcgetattr failed", tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_FATAL", "tcgetattr failed", tty_user, tty_group, exec_command, task_context, log_directory); close(fd_child_stderr_pipe[READ_END]); // Pipe Leaks on Error Paths close(fd_child_stderr_pipe[WRITE_END]); // Pipe Leaks on Error Paths throw std::runtime_error("tcgetattr failed"); } if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) { - tty_logger.log_to_json_file("E_FATAL", "ioctl-TIOCGWINSZ failed", tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_FATAL", "ioctl-TIOCGWINSZ failed", tty_user, tty_group, exec_command, task_context, log_directory); close(fd_child_stderr_pipe[READ_END]); // Pipe Leaks on Error Paths close(fd_child_stderr_pipe[WRITE_END]); // Pipe Leaks on Error Paths throw std::runtime_error("ioctl-TIOCGWINSZ failed"); @@ -254,7 +263,7 @@ int exec_pty( { // fork failed tty_logger.log(E_FATAL, "ptyfork failure: " + std::string(strerror(errno))); - tty_logger.log_to_json_file("E_FATAL", "ptyfork failure: " + std::string(strerror(errno)), tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_FATAL", "ptyfork failure: " + std::string(strerror(errno)), tty_user, tty_group, exec_command, task_context, log_directory); close(fd_child_stderr_pipe[READ_END]); // Pipe Leaks on Error Paths close(fd_child_stderr_pipe[WRITE_END]); // Pipe Leaks on Error Paths throw std::runtime_error("ptyfork() failed: " + std::string(strerror(errno))); @@ -262,7 +271,7 @@ int exec_pty( case 0: { // child process - run_child_process( fd_child_stderr_pipe, processed_command, &ttyOrig, context_override, context_user, context_group ); + run_child_process( fd_child_stderr_pipe, processed_command, &ttyOrig, context_override, context_user, context_group, task_context, log_directory ); } default: { @@ -320,7 +329,7 @@ int exec_pty( if (num_files_readable == -1) { // error occurred in poll() tty_logger.log(E_FATAL, "poll() failed: " + std::string(strerror(errno))); - tty_logger.log_to_json_file("E_FATAL", "poll() failed", tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_FATAL", "poll() failed", tty_user, tty_group, exec_command, task_context, log_directory); ttyResetExit( &ttyOrig); throw std::runtime_error("poll() failed"); } @@ -340,7 +349,7 @@ int exec_pty( if (errno == EAGAIN) { continue; } else { // error reading from pipe tty_logger.log(E_FATAL, "Error while reading: " + std::string(strerror(errno))); - tty_logger.log_to_json_file("E_FATAL", "Error while reading from pipe", tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_FATAL", "Error while reading from pipe", tty_user, tty_group, exec_command, task_context, log_directory); ttyResetExit( &ttyOrig); stderr_read_guard.reset(-1); master_fd_guard.reset(-1); @@ -415,7 +424,7 @@ int exec_pty( if (WIFEXITED(status)) { int exit_code = WEXITSTATUS(status); tty_logger.log(E_INFO, "Child exited with status " + std::to_string(exit_code)); - tty_logger.log_to_json_file("E_INFO", "Child exited with status " + std::to_string(exit_code), tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_INFO", "Child exited with status " + std::to_string(exit_code), tty_user, tty_group, exec_command, task_context, log_directory); ttyResetExit( &ttyOrig); return exit_code; } @@ -423,7 +432,7 @@ int exec_pty( else if (WIFSIGNALED(status)) { int signal_number = WTERMSIG(status); tty_logger.log(E_FATAL, "Process terminated by signal: " + std::to_string(signal_number)); - tty_logger.log_to_json_file("E_FATAL", "Process terminated by signal: " + std::to_string(signal_number), tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_FATAL", "Process terminated by signal: " + std::to_string(signal_number), tty_user, tty_group, exec_command, task_context, log_directory); // Reset signal handler to default before exiting signal(signal_number, SIG_DFL); ttyResetExit( &ttyOrig); @@ -432,7 +441,7 @@ int exec_pty( // Handle unexpected exit conditions else { tty_logger.log(E_WARN, "Unknown child exit condition."); - tty_logger.log_to_json_file("E_WARN", "Unknown child exit condition", tty_user, tty_group, exec_command); + tty_logger.log_to_json_file("E_WARN", "Unknown child exit condition", tty_user, tty_group, exec_command, task_context, log_directory); } } diff --git a/src/lcpex/vpty/libclpex_tty.h b/src/lcpex/vpty/libclpex_tty.h index 328cf8f..407d165 100644 --- a/src/lcpex/vpty/libclpex_tty.h +++ b/src/lcpex/vpty/libclpex_tty.h @@ -43,7 +43,9 @@ int exec_pty( bool context_override, std::string context_user, std::string context_group, - bool environment_supplied + bool environment_supplied, + std::string task_context = "", + std::string log_directory = "" ); diff --git a/src/logger/Logger.cpp b/src/logger/Logger.cpp index 5fe2dfd..37518ff 100644 --- a/src/logger/Logger.cpp +++ b/src/logger/Logger.cpp @@ -129,7 +129,8 @@ std::string Logger::get_current_timestamp() //Log to JSON file void Logger::log_to_json_file(const std::string& log_level, const std::string& message, const std::string& user, const std::string& group, - const std::string& command, bool log_to_console) + const std::string& command, const std::string& task_context, + const std::string& log_directory, bool log_to_console) { // Log to console if requested const char* log_level_str = "UNKNOWN"; @@ -148,9 +149,22 @@ void Logger::log_to_json_file(const std::string& log_level, const std::string& m char json_log[2048]; create_json_log_entry(json_log, sizeof(json_log), log_level_str, message.c_str(), user.c_str(), group.c_str(), command.c_str()); - // 3. Generate filename - std::string timestamp = get_current_timestamp(); - std::string filename = "log_" + timestamp + ".json"; + // 3. Generate filename with format: YYYY-MM-DD_context.log.json + std::string filename; + if (!task_context.empty() && !log_directory.empty()) { + // Use task-specific directory and format + time_t now = time(NULL); + struct tm* timeinfo = localtime(&now); + char date_buffer[16]; + strftime(date_buffer, sizeof(date_buffer), "%Y-%m-%d", timeinfo); + std::string date_str = std::string(date_buffer); + + filename = log_directory + "/" + task_context + "/" + date_str + "_" + task_context + ".log.json"; + } else { + // Fallback to original format for backward compatibility + std::string timestamp = get_current_timestamp(); + filename = "log_" + timestamp + ".json"; + } // 4. Use FdGuard for file handling (to manage file opening and closing) FdGuard check_file(open(filename.c_str(), O_RDONLY)); diff --git a/src/logger/Logger.h b/src/logger/Logger.h index ea79b5f..5e3af7d 100644 --- a/src/logger/Logger.h +++ b/src/logger/Logger.h @@ -51,7 +51,8 @@ class Logger { void log_task(int LOG_LEVEL, std::string task_name, std::string msg); void log_to_json_file(const std::string& log_level, const std::string& message, const std::string& user, const std::string& group, - const std::string& command, bool log_to_console = true); + const std::string& command, const std::string& task_context = "", + const std::string& log_directory = "", bool log_to_console = true); // Helper methods std::string get_current_timestamp(); std::string get_user_name(); diff --git a/src/plan/Task.cpp b/src/plan/Task.cpp index 6263388..e96d8ad 100644 --- a/src/plan/Task.cpp +++ b/src/plan/Task.cpp @@ -470,7 +470,9 @@ void Task::execute( Conf * configuration ) shell_definition.execution_arg, supply_environment, shell_definition.source_cmd, - environment_file + environment_file, + task_name, + logs_root ); // ********************************************** @@ -539,7 +541,9 @@ void Task::execute( Conf * configuration ) shell_definition.execution_arg, supply_environment, shell_definition.source_cmd, - environment_file + environment_file, + task_name, + logs_root ); // ********************************************** @@ -591,7 +595,9 @@ void Task::execute( Conf * configuration ) shell_definition.execution_arg, supply_environment, shell_definition.source_cmd, - environment_file + environment_file, + task_name, + logs_root ); // **********************************************