Implemented as a singleton (eager as well as lazy).
main.cpp shows how to use it.
Compile with
cmake .
make
Launch with
./loggerdemo
| app.log | |
| .vscode/ | |
| build/ | |
| CMakeFiles/ | |
| CMakeCache.txt | |
| cmake_install.cmake | |
| Makefile | |
| loggerdemo |
| cmake_minimum_required (VERSION 2.6) | |
| project(loggerdemo) | |
| set(CMAKE_CXX_FLAGS | |
| "-O2 -std=c++11") | |
| set(HEADER_FILES | |
| lazylogger.hpp) | |
| add_executable(loggerdemo | |
| main.cpp | |
| lazylogger.cpp | |
| ) |
| #include "lazylogger.hpp" | |
| Logger *Logger::logger = nullptr; |
| #ifndef __LAZYLOGGER_HPP__ | |
| #define __LAZYLOGGER_HPP__ | |
| #include <string> | |
| #include <fstream> | |
| #include <iostream> | |
| #include <sstream> | |
| #include <iomanip> | |
| using namespace std; | |
| class Logger { | |
| private: | |
| ofstream f; | |
| static Logger *logger; | |
| Logger() { /* ... */ } | |
| ~Logger() { | |
| f.close(); | |
| } | |
| public: | |
| static Logger *instance() { | |
| static Cleaner cleaner; | |
| if (logger == nullptr) { | |
| logger = new Logger; | |
| } | |
| return logger; | |
| } | |
| static void init(const string &filename) { | |
| if (instance()->f.is_open()) { | |
| throw runtime_error{ "Logger already initialized" }; | |
| } | |
| instance()->f.open(filename, | |
| ios::binary | ios::app); | |
| } | |
| Logger(const Logger &) = delete; | |
| Logger& operator=(const Logger &) = delete; | |
| void out(const string &msg) { | |
| if (!instance()->f.is_open()) { | |
| throw runtime_error{ "Logger not initialized" }; | |
| } | |
| time_t t = time(nullptr); | |
| stringstream ss; | |
| ss << put_time(localtime(&t), | |
| "%Y-%m-%dT%H:%M:%S ") | |
| << msg << endl; | |
| f << ss.str(); | |
| } | |
| void flush() { | |
| f.flush(); | |
| } | |
| class Cleaner { | |
| public: | |
| ~Cleaner() { | |
| if (Logger::logger != nullptr) { | |
| delete Logger::logger; | |
| Logger::logger = nullptr; | |
| } | |
| } | |
| }; | |
| }; | |
| #endif // __LAZYLOGGER_HPP__ |
| #ifndef __LOGGER_HPP__ | |
| #define __LOGGER_HPP__ | |
| #include <string> | |
| #include <fstream> | |
| #include <iostream> | |
| #include <sstream> | |
| #include <iomanip> | |
| #include <mutex> | |
| using namespace std; | |
| class Logger { | |
| private: | |
| mutex mtx; | |
| ofstream f; | |
| Logger() = default; | |
| Logger(const Logger&) | |
| = delete; | |
| Logger& operator=(const Logger&) | |
| = delete; | |
| ~Logger() { | |
| f.close(); | |
| } | |
| public: | |
| static Logger &instance() { | |
| static Logger logger; | |
| return logger; | |
| } | |
| static void init(const string &filename) { | |
| if (instance().f.is_open()) { | |
| throw runtime_error{ "Logger already initialized" }; | |
| } | |
| instance().f.open(filename, | |
| ios::binary | ios::app); | |
| } | |
| void out(const string &msg) { | |
| unique_lock<mutex> lock(mtx); | |
| time_t t = time(nullptr); | |
| stringstream ss; | |
| ss << put_time(localtime(&t), | |
| "%Y-%m-%dT%H:%M:%S ") | |
| << msg << endl; | |
| f << ss.str(); | |
| } | |
| void flush() { | |
| f.flush(); | |
| } | |
| }; | |
| #endif |
| #include "lazylogger.hpp" | |
| #include <string> | |
| int main(int argc, char *argv[]) { | |
| std::string msg = (argc > 1) | |
| ? argv[1] | |
| : "lorem ipsum ..."; | |
| Logger::init("app.log"); | |
| Logger *logger = Logger::instance(); | |
| logger->out(msg); | |
| return 0; | |
| } |