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; | |
} |