From a483699686d70217547b2cb4d0cb2670d4bcb51b Mon Sep 17 00:00:00 2001 From: Bjorn Hjortsberg Date: Fri, 8 Dec 2017 10:37:05 +0100 Subject: [PATCH 1/2] Use weak_ptr to not keep reference to FileStream LogStreamReferenceMap was keeping a reference to FileStream which kept the file open even though Logger was unregistred. --- src/easylogging++.cc | 18 ++++++++++++------ src/easylogging++.h | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/easylogging++.cc b/src/easylogging++.cc index 620921454..817dae41b 100644 --- a/src/easylogging++.cc +++ b/src/easylogging++.cc @@ -1717,17 +1717,23 @@ void TypedConfigurations::insertFile(Level level, const std::string& fullFilenam auto create = [&](Level level) { base::LogStreamsReferenceMap::iterator filestreamIter = m_logStreamsReference->find(resolvedFilename); base::type::fstream_t* fs = nullptr; - if (filestreamIter == m_logStreamsReference->end()) { + bool needNewStream = filestreamIter == m_logStreamsReference->end(); + if (!needNewStream && filestreamIter->second.lock() == nullptr) { + // Filestream is expired and exists in map + needNewStream = true; + m_logStreamsReference->erase(filestreamIter); + } + if (needNewStream) { // We need a completely new stream, nothing to share with fs = base::utils::File::newFileStream(resolvedFilename); m_filenameMap.insert(std::make_pair(level, resolvedFilename)); m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs))); - m_logStreamsReference->insert(std::make_pair(resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level)))); + m_logStreamsReference->insert(std::make_pair(resolvedFilename, base::WeakFileStreamPtr(m_fileStreamMap.at(level)))); } else { // Woops! we have an existing one, share it! m_filenameMap.insert(std::make_pair(level, filestreamIter->first)); - m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(filestreamIter->second))); - fs = filestreamIter->second.get(); + m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(filestreamIter->second.lock()))); + fs = filestreamIter->second.lock().get(); } if (fs == nullptr) { // We display bad file error from newFileStream() @@ -1851,8 +1857,8 @@ void RegisteredLoggers::unsafeFlushAll(void) { ELPP_INTERNAL_INFO(1, "Flushing all log files"); for (base::LogStreamsReferenceMap::iterator it = m_logStreamsReference.begin(); it != m_logStreamsReference.end(); ++it) { - if (it->second.get() == nullptr) continue; - it->second->flush(); + if (it->second.lock() == nullptr) continue; + it->second.lock()->flush(); } } diff --git a/src/easylogging++.h b/src/easylogging++.h index 921dfa90c..6b21c7586 100644 --- a/src/easylogging++.h +++ b/src/easylogging++.h @@ -1953,7 +1953,8 @@ class Configurations : public base::utils::RegistryWithPred FileStreamPtr; -typedef std::map LogStreamsReferenceMap; +typedef std::weak_ptr WeakFileStreamPtr; +typedef std::map LogStreamsReferenceMap; /// @brief Configurations with data types. /// /// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations. From 41ef65ec3b463af1ceaa1ed427ccd969156f7c58 Mon Sep 17 00:00:00 2001 From: Bjorn Hjortsberg Date: Fri, 8 Dec 2017 09:58:25 +0100 Subject: [PATCH 2/2] Add logrotate sample --- samples/logrotate/Makefile | 4 ++ samples/logrotate/main.cpp | 75 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 samples/logrotate/Makefile create mode 100644 samples/logrotate/main.cpp diff --git a/samples/logrotate/Makefile b/samples/logrotate/Makefile new file mode 100644 index 000000000..bdf658369 --- /dev/null +++ b/samples/logrotate/Makefile @@ -0,0 +1,4 @@ + +all: + $(CXX) ../../src/easylogging++.cc main.cpp -o logrotate-sample -DELPP_DEBUG_INFO --std=c++11 + diff --git a/samples/logrotate/main.cpp b/samples/logrotate/main.cpp new file mode 100644 index 000000000..cf340f0ba --- /dev/null +++ b/samples/logrotate/main.cpp @@ -0,0 +1,75 @@ +#include "../../src/easylogging++.h" +#include +#include + +INITIALIZE_EASYLOGGINGPP + +/* + * Send SIGHUP to the application and log is + * reopended + * + * Ex: + * $ ls -l logfile.log + * -rw-r--r-- 1 el staff 200 Dec 8 10:29 logfile.log + * $ rm logfile.log + * $ kill -SIGHUP $(pgrep logrotate-sample) + * $ ls -l logfile.log + * -rw-r--r-- 1 el staff 0 Dec 8 10:33 logfile.log + * + * */ + +#define loggerName "rotate-logger" + +void configure_logger() +{ + el::Configurations logConf; + logConf.setToDefault(); + logConf.setGlobally(el::ConfigurationType::ToStandardOutput, + "false"); + logConf.setGlobally(el::ConfigurationType::ToFile, "true"); + logConf.setGlobally(el::ConfigurationType::Filename, "logfile.log"); + + logConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "true"); + logConf.set(el::Level::Debug, + el::ConfigurationType::Format, + "%datetime %level %msg"); + el::Logger* logger = el::Loggers::getLogger(loggerName); + el::Loggers::reconfigureLogger(logger, logConf); + +} + +void handler_hup(int signal) +{ + LOG(INFO) << "SIGHUP received - reconfigure logger"; + el::Logger* logger = el::Loggers::getLogger(loggerName); + logger->reconfigure(); +} + +void handler_usr1(int signal) +{ + LOG(INFO) << "SIGUSR1 received - unregister logger"; + el::Loggers::unregisterLogger(loggerName); +} + +int main() +{ + std::signal(SIGHUP, handler_hup); + std::signal(SIGUSR1, handler_usr1); + + LOG(INFO) << "Configuring logger"; + configure_logger(); + + char c; + c = getchar(); + CLOG(DEBUG, loggerName) << "My logger"; + + while ((c = getchar()) != 'q') + { + CLOG(DEBUG, loggerName) << "My logger"; + } + + std::cout << "Unregistred my logger\n"; + + return 0; +} +