#include #include #include #include #include #include //////////////////////////////////// /* Static Variable Initialization */ //////////////////////////////////// ZMutex ZLog::LogLock; bool ZLog::bIsInitialized = false; ZArray< ZPair > ZLog::LogFiles; ZArray< ZPtr > 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(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 >::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 _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(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 >::Iterator i = ZLog::Delegates.Begin(); i != ZLog::Delegates.End(); i++) (*i)->Execute(_type, _file, _str); } }