在c++中使用easylogging++进行多进程日志记录时丢失消息



我在我的应用程序中使用easylogging++来记录消息以进行控制,并且我注意到在生产环境中(在Linux下运行)一些消息从日志文件中消失或丢失。我在测试环境(Windows)中用一个简单的例子模拟了这个问题。我创建了一个无限线程,它只记录一个计数器,然后我执行了我的程序的两个实例,下面是我的代码的一个恢复示例:

#include "Log/Log.h"
#include <chrono>
#include <thread>
INITIALIZE_EASYLOGGINGPP
void log_test() {
long int count = 0;
while (true) {
log_info("Logando..." + std::to_string(count)); // this is defined in Log.h
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
count++;
}
}
int main(){
std::thread t(log_test);
t.detach();
// rest of the code
}

和Log.h/Log.cpp分别为:

#pragma once
#include "easylogging++.h"
#include <mutex>
static std::mutex mtx;
void log_info(std::string s);
void log_error(std::string s);

Log.cpp:

#include "Log.h"
void log_info(std::string s)
{
mtx.lock();
LOG(INFO, ELPP_THREAD_SAFE) << s;
mtx.unlock();
}
void log_error(std::string s)
{
mtx.lock();
LOG(ERROR, ELPP_THREAD_SAFE) << s;
mtx.unlock();
}

和两个可执行文件使用相同的.conf文件,配置如下:

* GLOBAL:
FORMAT               =  "%datetime %msg"
FILENAME             =  "C:/logs/%datetime{%Y-%M-%d}/msgs.log"
ENABLED              =  true
TO_FILE              =  true
TO_STANDARD_OUTPUT   =  false
SUBSECOND_PRECISION  =  6
PERFORMANCE_TRACKING =  true
MAX_LOG_FILE_SIZE    =  2097152 ## 2MB - Comment starts with two hashes (##)

在msgs.log文件的中,我注意到这个示例:

2022-06-22 18:51:24,886631 Logando...288
2022-06-22 18:51:24,901856 Logando...289
2022-06-22 18:51:24,917820 Logando...5
2022-06-22 18:51:24,932827 Logando...291
2022-06-22 18:51:24,948248 Logando...292

在第一个进程中缺少日志290,取而代之的是这个空白行。猜我这个解决方案可能只是为每个进程使用不同的日志文件,但是它不会发生在具有多个线程的单个进程中(如前面的代码示例中实例化线程t1, t2,t3)。我不能只更改一个日志文件到生产中的每个进程,因为它会有很大的影响,所以我如何解决它,我不丢失任何消息?提前感谢!

我想一个解决方案可能只是使用不同的日志文件为每个进程,但它不会发生在一个单一的进程与多个线程(实例化线程t1, t2,t3,如之前的代码示例)

一个进程中的线程共享一个std::mutex mtx的实例,所以它们是正确同步的。也许更重要的是,正确同步的是对单个缓冲区的访问,这是唯一一个写入文件的缓冲区。

两个进程将拥有完全独立的std::mutex mtx实例,如果它们是单线程的,这并不重要,因为只有一个线程在写每个进程的缓冲区。问题是,当写入文件时,两个缓冲区没有相互同步,正如在注释中提到的,这些写入显然不是原子追加。

解决方案是:

  1. 只要使用线程,因为它已经工作了。
  2. 使用共享互斥——这通常是特定于平台的,但是Boost。进程间是一个很好的开始。
  3. 使用两个文件-如果你需要的话,让其他进程跟踪它们并合并成一个文件
  4. 为输出文件使用两个fifo,并让其他进程同时读取它们并将它们合并到一个文件中。它避免了重复磁盘上的文件存储,但可能是*NIX特定的。
  5. 使用网络接收器(请参阅easyloggingc++文档),并让一个进程侦听本地主机上的两个端口…然后把它们组合成一个文件。比fifo更可移植,但也需要更多的代码。

最新更新