I implemented the logger 2 months ago. I know I should review and summarize it. Here is place holder now, so I won’t forget about this post. Hope I will finish it by next week.
This is a review for the logger implementation. At the beginning, I want to log my program to see see heartbeat in every 0.5 sec, and track its performance. It is the first logger at AirLogger. It is very straightforward: Open a file, start to write string, and until I close it. Honestly, I wrote a terrible logger class.
[x] Singleton Pattern. It’s barely a good singleton design.
[x] Log level. I defined 5 log levels to provide different depth message
[x] Macro function wrapper. Use macro to wrap logger function itself
[ ] Thread-safe
[ ] I/O control
Just Open and leave it there, thank I remember to close it before it ends This bad File IO slow my program from 20fps camera capture reduce to 10fps.
[ ] precision timestamp. I used localtime() routine, but it is in second.
Appropriate message format.
After a few weeks, I need a real logger at my work. It is not just heart beat, but also write different level info into files. It should has a very high precision timestamp in millisecond, even nano second level. I want to extract data from each video frame and write into file with this utility. The video is about 30fps or 60 maybe, 1080p. I need to record the timestamp of each frame. If it is real-time camera. The timestamp should be the clock epoch, in microseconds or nanosecond precision. For future work, I want this tool can measure the time elapse for a code block. On my understanding, I will identify a block of code that highly hog the CPU and could processed at GPGPU or DSP. After modify this code block, use CUDA/OpenCL to make code in parallel programming. then we can compare what is different between them.
So consider others implementation, here is something I improved on my logger class.
- Move getInstance to header, and keep header as clean as possible.
disable copy constructor and assignment operators1234MetaLogger(MetaLogger const&) = delete;MetaLogger(MetaLogger&&) = delete;MetaLogger& operator=(MetaLogger const&) = delete;MetaLogger& operator=(MetaLogger &&) = delete;
Use enum to define Logger Level instead of a type struct
Instead of use a log() and switch condition for different level. Make each level log method as deprecated method. And try to use parameter format list to format message. Like this:1std::string error(const char* fat, ...)
Make default destructor as protected12protected:~MetaLogger() = default
each error() or info() only provide the ostream, and use another write(msg) to format the final message.
- Corresponding to last one, make logger I/O as another class. metaLogger only format log message, but call another fileLogger to handle Output stream.
Use constant size buffer1static const int MAX_BUFF 512
Use a mutex lock to access the text buffer
Use a better macro wrap to delegate my write function12#define LOG_ERROR_(fmt, ...) \m_logger_error("0x%08x](%s:%s:%d)" fat, std::this_thread::get_id(), FILENAME, __FUNCTION__, __LINE__, ##__VA_ARGS__)
use va_list, va_start to delegate the debugging message.
- Multi-threading. The original implementation REALLY slow everything down. However, even with multi-threading, I can’t write this message into file very time it calls. Another thread-safe queue.
- Tread-safe queue