#include "precompiled.h" #include "CLogger.h" #include "ConfigDB.h" #include "lib/lib.h" #include "lib/path_util.h" #include "lib/res/file/file.h" #include CLogger* g_Logger = NULL; #include "CConsole.h" extern CConsole* g_Console; using namespace std; const char* html_header0 = "\n" "Pyrogenesis Log\n" "\n" "

\"0

\n" "

"; // (note that the html,head,body tags are optional) const char* html_header1 = "

\n"; const char* html_footer = ""; // ( and are optional too - this way we get the same valid // output even if we crash and don't close the file properly) CLogger::CLogger() { char N_path[PATH_MAX]; (void)file_make_full_native_path("../logs", N_path); PathPackage pp; (void)path_package_set_dir(&pp, N_path); (void)path_package_append_file(&pp, "mainlog.html"); m_MainLog = new std::ofstream(pp.path, ofstream::out | ofstream::trunc); (void)path_package_append_file(&pp, "interestinglog.html"); m_InterestingLog = new std::ofstream(pp.path, ofstream::out | ofstream::trunc); Init(); } CLogger::CLogger(std::ostream* mainLog, std::ostream* interestingLog) { m_MainLog = mainLog; m_InterestingLog = interestingLog; Init(); } void CLogger::Init() { m_NumberOfMessages = 0; m_NumberOfErrors = 0; m_NumberOfWarnings = 0; //Write Headers for the HTML documents *m_MainLog << html_header0 << "Main log" << html_header1; //Write Headers for the HTML documents *m_InterestingLog << html_header0 << "Main log (interesting items only, as specified in system.cfg)" << html_header1; } CLogger::~CLogger () { char buffer[128]; sprintf(buffer," with %d message(s), %d error(s) and %d warning(s).", \ m_NumberOfMessages,m_NumberOfErrors,m_NumberOfWarnings); time_t t = time(NULL); struct tm* now = localtime(&t); const char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; CStr currentDate = CStr(months[now->tm_mon]) + " " + CStr(now->tm_mday) + " " + CStr(1900+now->tm_year); char currentTime[10]; sprintf(currentTime, "%02d:%02d:%02d", now->tm_hour, now->tm_min, now->tm_sec); //Write closing text *m_MainLog << "

Engine exited successfully on " << currentDate; *m_MainLog << " at " << currentTime << buffer << "

\n"; *m_MainLog << html_footer; *m_InterestingLog << "

Engine exited successfully on " << currentDate; *m_InterestingLog << " at " << currentTime << buffer << "

\n"; *m_InterestingLog << html_footer; delete m_InterestingLog; delete m_MainLog; } void CLogger::WriteMessage(const char *message, int interestedness) { m_NumberOfMessages++; if (interestedness >= 2) { if (g_Console) g_Console->InsertMessage(L"LOG: %hs", message); *m_InterestingLog << "

" << message << "

\n"; m_InterestingLog->flush(); } *m_MainLog << "

" << message << "

\n"; m_MainLog->flush(); } void CLogger::WriteError(const char *message, int interestedness) { m_NumberOfErrors++; debug_printf("ERROR: %s\n", message); if (interestedness >= 1) { if (g_Console) g_Console->InsertMessage(L"ERROR: %hs", message); *m_InterestingLog << "

ERROR: "<< message << "

\n"; m_InterestingLog->flush(); } *m_MainLog << "

ERROR: "<< message << "

\n"; m_MainLog->flush(); } void CLogger::WriteWarning(const char *message, int interestedness) { m_NumberOfWarnings++; if (interestedness >= 1) { if (g_Console) g_Console->InsertMessage(L"WARNING: %hs", message); *m_InterestingLog << "

WARNING: "<< message << "

\n"; m_InterestingLog->flush(); } *m_MainLog << "

WARNING: "<< message << "

\n"; m_MainLog->flush(); } // Sends the message to the appropriate piece of code void CLogger::LogUsingMethod(ELogMethod method, const char* category, const char* message) { if(method == NORMAL) WriteMessage(message, Interestedness(category)); else if(method == ERROR) WriteError(message, Interestedness(category)); else if(method == WARNING) WriteWarning(message, Interestedness(category)); else WriteMessage(message, Interestedness(category)); } void CLogger::Log(ELogMethod method, const char* category, const char *fmt, ...) { va_list argp; char buffer[512]; memset(buffer, 0, sizeof(buffer)); va_start(argp, fmt); if (vsnprintf2(buffer, sizeof(buffer)-1, fmt, argp) == -1) { // Buffer too small - ensure the string is nicely terminated strcpy(buffer+sizeof(buffer)-4, "..."); // safe } va_end(argp); LogUsingMethod(method, category, buffer); } void CLogger::LogOnce(ELogMethod method, const char* category, const char *fmt, ...) { va_list argp; char buffer[512]; memset(buffer, 0, sizeof(buffer)); va_start(argp, fmt); if (vsnprintf2(buffer, sizeof(buffer)-1, fmt, argp) == -1) { // Buffer too small - ensure the string is nicely terminated strcpy(buffer+sizeof(buffer)-4, "..."); // safe } va_end(argp); std::string message (buffer); // If this message has already been logged, ignore it if (m_LoggedOnce.find(message) != m_LoggedOnce.end()) return; // If not, mark it as having been logged and then log it m_LoggedOnce.insert(message); LogUsingMethod(method, category, buffer); } int CLogger::Interestedness(const char* category) { // This could be cached, but reading from the config DB every time allows // easy run-time alteration of interest levels (and shouldn't be particularly // slow) // Category unspecified: use a high interest level to encourage // people to categorise their errors if (category == NULL) return 2; // If the config DB hasn't been loaded, assume the default if (! CConfigDB::IsInitialised()) return 1; CConfigValue* v = g_ConfigDB.GetValue(CFG_SYSTEM, CStr("loginterest.")+category); // If the value is unspecified, also use the default if (!v) return 1; int level; // Try to retrieve the value as an integer if (! v->GetInt(level)) return 1; // something failed, so the default value might be a good alternative return level; }