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