DevLog - Wil Taylor

DevLog - Wil Taylor

Postby s173177 » May 10th, 2018, 7:08 pm

Exercises – Threading

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());
   }
}
s173177
 
Posts: 40
Joined: October 11th, 2017, 12:52 pm

Return to Complex Game Systems

Who is online

Users browsing this forum: No registered users and 1 guest