Added some utility files
Tested to be working although INIFile is currently a windows-only utility and so is currently removed from the project (but still in the repo as it may be re-written to be cross-platform)Gui_Panel_Refactor
parent
c0c1a48e22
commit
fd424abd16
@ -0,0 +1,65 @@
|
||||
/******************************************************************************
|
||||
* Filename: HighResTimer.cpp
|
||||
* Date: 12/06/2010
|
||||
* Mod. Date: 03/21/2018
|
||||
* Author: Joseph R. Pollack
|
||||
* Purpose: A high resolution timer suitable for profiling code. This new
|
||||
* version has stripped out the game specific functionality and
|
||||
* does not include windows.h in the header.
|
||||
******************************************************************************/
|
||||
|
||||
#include "HighResTimer.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Lunarium
|
||||
{
|
||||
|
||||
HighResTimer::HighResTimer()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HighResTimer::Initialize()
|
||||
{
|
||||
mStartTime = 0;
|
||||
LARGE_INTEGER tickFreq;
|
||||
QueryPerformanceFrequency(&tickFreq);
|
||||
mTickFrequency = tickFreq.QuadPart;
|
||||
}
|
||||
|
||||
// Starts or re-starts the timer.
|
||||
void HighResTimer::Reset()
|
||||
{
|
||||
LARGE_INTEGER tickStart;
|
||||
QueryPerformanceCounter(&tickStart);
|
||||
mStartTime = tickStart.QuadPart;
|
||||
}
|
||||
|
||||
|
||||
// Returns the amount of time in microseconds since the last Reset() call.
|
||||
int64_t HighResTimer::GetElapsedTime()
|
||||
{
|
||||
LARGE_INTEGER ticks;
|
||||
QueryPerformanceCounter(&ticks);
|
||||
int64_t elapsedMicro = ticks.QuadPart - mStartTime;
|
||||
|
||||
elapsedMicro *= mcMils;
|
||||
elapsedMicro /= mTickFrequency;
|
||||
|
||||
return elapsedMicro;
|
||||
}
|
||||
|
||||
|
||||
double HighResTimer::GetElapsedSeconds()
|
||||
{
|
||||
int64_t emicro = GetElapsedTime();
|
||||
double dmicro = ((double)emicro);
|
||||
double dmcMils = ((double)mcMils);
|
||||
double seconds = dmicro / dmcMils;
|
||||
return seconds;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
/******************************************************************************
|
||||
* Filename: HighResTimer.h
|
||||
* Date: 12/06/2010
|
||||
* Mod. Date: 03/21/2018
|
||||
* Author: Joseph R. Pollack
|
||||
* Purpose: A high resolution timer suitable for profiling code. This new
|
||||
* version has stripped out the game specific functionality and
|
||||
* does not include windows.h in the header.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef HIGH_RES_TIMER_H_
|
||||
#define HIGH_RES_TIMER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
namespace Lunarium
|
||||
{
|
||||
|
||||
class HighResTimer
|
||||
{
|
||||
public:
|
||||
// NOTE: Currently unused
|
||||
enum eUnits { SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS, PICOSECONDS };
|
||||
|
||||
public:
|
||||
|
||||
HighResTimer();
|
||||
|
||||
void Initialize();
|
||||
|
||||
// Starts or re starts the timer.
|
||||
void Reset();
|
||||
|
||||
// Returns the amount of time in microseconds since the last Reset() call.
|
||||
int64_t GetElapsedTime();
|
||||
|
||||
// Returns the elapsed time in terms of seconds
|
||||
double GetElapsedSeconds();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
int64_t mStartTime;
|
||||
int64_t mTickFrequency;
|
||||
|
||||
|
||||
|
||||
const int mcMils = 1000000;
|
||||
const int mcBils = 1000000000;
|
||||
const long long mcTrils = 1000000000000;
|
||||
|
||||
/* // OLD MEMBERS
|
||||
long long m_TickFreqQuadPart;
|
||||
double m_StartTime;
|
||||
*/
|
||||
|
||||
};
|
||||
}
|
||||
#endif // HIGH_RES_TIMER_H_
|
||||
@ -0,0 +1,109 @@
|
||||
/******************************************************************************
|
||||
* File - INIFile.h
|
||||
* Author - Joey Pollack
|
||||
* Date - 2017/11/28 (y/m/d)
|
||||
* Mod Date - 2017/11/28 (y/m/d)
|
||||
* Description - Read/Write from a .ini file
|
||||
******************************************************************************/
|
||||
|
||||
#include "INIFile.h"
|
||||
|
||||
// TODO: This needs to be re-written without the windows-specific functions
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Lunarium
|
||||
{
|
||||
INIFile::INIFile(const char * filename)
|
||||
{
|
||||
mFullPath = filename;
|
||||
}
|
||||
|
||||
INIFile::~INIFile()
|
||||
{
|
||||
}
|
||||
|
||||
std::string INIFile::Read(const char* section, const char* key)
|
||||
{
|
||||
char buffer[256];
|
||||
GetPrivateProfileStringA(section, key, nullptr, buffer, 256, mFullPath.c_str());
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
int INIFile::ReadInt(const char* section, const char* key)
|
||||
{
|
||||
int val = GetPrivateProfileIntA(section, key, -1, mFullPath.c_str());
|
||||
return val;
|
||||
}
|
||||
|
||||
bool INIFile::ReadBool(const char* section, const char* key)
|
||||
{
|
||||
std::string buffer = Read(section, key);
|
||||
|
||||
if (buffer.size() < 1)
|
||||
throw std::runtime_error("ReadBool() Failed: buffer was empty!");
|
||||
|
||||
std::transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower);
|
||||
|
||||
if (buffer == std::string("false"))
|
||||
return false;
|
||||
|
||||
if (buffer == std::string("true"))
|
||||
return true;
|
||||
|
||||
throw std::runtime_error("ReadBool() Failed: buffer not a boolean value!");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
double INIFile::ReadDouble(const char* section, const char* key)
|
||||
{
|
||||
throw "Not implemented!";
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void INIFile::Write(const char * section, const char * key, const char * value)
|
||||
{
|
||||
WritePrivateProfileStringA(section, key, value, mFullPath.c_str());
|
||||
}
|
||||
|
||||
void INIFile::WriteInt(const char * section, const char * key, int value)
|
||||
{
|
||||
std::string strVal = std::to_string(value);
|
||||
WritePrivateProfileStringA(section, key, strVal.c_str(), mFullPath.c_str());
|
||||
}
|
||||
|
||||
void INIFile::WriteBool(const char * section, const char * key, bool value)
|
||||
{
|
||||
std::string strVal = "true";
|
||||
if (!value)
|
||||
{
|
||||
strVal = "false";
|
||||
}
|
||||
|
||||
WritePrivateProfileStringA(section, key, strVal.c_str(), mFullPath.c_str());
|
||||
}
|
||||
|
||||
void INIFile::WriteDouble(const char * section, const char * key, double value)
|
||||
{
|
||||
throw "INIFile::WriteDouble Not implemented!";
|
||||
}
|
||||
|
||||
bool INIFile::KeyExists(const char* section, const char* key)
|
||||
{
|
||||
return Read(section, key).length() > 0;
|
||||
}
|
||||
|
||||
void INIFile::DeleteKey(const char* section, const char* key)
|
||||
{
|
||||
Write(section, key, nullptr);
|
||||
}
|
||||
|
||||
void INIFile::DeleteSection(const char * section)
|
||||
{
|
||||
Write(section, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
/******************************************************************************
|
||||
* File - INIFile.h
|
||||
* Author - Joey Pollack
|
||||
* Date - 2017/11/28 (y/m/d)
|
||||
* Mod Date - 2017/11/28 (y/m/d)
|
||||
* Description - Read/Write from a .ini file
|
||||
* Based on the C# class writen by Danny Beckett and released
|
||||
* to public domain:
|
||||
* https://stackoverflow.com/questions/217902/reading-writing-an-ini-file
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _INI_FILE_H_
|
||||
#define _INI_FILE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Lunarium
|
||||
{
|
||||
class INIFile
|
||||
{
|
||||
public:
|
||||
|
||||
// filename must be a full, absolute path to the .ini file.
|
||||
INIFile(const char* filename);
|
||||
~INIFile();
|
||||
|
||||
// Read methods
|
||||
std::string Read(const char* section, const char* key);
|
||||
int ReadInt(const char* section, const char* key);
|
||||
bool ReadBool(const char* section, const char* key);
|
||||
double ReadDouble(const char* section, const char* key);
|
||||
|
||||
// Write methods
|
||||
void Write(const char * section, const char* key, const char* value);
|
||||
void WriteInt(const char * section, const char* key, int value);
|
||||
void WriteBool(const char * section, const char* key, bool value);
|
||||
void WriteDouble(const char * section, const char* key, double value);
|
||||
|
||||
|
||||
// Management
|
||||
bool KeyExists(const char* section, const char* key);
|
||||
|
||||
void DeleteKey(const char* section, const char* key);
|
||||
void DeleteSection(const char* section);
|
||||
|
||||
|
||||
private:
|
||||
bool mbFileOpen;
|
||||
|
||||
std::string mFullPath;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // _INI_FILE_H_
|
||||
@ -0,0 +1,414 @@
|
||||
/******************************************************************************
|
||||
* File - Logger.h
|
||||
* Author - Joey Pollack
|
||||
* Date - 2019/06/24 (y/m/d)
|
||||
* Mod Date - 2019/06/26 (y/m/d)
|
||||
* Description - Main interface to the logging system. Manages a linked
|
||||
* list of built-in and user-defined listerers.
|
||||
******************************************************************************/
|
||||
|
||||
#include "Logger.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
namespace Lunarium
|
||||
{
|
||||
//namespace LogLevel
|
||||
//{
|
||||
// bool LevelIsSet(uint16_t buf, uint16_t mask)
|
||||
// {
|
||||
// return buf & mask;
|
||||
// }
|
||||
|
||||
// std::string FormatLevel(uint16_t level)
|
||||
// {
|
||||
// if (LevelIsSet(level, FATAL_ERROR))
|
||||
// {
|
||||
// return "[FATAL ERROR] ";
|
||||
// }
|
||||
// else if (LevelIsSet(level, ERROR))
|
||||
// {
|
||||
// return "[ERROR] ";
|
||||
// }
|
||||
// else if (LevelIsSet(level, WARNING))
|
||||
// {
|
||||
// return "[WARNING] ";
|
||||
// }
|
||||
// else if (LevelIsSet(level, INFO))
|
||||
// {
|
||||
// return "[INFO] ";
|
||||
// }
|
||||
// else if (LevelIsSet(level, INFO_VERBOSE))
|
||||
// {
|
||||
// return "[INFO_VERBOSE] ";
|
||||
// }
|
||||
// else if (LevelIsSet(level, OGL_DEBUG))
|
||||
// {
|
||||
// return "[OGL_DEBUG] ";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return "[UNKNOWN] ";
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//namespace LogCategory
|
||||
//{
|
||||
// bool CategoryIsSet(uint16_t buf, uint16_t mask)
|
||||
// {
|
||||
// return buf & mask;
|
||||
// }
|
||||
// std::string FormatCategory(uint16_t level)
|
||||
// {
|
||||
// if (CategoryIsSet(level, CORE))
|
||||
// {
|
||||
// return "[CORE] ";
|
||||
// }
|
||||
// else if (CategoryIsSet(level, WINDOW_CONTROLLER))
|
||||
// {
|
||||
// return "[WINDOW CONTROLLER] ";
|
||||
// }
|
||||
// else if (CategoryIsSet(level, GRAPHICS))
|
||||
// {
|
||||
// return "[GRAPHICS] ";
|
||||
// }
|
||||
// else if (CategoryIsSet(level, UTILITIES))
|
||||
// {
|
||||
// return "[UTILITIES] ";
|
||||
// }
|
||||
// else if (CategoryIsSet(level, USER_PROJECT))
|
||||
// {
|
||||
// return "[USER PROJECT] ";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return "[UNKNOWN] ";
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
LogListener::LogListener(uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
|
||||
: mAcceptedLogLevels(acceptedLogLevels), mAcceptedLogCategories(acceptedLogCategories), mMyName(myName)
|
||||
{
|
||||
}
|
||||
|
||||
const std::string & LogListener::GetName() const
|
||||
{
|
||||
return mMyName;
|
||||
}
|
||||
|
||||
bool LogListener::CategoryIsSet(uint32_t id) const
|
||||
{
|
||||
return mAcceptedLogCategories & id;
|
||||
}
|
||||
|
||||
bool LogListener::LevelIsSet(uint32_t id) const
|
||||
{
|
||||
return mAcceptedLogLevels & id;
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// ========================================================================
|
||||
// Standard Listener
|
||||
// ========================================================================
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
StandardListener::StandardListener(uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
|
||||
: LogListener(acceptedLogLevels, acceptedLogCategories, myName)
|
||||
{
|
||||
}
|
||||
|
||||
bool StandardListener::Log(LogMessage& message)
|
||||
{
|
||||
if (!LevelIsSet(message.LogLevel) ||
|
||||
!CategoryIsSet(message.LogCategory))
|
||||
return false;
|
||||
|
||||
std::cout << std::endl << Logger::TimeStamp() << Logger::GetCategoryName(message.LogCategory)
|
||||
<< Logger::GetLevelName(message.LogLevel) << message.Message;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// ========================================================================
|
||||
// Error Listener
|
||||
// ========================================================================
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
ErrorListener::ErrorListener(uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
|
||||
: LogListener(acceptedLogLevels, acceptedLogCategories, myName)
|
||||
{
|
||||
}
|
||||
|
||||
bool ErrorListener::Log(LogMessage& message)
|
||||
{
|
||||
if (!LevelIsSet(message.LogLevel) ||
|
||||
!CategoryIsSet(message.LogCategory))
|
||||
return false;
|
||||
|
||||
std::cerr << std::endl << Logger::TimeStamp() << Logger::GetCategoryName(message.LogCategory)
|
||||
<< Logger::GetLevelName(message.LogLevel) << message.Message;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// ========================================================================
|
||||
// File Listener
|
||||
// ========================================================================
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
FileListener::FileListener(std::ofstream & of, uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
|
||||
: mOF(of), LogListener(acceptedLogLevels, acceptedLogCategories, myName)
|
||||
{
|
||||
}
|
||||
|
||||
bool FileListener::Log(LogMessage& message)
|
||||
{
|
||||
if (!LevelIsSet(message.LogLevel) ||
|
||||
!CategoryIsSet(message.LogCategory))
|
||||
return false;
|
||||
|
||||
mOF << std::endl << Logger::TimeStamp() << Logger::GetCategoryName(message.LogCategory)
|
||||
<< Logger::GetLevelName(message.LogLevel) << message.Message;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// ========================================================================
|
||||
// Main Logger
|
||||
// ========================================================================
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Logger* Logger::mInstance = nullptr;
|
||||
uint32_t Logger::mNextCategoryID = 0x01;
|
||||
uint32_t Logger::mNextLevelID = 0x01;
|
||||
std::map<uint32_t, std::string> Logger::mCategoryNames;
|
||||
std::map<uint32_t, std::string> Logger::mLevelNames;
|
||||
|
||||
std::string Logger::TimeStamp()
|
||||
{
|
||||
time_t t = time(0);
|
||||
|
||||
struct tm now;
|
||||
localtime_s(&now, &t);
|
||||
|
||||
std::ostringstream oss("");
|
||||
oss << "[" << (now.tm_year + 1900) << "/";
|
||||
oss << std::setfill('0') << std::setw(2);
|
||||
oss << (now.tm_mon + 1) << "/"
|
||||
<< std::setw(2) << now.tm_mday << " -- "
|
||||
<< std::setw(2) << now.tm_hour << ":"
|
||||
<< std::setw(2) << now.tm_min << ":"
|
||||
<< std::setw(2) << now.tm_sec << "] ";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
Logger::Logger()
|
||||
{
|
||||
|
||||
// Register built-in levels
|
||||
RegisterLevel("INFO");
|
||||
RegisterLevel("WARNING");
|
||||
RegisterLevel("ERROR");
|
||||
RegisterLevel("FATAL_ERROR");
|
||||
RegisterLevel("INFO_VERBOSE");
|
||||
RegisterLevel("OGL_DEBUG");
|
||||
|
||||
RegisterCategory("CORE");
|
||||
RegisterCategory("WINDOW_CONTROLLER");
|
||||
RegisterCategory("GRAPHICS");
|
||||
RegisterCategory("UTILITIES");
|
||||
}
|
||||
|
||||
Logger * Logger::GetInstance()
|
||||
{
|
||||
if (!Logger::mInstance)
|
||||
{
|
||||
Logger::mInstance = new Logger;
|
||||
Logger::mInstance->mTimer.Reset();
|
||||
}
|
||||
|
||||
return Logger::mInstance;
|
||||
}
|
||||
|
||||
void Logger::FreeInstance()
|
||||
{
|
||||
delete mInstance;
|
||||
mInstance = nullptr;
|
||||
|
||||
Logger::mNextCategoryID = 0x01;
|
||||
Logger::mNextLevelID = 0x01;
|
||||
|
||||
Logger::mCategoryNames.clear();
|
||||
Logger::mLevelNames.clear();
|
||||
}
|
||||
|
||||
uint32_t Logger::RegisterCategory(const char * name)
|
||||
{
|
||||
Logger::mCategoryNames[mNextCategoryID] = name;
|
||||
uint32_t id = mNextCategoryID;
|
||||
mNextCategoryID = mNextCategoryID << 1;
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t Logger::RegisterLevel(const char * name)
|
||||
{
|
||||
Logger::mLevelNames[mNextLevelID] = name;
|
||||
uint32_t id = mNextLevelID;
|
||||
mNextLevelID = mNextLevelID << 1;
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string Logger::GetCategoryName(uint32_t id)
|
||||
{
|
||||
if (Logger::mCategoryNames.find(id) == Logger::mCategoryNames.end())
|
||||
return "[]";
|
||||
|
||||
std::string name = "[";
|
||||
name += Logger::mCategoryNames[id];
|
||||
name += "] ";
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string Logger::GetLevelName(uint32_t id)
|
||||
{
|
||||
if (Logger::mLevelNames.find(id) == Logger::mLevelNames.end())
|
||||
return "[]";
|
||||
|
||||
std::string name = "[";
|
||||
name += Logger::mLevelNames[id];
|
||||
name += "] ";
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
LogListener* Logger::AddListener(LogListener * pl)
|
||||
{
|
||||
mListeners.push_back(pl);
|
||||
return pl;
|
||||
}
|
||||
|
||||
LogListener* Logger::RemoveListener(LogListener * pl)
|
||||
{
|
||||
mListeners.remove(pl);
|
||||
return pl;
|
||||
}
|
||||
|
||||
LogListener* Logger::RemoveListener(const char * withName)
|
||||
{
|
||||
LogListener* pl = nullptr;
|
||||
for (auto iter = mListeners.begin(); iter != mListeners.end(); iter++)
|
||||
{
|
||||
if ((*iter)->GetName() == withName)
|
||||
{
|
||||
pl = (*iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mListeners.remove(pl);
|
||||
return pl;
|
||||
}
|
||||
|
||||
void Logger::FreeAllListeners()
|
||||
{
|
||||
for (auto iter = mListeners.begin(); iter != mListeners.end(); iter++)
|
||||
{
|
||||
delete (*iter);
|
||||
}
|
||||
|
||||
mListeners.clear();
|
||||
}
|
||||
|
||||
void Logger::ClearBacklog()
|
||||
{
|
||||
mBacklog.clear();
|
||||
}
|
||||
|
||||
void Logger::Log(uint32_t logCategory, uint32_t logLevel, const char * message, ...)
|
||||
{
|
||||
// clear the buffer
|
||||
memset(mBuffer, 0, 1024);
|
||||
|
||||
// Fill the buffer with the formatted message
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
vsprintf_s(mBuffer, BUFFER_SIZE, message, args);
|
||||
va_end(args);
|
||||
|
||||
double timeStamp = mTimer.GetElapsedSeconds();
|
||||
|
||||
LogMessage lm;
|
||||
lm.LogCategory = logCategory;
|
||||
lm.LogLevel = logLevel;
|
||||
lm.Message = mBuffer;
|
||||
lm.Repeats = 0;
|
||||
lm.RepeatAlertSent = false;
|
||||
lm.SentTimeStamp = timeStamp;
|
||||
|
||||
bool send = true;
|
||||
bool track = true;
|
||||
|
||||
// Check for repeats
|
||||
for (int i = 0; i < mBacklog.size(); i++)
|
||||
{
|
||||
LogMessage& prevMsg = mBacklog[i];
|
||||
if (prevMsg.Message == lm.Message)
|
||||
{
|
||||
|
||||
if (prevMsg.RepeatAlertSent)
|
||||
{
|
||||
send = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// only suppress the messsage if it has been less than
|
||||
// 1 second since it was last sent
|
||||
double timeSinceLastSend = timeStamp - prevMsg.SentTimeStamp;
|
||||
if (timeSinceLastSend <= 1.0)
|
||||
{
|
||||
prevMsg.Repeats += 1;
|
||||
|
||||
if (prevMsg.Repeats > 100 && !prevMsg.RepeatAlertSent)
|
||||
{
|
||||
lm.Message = lm.Message + " [This message has rapidly repeated over 100 times! No more repeats will be sent out!]";
|
||||
prevMsg.RepeatAlertSent = true;
|
||||
track = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
send = false;
|
||||
}
|
||||
}
|
||||
|
||||
prevMsg.SentTimeStamp = timeStamp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!send)
|
||||
return;
|
||||
|
||||
// Send to all listeners
|
||||
for (auto iter = mListeners.begin(); iter != mListeners.end(); iter++)
|
||||
{
|
||||
if ((*iter)->Log(lm))
|
||||
{
|
||||
// Track which listeners handle the message
|
||||
lm.HandledBy.push_back((*iter)->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
if (track)
|
||||
mBacklog.push_back(lm);
|
||||
}
|
||||
|
||||
const std::vector<LogMessage>& Logger::GetBacklog() const
|
||||
{
|
||||
return mBacklog;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,182 @@
|
||||
/******************************************************************************
|
||||
* File - Logger.h
|
||||
* Author - Joey Pollack
|
||||
* Date - 2019/06/24 (y/m/d)
|
||||
* Mod Date - 2019/06/26 (y/m/d)
|
||||
* Description - Main interface to the logging system. Manages a linked
|
||||
* list of built-in and user-defined listerers.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LOGGER_H_
|
||||
#define LOGGER_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
|
||||
// TODO: Remove the dependence on HighResTimer.h
|
||||
// OR re-write HighResTimer with modern timer code
|
||||
#include "HighResTimer.h"
|
||||
|
||||
// Conflict with a region flag in wingdi.h
|
||||
#undef ERROR
|
||||
|
||||
namespace Lunarium
|
||||
{
|
||||
namespace LogLevel
|
||||
{
|
||||
const uint16_t ANY = 0xFFFF;
|
||||
const uint16_t INFO = 0x0001;
|
||||
const uint16_t WARNING = 0x0002;
|
||||
const uint16_t ERROR = 0x0004;
|
||||
const uint16_t FATAL_ERROR = 0x0008;
|
||||
const uint16_t INFO_VERBOSE = 0x0010;
|
||||
const uint16_t OGL_DEBUG = 0x0020;
|
||||
}
|
||||
|
||||
namespace LogCategory
|
||||
{
|
||||
const uint16_t ANY = 0xFFFF;
|
||||
const uint16_t CORE = 0x0001;
|
||||
const uint16_t WINDOW_CONTROLLER = 0x0002;
|
||||
const uint16_t GRAPHICS = 0x0004;
|
||||
const uint16_t UTILITIES = 0x0008;
|
||||
//const uint16_t USER_PROJECT = 0x0010;
|
||||
}
|
||||
|
||||
struct LogMessage
|
||||
{
|
||||
// The ID of the category
|
||||
uint32_t LogCategory;
|
||||
|
||||
// The ID of the Level
|
||||
uint32_t LogLevel;
|
||||
|
||||
std::string Message;
|
||||
std::vector<std::string> HandledBy;
|
||||
uint32_t Repeats;
|
||||
bool RepeatAlertSent;
|
||||
double SentTimeStamp;
|
||||
};
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// ========================================================================
|
||||
// LISTENER CLASSES
|
||||
// ========================================================================
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Log Listener interface class
|
||||
class LogListener
|
||||
{
|
||||
public:
|
||||
LogListener(uint32_t acceptedLogLevels = LogLevel::ANY, uint32_t acceptedLogCategories = LogLevel::ANY, const char* myName = "UNKNOWN");
|
||||
virtual bool Log(LogMessage& message) = 0;
|
||||
|
||||
const std::string& GetName() const;
|
||||
|
||||
bool CategoryIsSet(uint32_t id) const;
|
||||
bool LevelIsSet(uint32_t id) const;
|
||||
|
||||
protected:
|
||||
uint32_t mAcceptedLogCategories;
|
||||
uint32_t mAcceptedLogLevels;
|
||||
std::string mMyName;
|
||||
};
|
||||
|
||||
|
||||
// Outputs all (by default) messages to std::cout
|
||||
// Adds a time stamp and the log level to the message.
|
||||
class StandardListener : public LogListener
|
||||
{
|
||||
public:
|
||||
StandardListener(uint32_t acceptedLogLevels = LogLevel::ANY,
|
||||
uint32_t acceptedLogCategories = LogCategory::ANY, const char* myName = "StandardListener");
|
||||
bool Log(LogMessage& message);
|
||||
};
|
||||
|
||||
|
||||
// Outputs Errors and Fatal Errors to std::err
|
||||
// Adds a time stamp and the log level to the message.
|
||||
class ErrorListener : public LogListener
|
||||
{
|
||||
public:
|
||||
ErrorListener(uint32_t acceptedLogLevels = LogLevel::ERROR | LogLevel::FATAL_ERROR,
|
||||
uint32_t acceptedLogCategories = LogCategory::ANY, const char* myName = "ErrorListener");
|
||||
bool Log(LogMessage& message);
|
||||
};
|
||||
|
||||
|
||||
// Outputs all (by default) messages to the given std::ofstream.
|
||||
// Adds a time stamp and the log level to the message.
|
||||
class FileListener : public LogListener
|
||||
{
|
||||
public:
|
||||
FileListener(std::ofstream& of, uint32_t acceptedLogLevels = LogLevel::ANY,
|
||||
uint32_t acceptedLogCategories = LogCategory::ANY, const char* myName = "FileListener");
|
||||
bool Log(LogMessage& message);
|
||||
|
||||
private:
|
||||
std::ofstream& mOF;
|
||||
};
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// ========================================================================
|
||||
// MAIN LOGGERCLASS
|
||||
// ========================================================================
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
static std::string TimeStamp();
|
||||
static Logger* GetInstance();
|
||||
static void FreeInstance();
|
||||
|
||||
static uint32_t RegisterCategory(const char* name);
|
||||
static uint32_t RegisterLevel(const char* name);
|
||||
static std::string GetCategoryName(uint32_t id);
|
||||
static std::string GetLevelName(uint32_t id);
|
||||
LogListener* AddListener(LogListener* pl);
|
||||
|
||||
// This method does NOT delete the listener's memory!
|
||||
LogListener* RemoveListener(LogListener* pl);
|
||||
|
||||
// This method does NOT delete the listener's memory!
|
||||
LogListener* RemoveListener(const char* withName);
|
||||
|
||||
// Calls delete on all listeners and clears the list
|
||||
void FreeAllListeners();
|
||||
|
||||
void ClearBacklog();
|
||||
|
||||
// The message argument and the variable argument list work just like
|
||||
// printf. Use the same formatters as printf when calling this function.
|
||||
// Messages must be shorter than 1024 bytes.
|
||||
void Log(uint32_t logCategory, uint32_t logLevel, const char* message, ...);
|
||||
|
||||
const std::vector<LogMessage>& GetBacklog() const;
|
||||
|
||||
private:
|
||||
static Logger* mInstance;
|
||||
static uint32_t mNextCategoryID;
|
||||
static uint32_t mNextLevelID;
|
||||
static std::map<uint32_t, std::string> mLevelNames;
|
||||
static std::map<uint32_t, std::string> mCategoryNames;
|
||||
std::list<LogListener*> mListeners;
|
||||
std::vector<LogMessage> mBacklog;
|
||||
char mBuffer[BUFFER_SIZE];
|
||||
HighResTimer mTimer;
|
||||
|
||||
private:
|
||||
Logger();
|
||||
Logger(const Logger&) = delete;
|
||||
const Logger& operator=(const Logger&) = delete;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LOGGER_H_
|
||||
@ -0,0 +1,2 @@
|
||||
[section]
|
||||
var=42
|
||||
Loading…
Reference in New Issue