Hi,

If you haven't reviewed this patch, please ignore it, I have sent out V2 that uses ifstream to read the core dump file.

Thanks,

Minh


On 16/07/18 16:13, Minh Chau wrote:
If a process produces a core dump file that has THREAD_TRACE_BUFFER
enabled, this option reads the core dump file to extract the trace
strings in all threads and writes them to the trace file.
---
  src/base/log_writer.h    |   3 +-
  src/dtm/tools/osaflog.cc | 114 +++++++++++++++++++++++++++++++++++++++++++++--
  2 files changed, 113 insertions(+), 4 deletions(-)

diff --git a/src/base/log_writer.h b/src/base/log_writer.h
index a7c5000..0a03e92 100644
--- a/src/base/log_writer.h
+++ b/src/base/log_writer.h
@@ -45,6 +45,7 @@ class LogWriter {
    void Write(size_t size);
    void Write(const char* bytes, size_t size);
    void Flush();
+  void SetLogFile(const std::string& log_file) { log_file_ = log_file; }
private:
    constexpr static const size_t kBufferSize = 128 * size_t{1024};
@@ -54,7 +55,7 @@ class LogWriter {
std::string log_file(size_t backup) const; - const std::string log_file_;
+  std::string log_file_;
    int fd_;
    size_t current_file_size_;
    size_t current_buffer_size_;
diff --git a/src/dtm/tools/osaflog.cc b/src/dtm/tools/osaflog.cc
index c5946ee..c91b1e6 100644
--- a/src/dtm/tools/osaflog.cc
+++ b/src/dtm/tools/osaflog.cc
@@ -27,10 +27,14 @@
  #include <cstdio>
  #include <cstdlib>
  #include <cstring>
+#include <algorithm>
  #include <list>
  #include <memory>
  #include <random>
  #include <string>
+#include <vector>
+#include "base/logtrace_buffer.h"
+#include "base/log_writer.h"
  #include "base/string_parse.h"
  #include "base/time.h"
  #include "base/unix_server_socket.h"
@@ -53,7 +57,7 @@ std::string PathName(const std::string& log_stream, int 
suffix);
  uint64_t GetInode(int fd);
  bool PrettyPrint(FILE* stream);
  bool PrettyPrint(const char* line, size_t size);
-
+int ExtractTrace(const std::string& core_file, const std::string& trace_file);
  char buf[65 * 1024];
} // namespace
@@ -64,6 +68,7 @@ int main(int argc, char** argv) {
                                    {"flush", no_argument, 0, 'f'},
                                    {"print", no_argument, nullptr, 'p'},
                                    {"delete", no_argument, nullptr, 'd'},
+                                  {"extract-trace", required_argument, 0, 'e'},
                                    {0, 0, 0, 0}};
uint64_t max_file_size = 0;
@@ -81,13 +86,16 @@ int main(int argc, char** argv) {
    bool delete_set = false;
    bool max_file_size_set = false;
    bool max_backups_set = false;
+  bool thread_trace = false;
+  std::string input_core = "";
+  std::string output_trace = "";
if (argc == 1) {
       PrintUsage(argv[0]);
       exit(EXIT_FAILURE);
    }
- while ((option = getopt_long(argc, argv, "m:b:p:f",
+  while ((option = getopt_long(argc, argv, "m:b:p:f:e:",
                     long_options, &long_index)) != -1) {
          switch (option) {
               case 'p':
@@ -115,11 +123,33 @@ int main(int argc, char** argv) {
                       exit(EXIT_FAILURE);
                     }
                   break;
+             case 'e':
+                   if (argv[optind] == nullptr || optarg == nullptr) {
+                     fprintf(stderr, "Coredump file or output trace file is "
+                         "not specified in arguments\n");
+                     exit(EXIT_FAILURE);
+                   }
+                   input_core = std::string(optarg);
+                   output_trace = std::string(argv[optind]);
+                   struct stat statbuf;
+                   if (stat(input_core.c_str(), &statbuf) != 0) {
+                    fprintf(stderr, "Core dump file does not exist\n");
+                    exit(EXIT_FAILURE);
+                   }
+
+                   if (stat(output_trace.c_str(), &statbuf) == 0) {
+                     fprintf(stderr, "Output trace file already exists\n");
+                     exit(EXIT_FAILURE);
+                   }
+                   thread_trace = true;
+                   break;
               default: PrintUsage(argv[0]);
                   exit(EXIT_FAILURE);
          }
    }
+ if (thread_trace) exit(ExtractTrace(input_core, output_trace));
+
    if (argc > optind && !pretty_print_set && !delete_set) {
      pretty_print_set = true;
      flush_set = true;
@@ -183,7 +213,13 @@ void PrintUsage(const char* program_name) {
            "                      G can be used for kilo-, mega- and\n"
            "                      gigabytes.\n"
            "--max-backups=NUM     Set the maximum number of backup files to\n"
-          "                      retain during log rotation to NUM.\n",
+          "                      retain during log rotation to NUM.\n"
+          "--extrace-trace <corefile> <tracefile>\n"
+          "                      If a process produces a core dump file has\n"
+          "                      THREAD_TRACE_BUFFER enabled, this option\n"
+          "                      reads the <corefile> to extract the trace\n"
+          "                      strings in all threads and writes them to\n"
+          "                      the <tracefile> file.\n",
            program_name);
  }
@@ -386,4 +422,76 @@ bool PrettyPrint(const char* line, size_t size) {
    return true;
  }
+int SearchStringInFile(int fd, const char* str) {
+  int rc = 0;
+  int len = strlen(str);
+  int i;
+  bool eof = false;
+  while (!eof && rc == 0) {
+    for (i = 0; i < len && !eof; i++) {
+      char c;
+      if (read(fd, &c, 1) == 1) {
+        if (str[i] != c) break;
+      } else {
+        eof = true;
+        rc = -1;
+      }
+    }
+    if (i == len) rc = 1;
+  }
+  return rc;
+}
+
+int ExtractTrace(const std::string& core_file,
+    const std::string& trace_file) {
+  int fd = 0;
+  std::vector<std::string> v_str{};
+  do {
+    fd = open(core_file.c_str(), O_RDONLY);
+  } while (fd < 0 && errno == EINTR);
+  // extract
+  if (fd > 0) {
+    bool eof = false;
+    while (!eof) {
+      int s = SearchStringInFile(fd, LogTraceBuffer::kLogTraceString);
+      if (s == -1) eof = true;
+      else if (s == 1) { // found
+        char c = '\0';
+        std::string str;
+        do {
+          if (read(fd, &c, 1) != 1) eof = true;
+          else {
+            str += c;
+            if (c == '\n') break;
+          }
+        } while (!eof);
+        v_str.push_back(str);
+      }
+    }
+    close(fd);
+  } else {
+    fprintf(stderr, "Failed to open coredump file\n");
+    return EXIT_FAILURE;
+  }
+  if (v_str.size() == 0) {
+    fprintf(stderr, "No trace string is found in coredump file\n");
+    return EXIT_FAILURE;
+  }
+  // sort by sequenceId
+  std::sort(v_str.begin(), v_str.end(),
+            [](const std::string a, const std::string b) -> bool {
+            int seqa, seqb;
+            std::sscanf(a.c_str(),"%*s %*s %*s %*s %*s %*s %*s "
+                "sequenceId=\"%d\"]", &seqa);
+            std::sscanf(b.c_str(),"%*s %*s %*s %*s %*s %*s %*s "
+                "sequenceId=\"%d\"]", &seqb);
+            return a < b;
+            });
+  // write
+  LogWriter log_writer{"", 1, LogWriter::kMaxFileSize_10MB};
+  log_writer.SetLogFile(trace_file);
+  for (auto str : v_str) log_writer.Write(str.c_str(), str.length());
+  log_writer.Flush();
+  return EXIT_SUCCESS;
+}
  }  // namespace


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to