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