diff --git a/Daemon.cpp b/Daemon.cpp index 9c0d15f8..490277fc 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -113,7 +113,7 @@ namespace i2p } else { // use stdout -- default } - i2p::log::Logger().Ready(); + i2p::log::Logger().Start(); LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); LogPrint(eLogDebug, "FS: main config file: ", config); @@ -351,6 +351,7 @@ namespace i2p } #endif i2p::crypto::TerminateCrypto (); + i2p::log::Logger().Stop(); return true; } diff --git a/Log.cpp b/Log.cpp index 268e9667..bace5f55 100644 --- a/Log.cpp +++ b/Log.cpp @@ -58,13 +58,29 @@ namespace log { Log::Log(): m_Destination(eLogStdout), m_MinLevel(eLogInfo), - m_LogStream (nullptr), m_Logfile(""), m_IsReady(false), m_HasColors(true) + m_LogStream (nullptr), m_Logfile(""), m_HasColors(true), + m_IsRunning (false), m_Thread (nullptr) { } Log::~Log () { - switch (m_Destination) { + delete m_Thread; + } + + void Log::Start () + { + if (!m_IsRunning) + { + m_IsRunning = true; + m_Thread = new std::thread (std::bind (&Log::Run, this)); + } + } + + void Log::Stop () + { + switch (m_Destination) + { #ifndef _WIN32 case eLogSyslog : closelog(); @@ -78,7 +94,14 @@ namespace log { /* do nothing */ break; } - Process(); + m_IsRunning = false; + m_Queue.WakeUp (); + if (m_Thread) + { + m_Thread->join (); + delete m_Thread; + m_Thread = nullptr; + } } void Log::SetLogLevel (const std::string& level) { @@ -106,45 +129,52 @@ namespace log { * Unfortunately, with current startup process with late fork() this * will give us nothing but pain. Maybe later. See in NetDb as example. */ - void Log::Process() { - std::unique_lock l(m_OutputLock); + void Log::Process(std::shared_ptr msg) + { + if (!msg) return; std::hash hasher; unsigned short short_tid; - while (1) { - auto msg = m_Queue.GetNextWithTimeout (1); - if (!msg) - break; - short_tid = (short) (hasher(msg->tid) % 1000); - switch (m_Destination) { + short_tid = (short) (hasher(msg->tid) % 1000); + switch (m_Destination) { #ifndef _WIN32 - case eLogSyslog: - syslog(GetSyslogPrio(msg->level), "[%03u] %s", short_tid, msg->text.c_str()); - break; + case eLogSyslog: + syslog(GetSyslogPrio(msg->level), "[%03u] %s", short_tid, msg->text.c_str()); + break; #endif - case eLogFile: - case eLogStream: - if (m_LogStream) - *m_LogStream << TimeAsString(msg->timestamp) - << "@" << short_tid - << "/" << g_LogLevelStr[msg->level] - << " - " << msg->text << std::endl; - break; - case eLogStdout: - default: - std::cout << TimeAsString(msg->timestamp) + case eLogFile: + case eLogStream: + if (m_LogStream) + *m_LogStream << TimeAsString(msg->timestamp) << "@" << short_tid - << "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level] << LogMsgColors[eNumLogLevels] + << "/" << g_LogLevelStr[msg->level] << " - " << msg->text << std::endl; - break; - } // switch - } // while + break; + case eLogStdout: + default: + std::cout << TimeAsString(msg->timestamp) + << "@" << short_tid + << "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level] << LogMsgColors[eNumLogLevels] + << " - " << msg->text << std::endl; + break; + } // switch } - void Log::Append(std::shared_ptr & msg) { + void Log::Run () + { + while (m_IsRunning) + { + std::shared_ptr msg; + while (msg = m_Queue.Get ()) + Process (msg); + if (m_LogStream) m_LogStream->flush(); + if (m_IsRunning) + m_Queue.Wait (); + } + } + + void Log::Append(std::shared_ptr & msg) + { m_Queue.Put(msg); - if (!m_IsReady) - return; - Process(); } void Log::SendTo (const std::string& path) diff --git a/Log.h b/Log.h index a6fc2222..1d02a845 100644 --- a/Log.h +++ b/Log.h @@ -16,6 +16,7 @@ #include #include #include +#include #include "Queue.h" #ifndef _WIN32 @@ -56,9 +57,9 @@ namespace log { std::time_t m_LastTimestamp; char m_LastDateTime[64]; i2p::util::Queue > m_Queue; - volatile bool m_IsReady; bool m_HasColors; - mutable std::mutex m_OutputLock; + volatile bool m_IsRunning; + std::thread * m_Thread; private: @@ -66,10 +67,8 @@ namespace log { Log (const Log &); const Log& operator=(const Log&); - /** - * @brief process stored messages in queue - */ - void Process (); + void Run (); + void Process (std::shared_ptr msg); /** * @brief Makes formatted string from unix timestamp @@ -87,6 +86,9 @@ namespace log { LogType GetLogType () { return m_Destination; }; LogLevel GetLogLevel () { return m_MinLevel; }; + void Start (); + void Stop (); + /** * @brief Sets minimal allowed level for log messages * @param level String with wanted minimal msg level @@ -120,12 +122,6 @@ namespace log { */ void Append(std::shared_ptr &); - /** @brief Allow log output */ - void Ready() { m_IsReady = true; } - - /** @brief Flushes the output log stream */ - void Flush(); - /** @brief Reopen log file */ void Reopen(); }; diff --git a/api.cpp b/api.cpp index 1828901b..5148ed41 100644 --- a/api.cpp +++ b/api.cpp @@ -47,7 +47,7 @@ namespace api i2p::log::Logger().SendTo (logStream); else i2p::log::Logger().SendTo (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log")); - i2p::log::Logger().Ready(); + i2p::log::Logger().Start (); LogPrint(eLogInfo, "API: starting NetDB"); i2p::data::netdb.Start(); LogPrint(eLogInfo, "API: starting Transports"); @@ -65,6 +65,7 @@ namespace api i2p::transport::transports.Stop(); LogPrint(eLogInfo, "API: stopping NetDB"); i2p::data::netdb.Stop(); + i2p::log::Logger().Stop (); } void RunPeerTest ()