logger.h
- Code: Select all
/**
* @file logger.h
* @author Wil Taylor (wilfridtaylor@gmail.com)
* @date 25/4/2018
* @version 1.0
*
* @brief Logger
*
* @section DESCRIPTION
*
* This is a simple logging class which uses a worker thread to write logs to disk.
*
*/
#ifndef __LOGGER_H_
#define __LOGGER_H_
#include <string>
#include <thread>
#include <mutex>
#include <queue>
using namespace std;
class logger
{
public:
/**
* \breif Constructor
* \param filename Filename of log file to create or appened
*/
logger(string filename);
/**
* \breif Constructor
* \param stream stream to write log data too.
*/
logger(ostream& stream);
~logger();
/**
* \breif Writes message to log file
* \param message Message to write to log file.
*/
void WriteToLog(const string& message);
/**
* \breif Returns true if there is an error with the log file.
*/
bool isInErrorState() { return m_inErrorState;}
private:
thread* m_thread;
ostream* m_logstream;
mutex* m_mutex;
queue<string> m_logMessages;
bool m_exiting;
bool m_inErrorState;
bool m_closeStreamOnExit;
void logHandler();
};
#endif
logger.cpp
- Code: Select all
#include "Logger.h"
#include <fstream>
logger::logger(string filename)
{
auto out = new ofstream();
out->open(filename, ofstream::out | ofstream::app);
m_inErrorState = !out->is_open();
m_logstream = out;
m_exiting = false;
m_mutex = new mutex;
m_thread = new thread(&logger::logHandler, this);
m_closeStreamOnExit = true;
}
logger::logger(ostream& stream)
{
m_logstream = &stream;
m_exiting = false;
m_mutex = new mutex;
m_thread = new thread(&logger::logHandler, this);
m_closeStreamOnExit = false;
}
logger::~logger()
{
//Letting log file finish writing before closing.
while (true)
{
m_mutex->lock();
if (m_logMessages.empty())
{
m_mutex->unlock();
break;
}
m_mutex->unlock();
}
m_exiting = true;
m_thread->join();
delete m_thread;
delete m_mutex;
//Only close log stream if we created it.
if (m_closeStreamOnExit)
{
m_logstream->flush();
delete m_logstream;
}
}
void logger::WriteToLog(const string& message)
{
m_mutex->lock();
m_logMessages.push(message);
m_mutex->unlock();
}
void logger::logHandler()
{
while(!m_exiting)
{
m_mutex->lock();
//If log message queue is empty then sleep
if(m_logMessages.empty())
{
m_mutex->unlock();
this_thread::sleep_for(chrono::duration<float> (0.1f));
continue;
}
string line = m_logMessages.front();
line += "\n";
m_logMessages.pop();
//If there was an error with log file exit and report error.
if (m_logstream->bad() || m_logstream->fail())
{
m_inErrorState = true;
m_mutex->unlock();
return;
}
m_mutex->unlock();
m_logstream->write(line.c_str(), line.length());
}
}