changeset 85:d0b7a759116d

Bug 2113: [ADD CONFIG] Add switch to output HeapStats messages to logfile. reviewed-by: yasuenag
author KUBOTA Yuji <kubota.yuji@lab.ntt.co.jp>
date Thu, 11 Jun 2015 12:30:59 +0900
parents 60db960255a5
children 93e0a0a66b9c
files agent/ChangeLog agent/heapstats.conf.in agent/src/heapstats-engines/configuration.cpp agent/src/heapstats-engines/configuration.hpp agent/src/heapstats-engines/fsUtil.cpp agent/src/heapstats-engines/fsUtil.hpp agent/src/heapstats-engines/libmain.cpp agent/src/heapstats-engines/logger.hpp
diffstat 8 files changed, 138 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/agent/ChangeLog	Thu May 28 17:01:36 2015 +0900
+++ b/agent/ChangeLog	Thu Jun 11 12:30:59 2015 +0900
@@ -1,3 +1,7 @@
+2015-06-11 KUBOTA Yuji  <kubota.yuji@lab.ntt.co.jp>
+
+	* Bug 2113: [ADD CONFIG] Add switch to output HeapStats messages to logfile.
+
 2015-05-28 KUBOTA Yuji  <kubota.yuji@lab.ntt.co.jp>
 
 	* Bug 2382: Update Private Enterprise Number for SNMP.
--- a/agent/heapstats.conf.in	Thu May 28 17:01:36 2015 +0900
+++ b/agent/heapstats.conf.in	Thu Jun 11 12:30:59 2015 +0900
@@ -6,6 +6,7 @@
 file=heapstats_snapshot.dat
 heaplogfile=heapstats_log.csv
 archivefile=heapstats_analyze.zip
+logfile=
 loglevel=INFO
 reduce_snapshot=true
 
--- a/agent/src/heapstats-engines/configuration.cpp	Thu May 28 17:01:36 2015 +0900
+++ b/agent/src/heapstats-engines/configuration.cpp	Thu Jun 11 12:30:59 2015 +0900
@@ -59,6 +59,7 @@
     FileName           = strdup("heapstats_snapshot.dat");
     heapLogFile        = strdup("heapstats_log.csv");
     archiveFile        = strdup("heapstats_analyze.zip");
+    logFile            = strdup("");
     RankLevel          = 5;
     LogLevel           = INFO;
     reduceSnapShot     = true;
@@ -107,6 +108,7 @@
                                                 : strdup(src.heapLogFile);
   archiveFile         = src.archiveFile == NULL ? NULL
                                                 : strdup(src.archiveFile);
+  logFile             = src.logFile == NULL ? NULL : strdup(src.logFile);
   RankLevel           = src.RankLevel;
   LogLevel            = src.LogLevel;
   reduceSnapShot      = src.reduceSnapShot;
@@ -158,7 +160,10 @@
     
     free(archiveFile);
     archiveFile = NULL;
-    
+
+    free(logFile);
+    logFile = NULL;
+
     if(logSignalNormal != NULL){
       free(logSignalNormal);
       logSignalNormal = NULL;
@@ -314,66 +319,6 @@
   }
 }
 
-
-/*!
- * \brief Check that path is accessible.
- * \param value [in] Value of this configuration.
- * \return Path is accessible.
- */
-bool TConfiguration::IsValidPath(const char *value){
-  /* Check archive file path. */
-  char *dir = getParentDirectoryPath(value);
-  if(dir == NULL){
-    throw "Cannot get parent directory";
-  }
-
-  errno = 0;
-  int ret = isAccessibleDirectory(dir, true, true);
-  free(dir);
-  if(ret == -1){
-    throw "Illegal parameter was passed to isAccessibleDirectory()";
-  }
-  else if(errno != 0){
-    return false;
-  }
-
-  struct stat st;
-  if(stat(value, &st) == -1){
-    if(errno == ENOENT){
-      return true;
-    }
-    else{
-      throw errno;
-    }
-  }
-
-  bool result = false;
-  bool isOwner  = (st.st_uid == geteuid());
-  bool isGroupUser = (st.st_gid == getegid());
-
-  /* Check access permition as file owner. */
-  if(isOwner){
-    result |= (st.st_mode & S_IRUSR) && (st.st_mode & S_IWUSR);
-  }
-
-  /* Check access permition as group user. */
-  if(!result && isGroupUser){
-    result |= (st.st_mode & S_IRGRP) && (st.st_mode & S_IWGRP);
-  }
-
-  /* Check access permition as other. */
-  if(!result){
-    result |= (st.st_mode & S_IROTH) && (st.st_mode & S_IWOTH);
-  }
-
-  if(!result){
-    errno = EPERM;
-  }
-
-  return result;
-}
-
-
 /*!
  * \brief Load configuration from file.
  * \param filename [in] Read configuration file path.
@@ -468,6 +413,8 @@
   logger->printInfoMsg("SnapShot FileName = %s", FileName);
   logger->printInfoMsg("Heap Log FileName = %s", heapLogFile);
   logger->printInfoMsg("Archive FileName = %s", archiveFile);
+  logger->printInfoMsg("Console Log FileName = %s",
+      strlen(logFile) > 0 ? logFile : "None (output to console)");
 
   /* Output log-level. */
   const char *loglevelArray[] = {NULL, "CRIT", "WARN", "INFO", "DEBUG"};
@@ -609,12 +556,20 @@
   struct{
     char *key;
     char *value;
-  } filenames[] = {{"file", FileName}, {"heaplogfile", heapLogFile},
-                   {"archivefile", archiveFile}, {"logdir", logDir},
+  } filenames[] = {{"file", FileName},
+                   {"heaplogfile", heapLogFile},
+                   {"archivefile", archiveFile},
+                   {"logfile", logFile},
+                   {"logdir", logDir},
                    {NULL, NULL}};
-  for(int idx = 0; filenames[idx].key != NULL; idx++){
+
+  for(int idx = 0; filenames[idx].key != NULL; idx++) {
+    if (strlen(filenames[idx].value) == 0) {
+      // "" means "disable", not a file path like "./".
+      continue;
+    }
     try{
-      if(!IsValidPath(filenames[idx].value)){
+      if(!isValidPath(filenames[idx].value)){
         throw "Permission denied";
       }
     }
@@ -684,7 +639,7 @@
                                                        threadRecordBufferSize);
       result = false;
     }
-    else if(!IsValidPath(threadRecordFileName)){
+    else if(!isValidPath(threadRecordFileName)){
       logger->printWarnMsg("Permission denied: thread_record_filename = %s",
                                                          threadRecordFileName);
       result = false;
@@ -720,6 +675,7 @@
   setFileName(src->FileName);
   setHeapLogFile(src->heapLogFile);
   setArchiveFile(src->archiveFile);
+  setLogFile(src->logFile);
   setRankLevel(src->RankLevel);
   setLogLevel(src->LogLevel);
   setReduceSnapShot(src->reduceSnapShot);
@@ -776,6 +732,9 @@
   else if(strcmp(key, "archivefile") == 0){
     setArchiveFile(value);
   }
+  else if(strcmp(key, "logfile") == 0){
+    setLogFile(value);
+  }
   else if(strcmp(key, "rank_level") == 0){
     setRankLevel(ReadLongValue(value, INT_MAX));
   }
--- a/agent/src/heapstats-engines/configuration.hpp	Thu May 28 17:01:36 2015 +0900
+++ b/agent/src/heapstats-engines/configuration.hpp	Thu Jun 11 12:30:59 2015 +0900
@@ -57,6 +57,9 @@
     /*!< Output archive log file name. */
     char *archiveFile;
 
+    /*!< Output console log file name. */
+    char *logFile;
+
     /*!< Is reduced snapshot. */
     bool reduceSnapShot;
 
@@ -182,14 +185,6 @@
      */
     void ReadSignalValue(const char *value, char **dest);
 
-    /*!
-     * \brief Check that path is accessible.
-     * \param value [in] Value of this configuration.
-     * \return Path is accessible.
-     */
-    bool IsValidPath(const char *value);
-
-
   public:
 
     TConfiguration(TJvmInfo *info);
@@ -263,6 +258,7 @@
     inline char *getFileName(){ return this->FileName; };
     inline char *getHeapLogFile(){ return this->heapLogFile; };
     inline char *getArchiveFile(){ return this->archiveFile; };
+    inline char *getLogFile(){ return this->logFile; };
     inline bool getReduceSnapShot(){ return this->reduceSnapShot; };
     inline bool getTriggerOnFullGC(){ return this->triggerOnFullGC; };
     inline bool getTriggerOnDump(){ return this->triggerOnDump; };
@@ -301,6 +297,7 @@
     inline void setFileName(const char *val){ ReadStringValue(val, &FileName); };
     inline void setHeapLogFile(const char *val){ ReadStringValue(val, &heapLogFile); };
     inline void setArchiveFile(const char *val){ ReadStringValue(val, &archiveFile); };
+    inline void setLogFile(const char *val){ ReadStringValue(val, &logFile); };
     inline void setReduceSnapShot(bool val){ this->reduceSnapShot = val; };
     inline void setTriggerOnFullGC(bool val){
       if(isLoaded && !triggerOnFullGC && val){
--- a/agent/src/heapstats-engines/fsUtil.cpp	Thu May 28 17:01:36 2015 +0900
+++ b/agent/src/heapstats-engines/fsUtil.cpp	Thu Jun 11 12:30:59 2015 +0900
@@ -558,3 +558,64 @@
     return (result) ? 0 : EACCES;
 }
 
+/*!
+ * \brief Check that path is accessible.
+ * \param path [in] A path to file.
+ * \return Path is accessible.
+ */
+bool isValidPath(const char *path){
+  /* Check archive file path. */
+  if (strlen(path) == 0) {
+    throw "Invalid file path";
+  }
+  char *dir = getParentDirectoryPath(path);
+  if(dir == NULL){
+    throw "Cannot get parent directory";
+  }
+
+  errno = 0;
+  int ret = isAccessibleDirectory(dir, true, true);
+  free(dir);
+  if(ret == -1){
+    throw "Illegal parameter was passed to isAccessibleDirectory()";
+  }
+  else if(errno != 0){
+    return false;
+  }
+
+  struct stat st;
+  if(stat(path, &st) == -1){
+    if(errno == ENOENT){
+      return true;
+    }
+    else{
+      throw errno;
+    }
+  }
+
+  bool result = false;
+  bool isOwner  = (st.st_uid == geteuid());
+  bool isGroupUser = (st.st_gid == getegid());
+
+  /* Check access permition as file owner. */
+  if(isOwner){
+    result |= (st.st_mode & S_IRUSR) && (st.st_mode & S_IWUSR);
+  }
+
+  /* Check access permition as group user. */
+  if(!result && isGroupUser){
+    result |= (st.st_mode & S_IRGRP) && (st.st_mode & S_IWGRP);
+  }
+
+  /* Check access permition as other. */
+  if(!result){
+    result |= (st.st_mode & S_IROTH) && (st.st_mode & S_IWOTH);
+  }
+
+  if(!result){
+    errno = EPERM;
+  }
+
+  return result;
+}
+
--- a/agent/src/heapstats-engines/fsUtil.hpp	Thu May 28 17:01:36 2015 +0900
+++ b/agent/src/heapstats-engines/fsUtil.hpp	Thu Jun 11 12:30:59 2015 +0900
@@ -98,6 +98,13 @@
 int isAccessibleDirectory(char const* path, bool needRead, bool needWrite);
 
 /*!
+ * \brief Check that path is accessible.
+ * \param path [in] A path to file.
+ * \return Path is accessible.
+ */
+bool isValidPath(const char *path);
+
+/*!
  * \brief Check disk full error.<br />
  *        If error is disk full, then print alert message.
  * \param aErrorNum [in] Number of error code.
--- a/agent/src/heapstats-engines/libmain.cpp	Thu May 28 17:01:36 2015 +0900
+++ b/agent/src/heapstats-engines/libmain.cpp	Thu Jun 11 12:30:59 2015 +0900
@@ -608,6 +608,7 @@
     }
 
     logger->setLogLevel(conf->getLogLevel());
+    logger->setLogFile(conf->getLogFile());
 
     /* Show package information. */
     logger->printInfoMsg(PACKAGE_STRING);
--- a/agent/src/heapstats-engines/logger.hpp	Thu May 28 17:01:36 2015 +0900
+++ b/agent/src/heapstats-engines/logger.hpp	Thu Jun 11 12:30:59 2015 +0900
@@ -49,6 +49,8 @@
 class TLogger{
 
   private:
+    FILE *out = stdout;
+    FILE *err = stderr;
     TLogLevel logLevel;
 
     /*!
@@ -64,11 +66,9 @@
                               bool isNewLine, const char *format, va_list ap){
       fprintf(stream, "heapstats %s: ", header);
       vfprintf(stream, format, ap);
-
       if(isNewLine){
         fputc('\n', stream);
       }
-
     }
 
   public:
@@ -76,16 +76,18 @@
     TLogger() : logLevel(INFO) {};
     TLogger(TLogLevel level) : logLevel(level) {};
 
+
     virtual ~TLogger(){
       flush();
+      if (out != stdout && out != NULL) { fclose(out); }
     }
 
     /*!
      * \brief Flush stdout and stderr.
      */
     inline void flush(){
-      fflush(stdout);
-      fflush(stderr);
+      fflush(out);
+      if (err != out) { fflush(err); }
     }
 
     /*!
@@ -97,33 +99,50 @@
     }
 
     /*!
-     * \brief Print critical message to stderr.
+     * \brief Setter for logFile.
+     * \param logfile: Console log filename.
+     */
+    inline void setLogFile(char *logfile) {
+      if (logfile != NULL && strlen(logfile) != 0) {
+        out = fopen(logfile, "a");
+        if (unlikely( out==NULL )) {
+          // If cannot open file.
+          this->printWarnMsgWithErrno("Could not open console log file: %s. Agent always output to console.", logfile);
+          out = stdout;
+        } else {
+          err = out;
+        }
+      }
+    }
+
+    /*!
+     * \brief Print critical error message.
      *        This function treats arguments as printf(3).
      */
     inline void printCritMsg(const char *format, ...){
       if(this->logLevel >= CRIT){
         va_list ap;
         va_start(ap, format);
-        this->printMessageInternal(stderr, "CRIT", true, format, ap);
+        this->printMessageInternal(err, "CRIT", true, format, ap);
         va_end(ap);
       }
     }
 
     /*!
-     * \brief Print warning message to stderr.
+     * \brief Print warning error message.
      *        This function treats arguments as printf(3).
      */
     inline void printWarnMsg(const char *format, ...){
       if(this->logLevel >= WARN){
         va_list ap;
         va_start(ap, format);
-        this->printMessageInternal(stderr, "WARN", true, format, ap);
+        this->printMessageInternal(err, "WARN", true, format, ap);
         va_end(ap);
       }
     }
 
     /*!
-     * \brief Print warning message to stderr with current errno.
+     * \brief Print warning error message with current errno.
      *        This function treats arguments as printf(3).
      */
     inline void printWarnMsgWithErrno(const char *format, ...){
@@ -133,34 +152,34 @@
 
         va_list ap;
         va_start(ap, format);
-        this->printMessageInternal(stderr, "WARN", false, format, ap);
+        this->printMessageInternal(err, "WARN", false, format, ap);
         va_end(ap);
-        fprintf(stderr, " cause: %s\n", output_message);
+        fprintf(err, " cause: %s\n", output_message);
       }
     }
 
     /*!
-     * \brief Print information message to stdout.
+     * \brief Print information message.
      *        This function treats arguments as printf(3).
      */
     inline void printInfoMsg(const char *format, ...){
       if(this->logLevel >= INFO){
         va_list ap;
         va_start(ap, format);
-        this->printMessageInternal(stdout, "INFO", true, format, ap);
+        this->printMessageInternal(out, "INFO", true, format, ap);
         va_end(ap);
       }
     }
 
     /*!
-     * \brief Print debug message to stdout.
+     * \brief Print debug message.
      *        This function treats arguments as printf(3).
      */
     inline void printDebugMsg(const char *format, ...){
       if(this->logLevel >= DEBUG){
         va_list ap;
         va_start(ap, format);
-        this->printMessageInternal(stdout, "DEBUG", true, format, ap);
+        this->printMessageInternal(out, "DEBUG", true, format, ap);
         va_end(ap);
       }
     }