C ++中的异步线程安全日志记录

时间:2022-08-11 11:47:25

I'm looking for a way to do asynchronous and thread-safe logging in my C++ project, if possible to one file. I'm currently using cerr and clog for the task, but since they are synchronous, execution shortly pauses every time something is logged. It's a relatively graphics-heavy app, so this kind of thing is quite annoying.

我正在寻找一种在我的C ++项目中进行异步和线程安全日志记录的方法,如果可能的话,可以在一个文件中进行。我目前正在使用cerr和clog来完成任务,但由于它们是同步的,因此每次记录某些内容时执行都会暂停。这是一个相对图形密集的应用程序,所以这种事情非常烦人。

The new logger should use asynchronous I/O to get rid of these pauses. Thread-safety would also be desirable as I intend to add some basic multithreading soon.

新的记录器应该使用异步I / O来摆脱这些暂停。线程安全也是可取的,因为我打算很快添加一些基本的多线程。

I considered a one-file-per-thread approach, but that seemed like it would make managing the logs a nightmare. Any suggestions?

我考虑过每个线程一个文件的方法,但这似乎会使管理日志变成一场噩梦。有什么建议?

5 个解决方案

#1


18  

I noticed this 1 year+ old thread. Maybe the asynchronous logger I wrote could be of interest.

我注意到这个1年+旧线程。也许我写的异步记录器可能很有意思。

http://www.codeproject.com/KB/library/g2log.aspx

G2log uses a protected message queue to forward log entries to a background worker that the slow disk accesses.

G2log使用受保护的消息队列将日志条目转发给慢速磁盘访问的后台工作程序。

I have tried it with a lock-free queue which increased the average time for a LOG call but decreased the worst case time, however I am using the protected queue now as it is cross-platform. It's tested on Windows/Visual Studio 2010 and Ubuntu 11.10/gcc4.6.

我尝试使用无锁队列,这增加了LOG调用的平均时间,但减少了最坏情况时间,但我现在使用受保护的队列,因为它是跨平台的。它在Windows / Visual Studio 2010和Ubuntu 11.10 / gcc4.6上进行了测试。

It's released as public domain so you can do with it what you want with no strings attached.

它是作为公共领域发布的,所以你可以用它来做你想要的,没有任何附加条件。

#2


4  

This is VERY possible and practical. How do I know? I wrote exactly that at my last job. Unfortunately (for us), they now own the code. :-) Sadly, they don't even use it.

这是非常可行和实用的。我怎么知道?我在上一份工作中写到了这一点。不幸的是(对我们而言),他们现在拥有代码。 :-)可悲的是,他们甚至没有使用它。

I intend on writing an open source version in the near future. Meanwhile, I can give you some hints.

我打算在不久的将来编写一个开源版本。同时,我可以给你一些提示。

  1. I/O manipulators are really just function names. You can implement them for your own logging class so that your logger is cout/cin compatible.
  2. I / O操纵器实际上只是函数名称。您可以为自己的日志记录类实现它们,以便您的记录器兼容cout / cin。

  3. Your manipulator functions can tokenize the operations and store them into a queue.
  4. 您的操纵器函数可以对操作进行标记,并将它们存储到队列中。

  5. A thread can be blocked on that queue waiting for chunks of log to come flying through. It then processes the string operations and generates the actual log.
  6. 可以在该队列上阻止线程,等待日志块通过。然后它处理字符串操作并生成实际日志。

This is intrinsically thread compatible since you are using a queue. However, you still would want to put some mutex-like protection around writing to the queue so that a given log << "stuff" << "more stuff"; type operation remains line-atomic.

由于您使用的是队列,因此本质上是线程兼容的。但是,您仍然希望在写入队列时放置一些类似互斥锁的保护,以便给定日志<<“东西”<<“更多东西”;类型操作仍然是行原子的。

Have fun!

#3


1  

I think the proper approach is not one-file-per-thread, but one-thread-per-file. If any one file (or resource in general) in your system is only ever accessed by one thread, thread-safe programming becomes so much easier.

我认为正确的方法不是每个文件一个文件,而是每个文件一个线程。如果系统中的任何一个文件(或一般资源)只能由一个线程访问,则线程安全编程变得更加容易。

So why not make Logger a dedicated thread (or several threads, one per file, if you're logging different things in different files), and in all other threads, writing to log would place the message on the input queue in the appropriate Logger thread, which would get to it after it's done writing the previous message. All it takes is a mutex to protect the queue from adding an event while Logger is reading an event, and a condvar for Logger to wait on when its queue is empty.

那么为什么不让Logger成为一个专用线程(或者几个线程,每个文件一个,如果你在不同文件中记录不同的东西),并且在所有其他线程中,写入日志会将消息放在相应Logger中的输入队列中线程,在写完上一条消息后会到达它。只需要一个互斥锁来保护队列在Logger正在读取事件时添加事件,以及Logger在其队列为空时等待的condvar。

#4


1  

Have you considered using a log library.

您是否考虑过使用日志库?

There are several available, I discovered Pantheios recently and it really seems to be quite incredible.

有几个可用,我最近发现了Pantheios,它看起来真的很不可思议。

It's more a front-end logger, you can customize which system is used. It can interact with ACE or log4cxx for example and it seems really easy to use and configure. The main advantage is that it use typesafe operators, which is always great.

它更像是一个前端记录器,您可以自定义使用哪个系统。例如,它可以与ACE或log4cxx交互,看起来非常容易使用和配置。主要优点是它使用类型安全的运算符,这总是很好。

If you just want a barebone logging library:

如果您只想要一个准系统日志库:

  • ACE
  • log4c*
  • Boost.Log

Pick any :)

挑选任何:)

I should note that it's possible to implement lock-free queues in C++ and that they are great for logging.

我应该注意,可以在C ++中实现无锁队列,并且它们非常适合日志记录。

#5


0  

I had the same issue and I believe I have found the perfect solution. I present to you, a single-header library called loguru: https://github.com/emilk/loguru

我有同样的问题,我相信我找到了完美的解决方案。我向您介绍一个名为loguru的单头库:https://github.com/emilk/loguru

It's simple to use, portable, configurable, macro-based and by default doesn't #include anything (for that sweet, sweet compilation times).

它使用简单,可移植,可配置,基于宏,默认情况下不包含任何内容(为了甜蜜,甜蜜的编译时间)。

#1


18  

I noticed this 1 year+ old thread. Maybe the asynchronous logger I wrote could be of interest.

我注意到这个1年+旧线程。也许我写的异步记录器可能很有意思。

http://www.codeproject.com/KB/library/g2log.aspx

G2log uses a protected message queue to forward log entries to a background worker that the slow disk accesses.

G2log使用受保护的消息队列将日志条目转发给慢速磁盘访问的后台工作程序。

I have tried it with a lock-free queue which increased the average time for a LOG call but decreased the worst case time, however I am using the protected queue now as it is cross-platform. It's tested on Windows/Visual Studio 2010 and Ubuntu 11.10/gcc4.6.

我尝试使用无锁队列,这增加了LOG调用的平均时间,但减少了最坏情况时间,但我现在使用受保护的队列,因为它是跨平台的。它在Windows / Visual Studio 2010和Ubuntu 11.10 / gcc4.6上进行了测试。

It's released as public domain so you can do with it what you want with no strings attached.

它是作为公共领域发布的,所以你可以用它来做你想要的,没有任何附加条件。

#2


4  

This is VERY possible and practical. How do I know? I wrote exactly that at my last job. Unfortunately (for us), they now own the code. :-) Sadly, they don't even use it.

这是非常可行和实用的。我怎么知道?我在上一份工作中写到了这一点。不幸的是(对我们而言),他们现在拥有代码。 :-)可悲的是,他们甚至没有使用它。

I intend on writing an open source version in the near future. Meanwhile, I can give you some hints.

我打算在不久的将来编写一个开源版本。同时,我可以给你一些提示。

  1. I/O manipulators are really just function names. You can implement them for your own logging class so that your logger is cout/cin compatible.
  2. I / O操纵器实际上只是函数名称。您可以为自己的日志记录类实现它们,以便您的记录器兼容cout / cin。

  3. Your manipulator functions can tokenize the operations and store them into a queue.
  4. 您的操纵器函数可以对操作进行标记,并将它们存储到队列中。

  5. A thread can be blocked on that queue waiting for chunks of log to come flying through. It then processes the string operations and generates the actual log.
  6. 可以在该队列上阻止线程,等待日志块通过。然后它处理字符串操作并生成实际日志。

This is intrinsically thread compatible since you are using a queue. However, you still would want to put some mutex-like protection around writing to the queue so that a given log << "stuff" << "more stuff"; type operation remains line-atomic.

由于您使用的是队列,因此本质上是线程兼容的。但是,您仍然希望在写入队列时放置一些类似互斥锁的保护,以便给定日志<<“东西”<<“更多东西”;类型操作仍然是行原子的。

Have fun!

#3


1  

I think the proper approach is not one-file-per-thread, but one-thread-per-file. If any one file (or resource in general) in your system is only ever accessed by one thread, thread-safe programming becomes so much easier.

我认为正确的方法不是每个文件一个文件,而是每个文件一个线程。如果系统中的任何一个文件(或一般资源)只能由一个线程访问,则线程安全编程变得更加容易。

So why not make Logger a dedicated thread (or several threads, one per file, if you're logging different things in different files), and in all other threads, writing to log would place the message on the input queue in the appropriate Logger thread, which would get to it after it's done writing the previous message. All it takes is a mutex to protect the queue from adding an event while Logger is reading an event, and a condvar for Logger to wait on when its queue is empty.

那么为什么不让Logger成为一个专用线程(或者几个线程,每个文件一个,如果你在不同文件中记录不同的东西),并且在所有其他线程中,写入日志会将消息放在相应Logger中的输入队列中线程,在写完上一条消息后会到达它。只需要一个互斥锁来保护队列在Logger正在读取事件时添加事件,以及Logger在其队列为空时等待的condvar。

#4


1  

Have you considered using a log library.

您是否考虑过使用日志库?

There are several available, I discovered Pantheios recently and it really seems to be quite incredible.

有几个可用,我最近发现了Pantheios,它看起来真的很不可思议。

It's more a front-end logger, you can customize which system is used. It can interact with ACE or log4cxx for example and it seems really easy to use and configure. The main advantage is that it use typesafe operators, which is always great.

它更像是一个前端记录器,您可以自定义使用哪个系统。例如,它可以与ACE或log4cxx交互,看起来非常容易使用和配置。主要优点是它使用类型安全的运算符,这总是很好。

If you just want a barebone logging library:

如果您只想要一个准系统日志库:

  • ACE
  • log4c*
  • Boost.Log

Pick any :)

挑选任何:)

I should note that it's possible to implement lock-free queues in C++ and that they are great for logging.

我应该注意,可以在C ++中实现无锁队列,并且它们非常适合日志记录。

#5


0  

I had the same issue and I believe I have found the perfect solution. I present to you, a single-header library called loguru: https://github.com/emilk/loguru

我有同样的问题,我相信我找到了完美的解决方案。我向您介绍一个名为loguru的单头库:https://github.com/emilk/loguru

It's simple to use, portable, configurable, macro-based and by default doesn't #include anything (for that sweet, sweet compilation times).

它使用简单,可移植,可配置,基于宏,默认情况下不包含任何内容(为了甜蜜,甜蜜的编译时间)。