From 865bce57749954eaf0c07b40235c33fd8b12728e Mon Sep 17 00:00:00 2001 From: WHR Date: Wed, 11 Jun 2025 22:09:54 +0800 Subject: [PATCH] Always reopen the log file on SIGUSR1 --- src/log.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/src/log.cpp b/src/log.cpp index 151a4d8..cfd9238 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -24,6 +24,10 @@ #include #include +#if defined(_WIN32) && !defined(S_ISREG) +#define S_ISREG(M) (((M) & _S_IFMT) == _S_IFREG) +#endif + #ifdef _MSC_VER #pragma warning(disable : 4996) #endif @@ -118,6 +122,9 @@ public: : m_writePos(0) , m_readPos(0) , m_stopped(false) + , m_needReopen(false) + , m_logFileDevice(0) + , m_logFileINode(0) { #if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG) SetUnhandledExceptionFilter(UnhandledExceptionFilter); @@ -128,9 +135,8 @@ public: std::setlocale(LC_ALL, "en_001"); m_logFilePath = DATA_DIR + log_file_name; - m_logFile.open(m_logFilePath, std::ios::app | std::ios::binary); - if (!m_logFile.is_open()) { + if (!reopen()) { fprintf(stderr, "failed to open %s: error %d\n", m_logFilePath.c_str(), errno); } @@ -219,6 +225,12 @@ public: const std::string& log_file_path() const { return m_logFilePath; } + FORCEINLINE void schedule_reopen() + { + m_needReopen = true; + uv_cond_signal(&m_cond); + } + private: static void init_uv_threadpool() { @@ -245,6 +257,28 @@ private: } } + bool reopen() + { + m_logFile.close(); + m_logFile.open(m_logFilePath, std::ios::app | std::ios::binary); + bool ok = m_logFile.is_open(); + if(ok) { + struct stat st; + if(stat(m_logFilePath.c_str(), &st) == 0) { + m_logFileDevice = st.st_dev; + m_logFileINode = st.st_ino; + } else { + // How? + m_logFileDevice = 0; + m_logFileINode = 0; + } + } else { + m_logFileDevice = 0; + m_logFileINode = 0; + } + return ok; + } + private: static void run_wrapper(void* arg) { reinterpret_cast(arg)->run(); } @@ -264,6 +298,14 @@ private: } uv_mutex_unlock(&m_mutex); + bool expected = true; + if (m_needReopen.compare_exchange_strong(expected, false)) { + // Reopen the log file on request (logrotate support) + if(reopen()) { + LOGINFO(0, "reopened " << m_logFilePath); + } + } + for (uint32_t writePos = m_writePos.load(); m_readPos != writePos; writePos = m_writePos.load()) { // We have at least one log slot pending, possibly more than one // Process everything in a loop before reading m_writePos again @@ -327,11 +369,18 @@ private: if (m_logFile.is_open()) { m_logFile.flush(); - // Reopen the log file if it's been moved (logrotate support) + // Automatically reopen the file if either it + // no longer exists or it is now a different + // regular file; this detects manual moving or + // recreating of the file struct stat buf; - if (stat(m_logFilePath.c_str(), &buf) != 0) { - m_logFile.close(); - m_logFile.open(m_logFilePath, std::ios::app | std::ios::binary); + if (stat(m_logFilePath.c_str(), &buf) == 0) { + if(m_logFileDevice && m_logFileINode && S_ISREG(buf.st_mode) && + (buf.st_dev != m_logFileDevice || buf.st_ino != m_logFileINode)) { + reopen(); + } + } else if(errno == ENOENT) { + reopen(); } } @@ -376,6 +425,10 @@ private: uv_thread_t m_worker; bool m_stopped; + std::atomic m_needReopen; + + dev_t m_logFileDevice; + ino_t m_logFileINode; std::ofstream m_logFile; std::string m_logFilePath; @@ -445,7 +498,7 @@ void reopen() { // This will trigger the worker thread which will then reopen log file if it's been moved #ifndef P2POOL_LOG_DISABLE - LOGINFO(0, "reopening " << worker->log_file_path()); + worker->schedule_reopen(); #endif }