Browse Source

implement log_history functionality

Ken Patel 16 years ago
parent
commit
8dc84e42d8

+ 82 - 2
direct/src/plugin/p3dMainObject.cxx

@@ -450,9 +450,11 @@ call_read_log(P3D_object *params[], int num_params) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DMainObject::
 P3D_object *P3DMainObject::
 read_log(const string &log_pathname, P3D_object *params[], int num_params) {
 read_log(const string &log_pathname, P3D_object *params[], int num_params) {
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  string log_directory = inst_mgr->get_log_directory();
+
   ifstream log(log_pathname.c_str(), ios::in);
   ifstream log(log_pathname.c_str(), ios::in);
   if (!log) {
   if (!log) {
-    P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
     return inst_mgr->new_undefined_object();
     return inst_mgr->new_undefined_object();
   }
   }
 
 
@@ -470,6 +472,49 @@ read_log(const string &log_pathname, P3D_object *params[], int num_params) {
     head_bytes = (size_t)max(P3D_OBJECT_GET_INT(params[1]), 0);
     head_bytes = (size_t)max(P3D_OBJECT_GET_INT(params[1]), 0);
   }
   }
 
 
+  // Check if we want data from previous logs
+  const char log_sep_line_char = '-';
+  const int log_sep_line_chars = 80;
+  const int log_sep_filename_chars = 256;
+  const int log_sep_bytes = log_sep_line_chars + log_sep_filename_chars + 16;
+  size_t tail_bytes_prev = 0;
+  vector<string> log_basenames_prev;
+  if (num_params > 2) {
+    // Determine the base of the log file names
+    tail_bytes_prev = (size_t)max(P3D_OBJECT_GET_INT(params[2]), 0);
+    if (tail_bytes_prev > 0) {
+      string log_basename = log_pathname;
+      size_t slash = log_basename.rfind('/');
+      if (slash != string::npos) {
+        log_basename = log_basename.substr(slash + 1);
+      }
+#ifdef _WIN32
+      slash = log_basename.rfind('\\');
+      if (slash != string::npos) {
+        log_basename = log_basename.substr(slash + 1);
+      }
+#endif  // _WIN32
+      string log_basename_curr = log_basename;
+      int dash = log_basename.rfind("-");
+      if (dash != string::npos) {
+        log_basename = log_basename.substr(0, dash+1);
+
+        // Find matching files
+        vector<string> all_logs;
+        inst_mgr->scan_directory(log_directory, all_logs);
+        for (int i=0; i<(int)all_logs.size(); ++i) {
+          if ((all_logs[i].size() > 4) &&
+              (all_logs[i].find(log_basename) == 0) &&
+              (all_logs[i].substr(all_logs[i].size() - 4) == string(".log"))) {
+            if (all_logs[i] != log_basename_curr) {
+              log_basenames_prev.push_back(all_logs[i]);
+            }
+          }
+        }
+      }
+    }
+  }
+
   // Get the size of the file.
   // Get the size of the file.
   log.seekg(0, ios::end);
   log.seekg(0, ios::end);
   size_t file_size = (size_t)log.tellg();
   size_t file_size = (size_t)log.tellg();
@@ -500,6 +545,12 @@ read_log(const string &log_pathname, P3D_object *params[], int num_params) {
     return_size = head_bytes + separator.size() + tail_bytes;
     return_size = head_bytes + separator.size() + tail_bytes;
   }
   }
 
 
+  // We will need additional space for data from previous logs
+  if ((tail_bytes_prev > 0) && (log_basenames_prev.size() > 0)) {
+      int extra_bytes_per_prev_log = tail_bytes_prev + log_sep_bytes;
+      return_size += log_basenames_prev.size() * extra_bytes_per_prev_log;
+  }
+
   nout << "allocating " << return_size << " bytes to return.\n";
   nout << "allocating " << return_size << " bytes to return.\n";
   char *buffer = new char[return_size];
   char *buffer = new char[return_size];
   if (buffer == NULL) {
   if (buffer == NULL) {
@@ -524,11 +575,40 @@ read_log(const string &log_pathname, P3D_object *params[], int num_params) {
     bp += log.gcount();
     bp += log.gcount();
   }
   }
 
 
+  // add data for previous logs
+  if ((tail_bytes_prev > 0) && (log_basenames_prev.size() > 0)) {
+    string log_sep_line = "\n";
+    for (int c=0; c<log_sep_line_chars; ++c) {
+        log_sep_line += log_sep_line_char;
+    }
+    log_sep_line += "\n";
+    for (int i=0; i<(int)log_basenames_prev.size(); ++i) {
+      ifstream log_prev((log_directory+log_basenames_prev[i]).c_str(), ios::in);
+      if (log_prev) {
+        // Insert file separator
+        string log_sep = "\n"+log_sep_line+log_basenames_prev[i]+log_sep_line+"\n";
+        assert(log_sep.length() <= (unsigned)log_sep_bytes); 
+        memcpy(bp, log_sep.data(), log_sep.length());
+        bp += log_sep.length();
+        // Insert prev file data
+        log_prev.seekg(0, ios::end);
+        size_t file_size = (size_t)log_prev.tellg();
+        size_t data_size = tail_bytes_prev;
+        if (data_size > file_size) {
+          data_size = file_size;
+        }
+        log_prev.seekg(file_size - data_size, ios::beg);
+        log_prev.read(bp, data_size);
+        bp += log_prev.gcount();
+      }
+    }
+  }
+
   assert(bp <= buffer + return_size);
   assert(bp <= buffer + return_size);
 
 
   P3D_object *result = new P3DStringObject(buffer, bp - buffer);
   P3D_object *result = new P3DStringObject(buffer, bp - buffer);
   delete[] buffer;
   delete[] buffer;
-
+  
   return result;
   return result;
 }
 }
 
 

+ 44 - 0
direct/src/plugin/p3dSession.cxx

@@ -29,6 +29,7 @@
 #include "run_p3dpython.h"
 #include "run_p3dpython.h"
 
 
 #include <ctype.h>
 #include <ctype.h>
+#include <time.h>
 
 
 #ifndef _WIN32
 #ifndef _WIN32
 #include <fcntl.h>
 #include <fcntl.h>
@@ -1019,6 +1020,49 @@ start_p3dpython(P3DInstance *inst) {
   }
   }
 #endif  // _WIN32
 #endif  // _WIN32
 
 
+  // Check if we want to keep copies of recent logs on disk.
+  // Get the log history count from the HTML tokens, or from the
+  // p3d_info.xml file.
+  int log_history = inst->get_fparams().lookup_token_int("log_history");
+  if (!log_basename.empty() && (log_history > 1)) {
+    // Append suffix separator
+    log_basename += "-";
+
+    // Delete all but the most recent 'log_history' logs
+    vector<string> all_logs;
+    vector<string> matching_logs;
+    string log_directory = inst_mgr->get_log_directory();
+    inst_mgr->scan_directory(log_directory, all_logs);
+    for (int i=0; i<(int)all_logs.size(); ++i) {
+      if ((all_logs[i].size() > 4) &&
+          (all_logs[i].find(log_basename) == 0) &&
+          (all_logs[i].substr(all_logs[i].size() - 4) == string(".log"))) {
+        matching_logs.push_back((log_directory + all_logs[i]));
+      }
+    }
+    for (int i=0; i<(int)matching_logs.size()-log_history; ++i) {
+      unlink(matching_logs[i].c_str());
+    }
+
+    // Append a timestamp suffix to the log_basename
+    _tzset();
+    time_t log_time_seconds = time(NULL);
+    struct tm *log_time_local_p = localtime(&log_time_seconds);
+    if (log_time_local_p != NULL) {
+      struct tm log_time_local = *log_time_local_p;
+      static const size_t buffer_size = 16;
+      char buffer[buffer_size];
+      sprintf(buffer, "%02d%02d%02d_%02d%02d%02d", 
+              (int)(log_time_local.tm_year+1900-2000),
+              (int)(log_time_local.tm_mon),
+              (int)(log_time_local.tm_mday),
+              (int)(log_time_local.tm_hour),
+              (int)(log_time_local.tm_min),
+              (int)(log_time_local.tm_sec));
+      log_basename += buffer;
+    }
+  }
+
   if (!console_output && !log_basename.empty()) {
   if (!console_output && !log_basename.empty()) {
     _log_pathname = inst_mgr->get_log_directory();
     _log_pathname = inst_mgr->get_log_directory();
     _log_pathname += log_basename;
     _log_pathname += log_basename;

+ 4 - 1
direct/src/plugin/p3d_plugin.h

@@ -120,7 +120,10 @@ extern "C" {
    written.  Otherwise, the compiled-in default is used; if there is
    written.  Otherwise, the compiled-in default is used; if there is
    no compiled-in default, no logfile output will be generated by the
    no compiled-in default, no logfile output will be generated by the
    core API.  Note that the individual instances also have their own
    core API.  Note that the individual instances also have their own
-   log_basename values.
+   log_basename values.  If log_history is greater than zero, the
+   most recent log_history (count) logs generated (per log_basename)
+   will be retained on disk, each named uniquely by appending a 
+   timestamp to the log_basename before file creation.
 
 
    Next, trusted_environment should be set true to indicate that the
    Next, trusted_environment should be set true to indicate that the
    environment and p3d file are already trusted.  If this is set, the
    environment and p3d file are already trusted.  If this is set, the