changeset 25:b8a514c97fb7

Bug 1849: HeapStats agent should collect systemd-journald information reviewed-by: yasuenag
author KUBOTA Yuji <kubota.yuji@lab.ntt.co.jp>
date Fri, 20 Jun 2014 11:58:32 +0900
parents a3d52921b48f
children 8008ab68f482
files agent/ChangeLog agent/src/logManager.cpp
diffstat 2 files changed, 78 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/agent/ChangeLog	Thu Jun 19 00:01:36 2014 +0900
+++ b/agent/ChangeLog	Fri Jun 20 11:58:32 2014 +0900
@@ -1,3 +1,7 @@
+2014-06-20  KUBOTA Yuji  <kubota.yuji@lab.ntt.co.jp>
+
+	* Bug 1849: HeapStats agent should collect systemd-journald information
+
 2014-06-18  Yasumasa Suenaga  <yasuenag@gmail.com>
 
 	* Bug 1683: HeapStats agent should be adapted to JDK-8027746
--- a/agent/src/logManager.cpp	Thu Jun 19 00:01:36 2014 +0900
+++ b/agent/src/logManager.cpp	Fri Jun 20 11:58:32 2014 +0900
@@ -31,6 +31,7 @@
 #include <limits.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <dirent.h>
 #include <errno.h>
 
@@ -1250,8 +1251,6 @@
         /* Netstat infomation. */
         "/proc/net/tcp", "/proc/net/tcp6",
         "/proc/net/udp", "/proc/net/udp6",
-        /* Syslog. */
-        "/var/log/messages",
         /* End flag. */
         {0}
   };
@@ -1277,7 +1276,79 @@
     }
 
   }
- 
+
+  /* Collect Syslog or Systemd-Journald */
+  /*
+   * Try to copy syslog at first, because journal daemon will forward all received
+   * log messages to a traditional syslog by default.
+   */
+  result = copyFile("/var/log/messages", basePath);
+  if (unlikely(result != 0)) {
+    PRINT_WARN_MSG_AND_ERRNO("Failure copy file. path:\"/var/log/messages\"", result);
+    /* If disk is full. */
+    if(unlikely(isRaisedDiskFull(result))){
+      return result;
+    }
+  }
+
+  /* Collect systemd-journald instead of syslog when failed to copy syslog, */
+  if (result != 0) {
+    /*
+     * Select vfork() to run journalctl in a separate process. Unlikely system(),
+     * this function does not block SIGINT, et al. Unlikely fork(), this function
+     * does not copy but shares all memory with its parent, including the stack.
+     */
+    pid_t child = vfork();
+    if ( child == 0 ) {
+      /* Child process */
+      /* logfile name shows what command is used to output it.*/
+      char logfile[PATH_MAX];
+      sprintf(logfile, "%s%s", basePath, "/journalctl_-q_--all_--this-boot_--no-pager_-o_verbose.log");
+      /* Redirect child process' stdout/stderr to logfile */
+      int fd = open(logfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+      if (dup2(fd, 1) < 0) {
+        close(fd);
+        _exit(errno);
+      } if (dup2(fd, 2) < 0) {
+        close(fd);
+        _exit(errno);
+      }
+      close(fd);
+      /* Use execve() for journalctl to prevent command injection */
+      const char * argv[] = {"journalctl", "-q", "--all", "--this-boot", "--no-pager", "-o", "verbose", NULL};
+      extern char **environ;
+      execve("/bin/journalctl", (char* const*)argv, environ);
+      /* if execve returns, it has failed */
+      _exit(errno);
+    } else if(child < 0) {
+      /* vfork failed */
+      result = errno;
+      PRINT_WARN_MSG_AND_ERRNO("Failure collect systemd-journald log by vfork().", result);
+    } else {
+      /* Parent process */
+      int status;
+      if (waitpid(child, &status, 0) < 0) {
+        /* The child process failed. */
+        result = errno;
+        PRINT_WARN_MSG_AND_ERRNO("Failure collect systemd-journald log by process error.", result);
+        /* If disk is full. */
+        if(unlikely(isRaisedDiskFull(result))){
+          return result;
+        }
+      }
+      if (WIFEXITED(status)) {
+        /* The child exited normally, get the returns as result. */
+        result = WEXITSTATUS(status);
+        if (result != 0) {
+          PRINT_WARN_MSG_AND_ERRNO("Failure collect systemd-journald log.", result);
+        }
+      } else {
+        /* The child exited with a signal or unknown exit code. */
+        PRINT_WARN_MSG("Failure collect systemd-journald log by signal or unknown exit code.");
+      }
+    }
+  }
+
   /* Copy stdout */
   result = copyFile("/proc/self/fd/1", basePath, "fd1");
   if(unlikely(result != 0)){