Providing a new option '--max-idle' to configure the maximum idle time
of logtrace streams. If a stream has not been used for such time, logtrace
server will close the stream from its database.

This patch also corrects wrong indentation in osaflog.cc file.
---
 src/dtm/Makefile                  |   2 +-
 src/dtm/common/osaflog_protocol.h |   2 +
 src/dtm/tools/Makefile            |  18 ++++
 src/dtm/tools/osaflog.cc          | 132 ++++++++++++++++++------------
 src/dtm/transport/log_server.cc   |  57 ++++++++++++-
 src/dtm/transport/log_server.h    |   7 +-
 src/dtm/transport/transportd.conf |   6 ++
 7 files changed, 168 insertions(+), 56 deletions(-)
 create mode 100644 src/dtm/tools/Makefile

diff --git a/src/dtm/Makefile b/src/dtm/Makefile
index 533b0f273..fb0221075 100644
--- a/src/dtm/Makefile
+++ b/src/dtm/Makefile
@@ -15,7 +15,7 @@
 #
 
 all:
-       $(MAKE) -C ../.. bin/osafdtmd bin/osaftransportd
+       $(MAKE) -C ../.. bin/osafdtmd bin/osaftransportd bin/osaflog
 
 check:
        $(MAKE) -C ../.. bin/transport_test
diff --git a/src/dtm/common/osaflog_protocol.h 
b/src/dtm/common/osaflog_protocol.h
index 61e9f6f39..d35e5f345 100644
--- a/src/dtm/common/osaflog_protocol.h
+++ b/src/dtm/common/osaflog_protocol.h
@@ -27,6 +27,8 @@ namespace Osaflog {
 static constexpr const char* kServerSocketPath =
     PKGLOCALSTATEDIR "/osaf_log.sock";
 
+static constexpr const uint64_t kOneDayInMinute = 24*60;
+
 struct __attribute__((__packed__)) ClientAddressConstantPrefix {
   sa_family_t family = AF_UNIX;
   char abstract = '\0';
diff --git a/src/dtm/tools/Makefile b/src/dtm/tools/Makefile
new file mode 100644
index 000000000..8c48b70a5
--- /dev/null
+++ b/src/dtm/tools/Makefile
@@ -0,0 +1,18 @@
+#      -*- OpenSAF  -*-
+#
+# (C) Copyright 2019 The OpenSAF Foundation
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+# under the GNU Lesser General Public License Version 2.1, February 1999.
+# The complete license can be accessed from the following location:
+# http://opensource.org/licenses/lgpl-license.php
+# See the Copying file included with the OpenSAF distribution for full
+# licensing terms.
+#
+# Author(s): Ericsson AB
+#
+
+all:
+       $(MAKE) -C ../../.. bin/osaflog
diff --git a/src/dtm/tools/osaflog.cc b/src/dtm/tools/osaflog.cc
index 64be253e9..abbf0b164 100644
--- a/src/dtm/tools/osaflog.cc
+++ b/src/dtm/tools/osaflog.cc
@@ -47,6 +47,7 @@ namespace {
 void PrintUsage(const char* program_name);
 bool SendCommand(const std::string& command);
 bool MaxTraceFileSize(uint64_t max_file_size);
+bool SetMaxIdleTime(uint64_t max_idle);
 bool NoOfBackupFiles(uint64_t number_of_backups);
 bool Flush();
 base::UnixServerSocket* CreateSocket();
@@ -70,10 +71,12 @@ int main(int argc, char** argv) {
                                   {"print", no_argument, nullptr, 'p'},
                                   {"delete", no_argument, nullptr, 'd'},
                                   {"extract-trace", required_argument, 0, 'e'},
+                                  {"max-idle", required_argument, 0, 'i'},
                                   {0, 0, 0, 0}};
 
   uint64_t max_file_size = 0;
   uint64_t max_backups = 0;
+  uint64_t max_idle = 0;
   int option = 0;
 
   int long_index = 0;
@@ -82,71 +85,81 @@ int main(int argc, char** argv) {
   bool delete_result =  true;
   bool max_file_size_result = true;
   bool number_of_backups_result = true;
+  bool max_idle_result = true;
   bool flush_set = false;
   bool pretty_print_set = false;
   bool delete_set = false;
   bool max_file_size_set = false;
   bool max_backups_set = false;
+  bool max_idle_set = false;
   bool thread_trace = false;
   std::string input_core = "";
   std::string output_trace = "";
 
   if (argc == 1) {
-     PrintUsage(argv[0]);
-     exit(EXIT_FAILURE);
+    PrintUsage(argv[0]);
+    exit(EXIT_FAILURE);
   }
 
   while ((option = getopt_long(argc, argv, "m:b:p:f:e:",
-                   long_options, &long_index)) != -1) {
-        switch (option) {
-             case 'p':
-                   pretty_print_set = true;
-                   flush_set = true;
-                 break;
-             case 'd':
-                   delete_set = true;
-                 break;
-             case 'f':
-                   flush_set = true;
-                 break;
-             case 'm':
-                   max_file_size = base::StrToUint64(optarg,
-                                                     &max_file_size_set);
-                   if (!max_file_size_set || max_file_size > SIZE_MAX) {
-                     fprintf(stderr, "Illegal max-file-size argument\n");
-                     exit(EXIT_FAILURE);
-                   }
-                 break;
-             case 'b':
-                   max_backups = base::StrToUint64(optarg, &max_backups_set);
-                   if (!max_backups_set || max_backups > SIZE_MAX) {
-                     fprintf(stderr, "Illegal max-backups argument\n");
-                     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);
+                               long_options, &long_index)) != -1) {
+    switch (option) {
+      case 'p':
+        pretty_print_set = true;
+        flush_set = true;
+        break;
+      case 'd':
+        delete_set = true;
+        break;
+      case 'f':
+        flush_set = true;
+        break;
+      case 'm':
+        max_file_size = base::StrToUint64(optarg,
+                                          &max_file_size_set);
+        if (!max_file_size_set || max_file_size > SIZE_MAX) {
+          fprintf(stderr, "Illegal max-file-size argument\n");
+          exit(EXIT_FAILURE);
+        }
+        break;
+      case 'b':
+        max_backups = base::StrToUint64(optarg, &max_backups_set);
+        if (!max_backups_set || max_backups > SIZE_MAX) {
+          fprintf(stderr, "Illegal max-backups argument\n");
+          exit(EXIT_FAILURE);
+        }
+        break;
+      case 'i':
+        max_idle = base::StrToUint64(optarg, &max_idle_set);
+        if (!max_idle_set || max_idle > Osaflog::kOneDayInMinute) {
+          fprintf(stderr, "Illegal max-idle argument."
+                  " Valid value is in the range [0-24*60]\n");
+          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));
@@ -181,8 +194,11 @@ int main(int argc, char** argv) {
   if (max_file_size_set == true) {
      max_file_size_result = MaxTraceFileSize(max_file_size);
   }
+  if (max_idle_set == true) {
+    max_idle_result = SetMaxIdleTime(max_idle);
+  }
   if (flush_result && print_result && max_file_size_result &&
-      delete_result && number_of_backups_result)
+      delete_result && number_of_backups_result && max_idle_result)
      exit(EXIT_SUCCESS);
   exit(EXIT_FAILURE);
 }
@@ -220,7 +236,12 @@ void PrintUsage(const char* program_name) {
           "                      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",
+          "                      the <tracefile> file.\n"
+          "--max-idle=NUM        Set the maximum number of idle time to NUM\n"
+          "                      minutes. If a stream has not been used for\n"
+          "                      NUM minutes, the stream will be closed.\n"
+          "                      The default value is zero (disable the\n"
+          "                      clean-up job)\n",
           program_name);
 }
 
@@ -297,6 +318,11 @@ bool NoOfBackupFiles(uint64_t max_backups) {
   return SendCommand(std::string("max-backups ") + 
std::to_string(max_backups));
 }
 
+bool SetMaxIdleTime(uint64_t max_idle) {
+  return SendCommand(std::string("max-idle-time ") +
+                     std::to_string(max_idle));
+}
+
 bool Flush() {
   return SendCommand(std::string{"flush"});
 }
diff --git a/src/dtm/transport/log_server.cc b/src/dtm/transport/log_server.cc
index 43fa86a89..51a0a582c 100644
--- a/src/dtm/transport/log_server.cc
+++ b/src/dtm/transport/log_server.cc
@@ -44,6 +44,7 @@ LogServer::LogServer(int term_fd)
 
 LogServer::~LogServer() {
   for (const auto& s : log_streams_) delete s.second;
+  log_streams_.clear();
 }
 
 void LogServer::Run() {
@@ -77,6 +78,9 @@ void LogServer::Run() {
         ExecuteCommand(buffer, result, src_addr, addrlen);
       }
     }
+
+    CloseIdleStreams();
+
     struct timespec current = base::ReadMonotonicClock();
     struct timespec last_flush = current;
     bool empty = true;
@@ -91,11 +95,40 @@ void LogServer::Run() {
       if (!stream->empty()) empty = false;
     }
     struct timespec timeout = (last_flush + base::kFifteenSeconds) - current;
+    struct timespec* poll_timeout = &timeout;
+    if (empty && log_streams_.size() > 1) {
+      uint64_t max_idle = max_idle_time_.tv_sec;
+      poll_timeout = (max_idle) ? &max_idle_time_ : nullptr;
+    }
     pfd[1].fd = log_socket_.fd();
-    osaf_ppoll(pfd, 2, empty ? nullptr : &timeout, nullptr);
+    osaf_ppoll(pfd, 2, poll_timeout, nullptr);
   } while ((pfd[0].revents & POLLIN) == 0);
 }
 
+void LogServer::CloseIdleStreams() {
+  if (max_idle_time_.tv_sec == 0) return;
+
+  struct timespec current = base::ReadMonotonicClock();
+  auto it = log_streams_.begin();
+  while (it != log_streams_.end()) {
+    LogStream* stream = it->second;
+    struct timespec last_write = stream->last_write();
+    std::string name = stream->name();
+    if ((current - last_write) >= max_idle_time_
+        && name != kMdsLogStreamName) {
+      syslog(LOG_NOTICE, "Deleted the idle stream: %s", name.c_str());
+      if (current_stream_ == stream) {
+        current_stream_ = log_streams_.begin()->second;
+      }
+      it = log_streams_.erase(it);
+      delete stream;
+      no_of_log_streams_--;
+    } else {
+      it++;
+    }
+  }
+}
+
 LogServer::LogStream* LogServer::GetStream(const char* msg_id,
                                            size_t msg_id_size) {
   if (msg_id_size == current_stream_->log_name_size() &&
@@ -176,6 +209,19 @@ bool LogServer::ReadConfig(const char 
*transport_config_file) {
                "has illegal value '%s'", &line[tag_len]);
       }
     }
+
+    if (strncmp(line, "TRANSPORT_MAX_IDLE_TIME=",
+                strlen("TRANSPORT_MAX_IDLE_TIME=")) == 0) {
+      tag_len = strlen("TRANSPORT_MAX_IDLE_TIME=");
+      bool success;
+      uint64_t max_idle_time = base::StrToUint64(&line[tag_len], &success);
+      if (success && max_idle_time <= Osaflog::kOneDayInMinute) {
+        max_idle_time_.tv_sec = max_idle_time;
+      } else {
+        syslog(LOG_ERR, "TRANSPORT_MAX_IDLE_TIME "
+               "has illegal value '%s'", &line[tag_len]);
+      }
+    }
   }
 
   /* Close file. */
@@ -258,6 +304,13 @@ std::string LogServer::ExecuteCommand(const std::string& 
command,
       stream->Flush();
     }
     return std::string{"!flush"};
+  } else if (command == "?max-idle-time") {
+      bool success = false;
+      uint64_t max_idle_time = base::StrToUint64(argument.c_str(), &success);
+      if (success && max_idle_time <= Osaflog::kOneDayInMinute) {
+        max_idle_time_.tv_sec = max_idle_time*60;
+      }
+      return std::string{"!max-idle-time " + std::to_string(max_idle_time)};
   } else {
     return std::string{"!not_supported"};
   }
@@ -268,11 +321,13 @@ LogServer::LogStream::LogStream(const std::string& 
log_name,
     : log_name_{log_name}, last_flush_{}, log_writer_{log_name, max_backups,
                                                              max_file_size} {
   if (log_name.size() > kMaxLogNameSize) osaf_abort(log_name.size());
+  last_write_ = base::ReadMonotonicClock();
 }
 
 void LogServer::LogStream::Write(size_t size) {
   if (log_writer_.empty()) last_flush_ = base::ReadMonotonicClock();
   log_writer_.Write(size);
+  last_write_ = base::ReadMonotonicClock();
 }
 
 void LogServer::LogStream::Flush() {
diff --git a/src/dtm/transport/log_server.h b/src/dtm/transport/log_server.h
index 283509cc7..65b95b9b0 100644
--- a/src/dtm/transport/log_server.h
+++ b/src/dtm/transport/log_server.h
@@ -46,6 +46,7 @@ class LogServer {
   // process has received the SIGTERM signal, which is indicated by the caller
   // by making the term_fd (provided in the constructor) readable.
   void Run();
+  void CloseIdleStreams();
   // To read Transportd.conf
   bool ReadConfig(const char *transport_config_file);
 
@@ -55,7 +56,7 @@ class LogServer {
     static constexpr size_t kMaxLogNameSize = 32;
     LogStream(const std::string& log_name, size_t max_backups,
                                                  size_t max_file_size);
-
+    ~LogStream() { Flush(); }
     size_t log_name_size() const { return log_name_.size(); }
     const char* log_name_data() const { return log_name_.data(); }
     char* current_buffer_position() {
@@ -68,6 +69,8 @@ class LogServer {
     // I/O.
     void Write(size_t size);
     void Flush();
+    const char* name() const { return log_name_.c_str(); }
+    struct timespec last_write() const { return last_write_; }
     struct timespec last_flush() const {
       return last_flush_;
     }
@@ -75,6 +78,7 @@ class LogServer {
    private:
     const std::string log_name_;
     struct timespec last_flush_;
+    struct timespec last_write_;
     LogWriter log_writer_;
   };
   LogStream* GetStream(const char* msg_id, size_t msg_id_size);
@@ -95,6 +99,7 @@ class LogServer {
   // Configuration for LogServer
   size_t max_backups_;
   size_t max_file_size_;
+  struct timespec max_idle_time_{0, 0};
 
   base::UnixServerSocket log_socket_;
   std::map<std::string, LogStream*> log_streams_;
diff --git a/src/dtm/transport/transportd.conf 
b/src/dtm/transport/transportd.conf
index 23e87a0a1..0746c1775 100644
--- a/src/dtm/transport/transportd.conf
+++ b/src/dtm/transport/transportd.conf
@@ -11,3 +11,9 @@
 # be done based on this value. Default value will be 9
 # i.e totally 10 log files will be maintain.
 #TRANSPORT_MAX_BACKUPS=9
+
+#
+# TRANSPORT_MAX_IDLE_TIME: Number of idle time. If a stream has not been used
+# for this number minutes (e.g: trace was disabled using SIGUSR2), the stream
+# will be closed. A valid value is in the range [0-24*60].
+#TRANSPORT_MAX_IDLE_TIME=0
-- 
2.17.1



_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to