Initial commit
This commit is contained in:
306
ZUtil/ZLog.cpp
Normal file
306
ZUtil/ZLog.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
#include <ZUtil/ZLog.hpp>
|
||||
#include <ZUtil/ZAlloc.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdarg.h>
|
||||
#include <algorithm>
|
||||
|
||||
////////////////////////////////////
|
||||
/* Static Variable Initialization */
|
||||
////////////////////////////////////
|
||||
|
||||
ZMutex ZLog::LogLock;
|
||||
|
||||
bool ZLog::bIsInitialized = false;
|
||||
|
||||
ZArray< ZPair<std::ofstream*, bool> > ZLog::LogFiles;
|
||||
|
||||
ZArray< ZPtr<ZLogDelegate> > ZLog::Delegates;
|
||||
|
||||
ZString ZLog::LogFileRoot;
|
||||
|
||||
uint64_t* ZLog::UserTick = NULL;
|
||||
uint64_t* ZLog::UserUpdate = NULL;
|
||||
|
||||
uint64_t ZLog::TickEstimate = 0;
|
||||
uint64_t ZLog::UpdateFrameEstimate = 0;
|
||||
|
||||
///////////////////////////
|
||||
/* Local Helper Function */
|
||||
///////////////////////////
|
||||
|
||||
void writeHeader(std::ofstream& logfile, const char* filename)
|
||||
{
|
||||
|
||||
logfile << filename << " : ZUtil version " << ZUTIL_VERSION_STRING << " default log file\n\n";
|
||||
|
||||
#if ZLOG_LEVEL >= ZLOG_LEVEL_INFO
|
||||
logfile << "+------------+------------+\n";
|
||||
logfile << "| Time (sec) | Update No. |\n";
|
||||
logfile << "+------------+------------+\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
void writeFooter(std::ofstream& logfile)
|
||||
{
|
||||
#if ZLOG_LEVEL >= ZLOG_LEVEL_INFO
|
||||
logfile << "+------------+------------+\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
int logAssertHandler(const char* _msg, void *_arg)
|
||||
{
|
||||
URFP(_arg);
|
||||
|
||||
//Log it!
|
||||
SystemLogError("Assertion Failed: \n");
|
||||
SystemLogError(_msg);
|
||||
|
||||
//Let the error propagate
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
/* Static Function Declaration */
|
||||
/////////////////////////////////
|
||||
|
||||
void ZLog::Init(const ZString& _logFileRoot, const ZString& _defaultLogFile, uint64_t* _ticks /*= NULL*/, uint64_t* _update /*= NULL*/)
|
||||
{
|
||||
std::ofstream *logfile;
|
||||
|
||||
//Save our root path
|
||||
ZLog::LogFileRoot = _logFileRoot;
|
||||
|
||||
//Create a default log file
|
||||
ZString logFilePath = ZLog::LogFileRoot + _defaultLogFile;
|
||||
|
||||
logfile = znew_notrack std::ofstream();
|
||||
logfile->open(logFilePath.Data(), std::ios::out);
|
||||
|
||||
while (logfile->fail()) {
|
||||
logFilePath += "_";
|
||||
logfile->open(logFilePath.Data(), std::ios::out);
|
||||
}
|
||||
|
||||
//Write the header
|
||||
writeHeader(*logfile, _defaultLogFile.Data());
|
||||
|
||||
//Add the default log file to the set
|
||||
ZLog::LogFiles.Reserve(16);
|
||||
ZLog::LogFiles.Clear();
|
||||
ZLog::LogFiles.PushBack(ZPair<std::ofstream*, bool>(logfile, true));
|
||||
|
||||
//Set our SST_Assert handlers
|
||||
SST_OS_SetDebugAssertHandler(logAssertHandler, NULL);
|
||||
SST_OS_SetRuntimeAssertHandler(logAssertHandler, NULL);
|
||||
|
||||
ZLog::UserTick = _ticks;
|
||||
ZLog::UserUpdate = _update;
|
||||
|
||||
//We're ready to rock and roll
|
||||
ZLog::bIsInitialized = true;
|
||||
}
|
||||
|
||||
void ZLog::Shutdown()
|
||||
{
|
||||
ZArray< ZPair<std::ofstream*, bool> >::Iterator itr;
|
||||
|
||||
//Iterate and close out
|
||||
for (itr = ZLog::LogFiles.Begin(); itr != ZLog::LogFiles.End(); itr++)
|
||||
{
|
||||
writeFooter(*((*itr).First));
|
||||
|
||||
(*itr).First->close();
|
||||
(*itr).Second = false;
|
||||
|
||||
zdelete (*itr).First;
|
||||
}
|
||||
|
||||
//Flush standard outputs
|
||||
std::cout.flush();
|
||||
std::cerr.flush();
|
||||
|
||||
//Clear our set of log files
|
||||
ZLog::LogFiles.Clear();
|
||||
}
|
||||
|
||||
void ZLog::AddLoggingDelegate(ZPtr<ZLogDelegate> _delegate)
|
||||
{
|
||||
ZLog::LogLock.Acquire();
|
||||
|
||||
ZLog::Delegates.PushBack(_delegate);
|
||||
|
||||
ZLog::LogLock.Release();
|
||||
}
|
||||
|
||||
ZLogFile ZLog::CreateLogFile(const ZString& _fileName)
|
||||
{
|
||||
ZLogFile handle;
|
||||
std::ofstream *file;
|
||||
|
||||
//See if we can early out
|
||||
if (!ZLog::bIsInitialized)
|
||||
{
|
||||
std::cerr << "Attempted to create log file (Before call to Init) : " << _fileName.Data() << std::endl;
|
||||
return (ZLogFile)0;
|
||||
}
|
||||
|
||||
ZString logFilePath = ZLog::LogFileRoot + _fileName;
|
||||
|
||||
//Synchronized Section
|
||||
{
|
||||
//Scoped lock
|
||||
ZLock scopedLock(ZLog::LogLock);
|
||||
|
||||
file = znew_notrack std::ofstream();
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to create log file %s!\n", _fileName.Data());
|
||||
return (ZLogFile)0;
|
||||
}
|
||||
|
||||
file->open(logFilePath.Data(), std::ios::out);
|
||||
|
||||
if (!file->is_open())
|
||||
{
|
||||
//Nope nope nope
|
||||
fprintf(stderr, "Failed to open log file %s!\n", _fileName.Data());
|
||||
zdelete file;
|
||||
return (ZLogFile)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Write the header
|
||||
writeHeader(*file, _fileName.Data());
|
||||
|
||||
//This will give us the index where it will be going
|
||||
handle = ZLog::LogFiles.Size();
|
||||
|
||||
//Add to the set of streams already activated
|
||||
ZLog::LogFiles.PushBack(ZPair<std::ofstream*, bool>(file, true));
|
||||
}
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void ZLog::Resume( ZLogFile _logFile )
|
||||
{
|
||||
//Scoped Lock
|
||||
ZLock scopedLock(ZLog::LogLock);
|
||||
|
||||
ZASSERT_RUNTIME((size_t)_logFile < LogFiles.Size(), "Cannot resume logging to file: file does not exist!");
|
||||
|
||||
ZLog::LogFiles[_logFile].Second = true;
|
||||
}
|
||||
|
||||
void ZLog::Suspend( ZLogFile _logFile )
|
||||
{
|
||||
//Scoped Lock
|
||||
ZLock scopedLock(ZLog::LogLock);
|
||||
|
||||
ZASSERT_RUNTIME((size_t)_logFile < LogFiles.Size(), "Cannot resume logging to file: file does not exist!");
|
||||
|
||||
ZLog::LogFiles[_logFile].Second = false;
|
||||
}
|
||||
|
||||
void ZLog::Printf(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char *_function, const char *_str, ...)
|
||||
{
|
||||
URFP(_function);
|
||||
|
||||
va_list args;
|
||||
|
||||
//Check for easy out
|
||||
if (!ZLog::bIsInitialized)
|
||||
return;
|
||||
|
||||
//Make sure we're null terminated
|
||||
char string[32768];
|
||||
MemSetChar(string, 0, 32768);
|
||||
|
||||
va_start(args, _str);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
vsnprintf_s(string, sizeof(string)-1, sizeof(string)-1, _str, args);
|
||||
#else
|
||||
vsnprintf(string, sizeof(string)-1, _str, args);
|
||||
#endif
|
||||
|
||||
//Write using our existing write function
|
||||
ZLog::WriteLine(_type, _file, _ticks, _updateFrame, string);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void ZLog::WriteLine(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char *_str)
|
||||
{
|
||||
#if ZLOG_LEVEL >= ZLOG_LEVEL_INFO
|
||||
char time[32];
|
||||
char update[32];
|
||||
#endif
|
||||
|
||||
//See if we can early out (should warn)
|
||||
if (!ZLog::bIsInitialized)
|
||||
{
|
||||
std::cerr << "Logging Output (Before call to Init): " << _str << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//Synchronized Section
|
||||
{
|
||||
//Scoped Lock
|
||||
ZLock scopedLock(ZLog::LogLock);
|
||||
|
||||
ZASSERT_RUNTIME((size_t)_file < LogFiles.Size(), "Cannot log to file: file not created!");
|
||||
|
||||
//Get the file and find out if activated
|
||||
std::ofstream *logfile = ZLog::LogFiles[_file].First;
|
||||
bool enabled = ZLog::LogFiles[_file].Second;
|
||||
|
||||
//If we are not currently enabled, we are no longer needed
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
//Get our best guesses
|
||||
if (ZLog::UserTick != NULL) {
|
||||
ZLog::TickEstimate = *ZLog::UserTick;
|
||||
} else if (_ticks > ZLog::TickEstimate) {
|
||||
ZLog::TickEstimate = _ticks;
|
||||
}
|
||||
|
||||
if (ZLog::UserUpdate != NULL) {
|
||||
ZLog::UpdateFrameEstimate = *ZLog::UserUpdate;
|
||||
} else if (_updateFrame > ZLog::UpdateFrameEstimate) {
|
||||
ZLog::UpdateFrameEstimate = _updateFrame;
|
||||
}
|
||||
|
||||
ZASSERT_UTIL(logfile != NULL, "ZLog Error: logfile is NULL!");
|
||||
|
||||
#if ZLOG_LEVEL >= ZLOG_LEVEL_INFO
|
||||
|
||||
//If we are at detailed (or higher) log level, then log the extra details, then the string
|
||||
if (_ticks == 0 && _updateFrame == 0 && ZLog::UserTick == NULL && ZLog::UserUpdate == NULL) {
|
||||
sprintf(time, "?%11.3f", ((float)ZLog::TickEstimate) / 1000.0f);
|
||||
sprintf(update, "?%11lu", ZLog::UpdateFrameEstimate);
|
||||
} else {
|
||||
sprintf(time, "%12.3f", ((float)ZLog::TickEstimate) / 1000.0f);
|
||||
sprintf(update, "%12lu", ZLog::UpdateFrameEstimate);
|
||||
}
|
||||
|
||||
std::cout << _str << std::endl;
|
||||
*logfile << "|" << time << "|" << update << "| " << /*ZConcurrency::GetThreadName() << ": " << */_str << std::endl;
|
||||
|
||||
#else
|
||||
|
||||
std::cout << _str << std::endl;
|
||||
*logfile << _str << std::endl;
|
||||
|
||||
#endif //ZLOG_LEVEL >= ZLOG_LEVEL_DETAILED
|
||||
|
||||
//Let the delegates know what happened
|
||||
for (ZArray< ZPtr<ZLogDelegate> >::Iterator i = ZLog::Delegates.Begin(); i != ZLog::Delegates.End(); i++)
|
||||
(*i)->Execute(_type, _file, _str);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user