// vim: set ts=4 sw=4 tw=99 noet: // // AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). // Copyright (C) The AMX Mod X Development Team. // // This software is licensed under the GNU General Public License, version 3 or higher. // Additional exceptions apply. For full license details, see LICENSE.txt or visit: // https://alliedmods.net/amxmodx-license // amxx_logging localinfo: // 0 = no logging // 1 = one logfile / day // 2 = one logfile / map // 3 = HL Logs #include #if defined(_WIN32) #include #endif #include "amxmodx.h" #if defined(_WIN32WIN32) #define vsnprintf _vsnprintf #endif #include CLog::CLog() { m_LogType = 0; m_LogFile = nullptr; m_FoundError = false; m_LoggedErrMap = false; } CLog::~CLog() { CloseFile(); } void CLog::CloseFile() { // log "log file closed" to old file, if any if (m_LogFile.length()) { FILE *fp = fopen(m_LogFile.chars(), "r"); if (fp) { fclose(fp); fp = fopen(m_LogFile.chars(), "a+"); // get time time_t td; time(&td); tm *curTime = localtime(&td); char date[32]; strftime(date, 31, "%m/%d/%Y - %H:%M:%S", curTime); fprintf(fp, "L %s: %s\n", date, "Log file closed."); fclose(fp); } m_LogFile = nullptr; } } void CLog::CreateNewFile() { CloseFile(); // build filename time_t td; time(&td); tm *curTime = localtime(&td); char file[PLATFORM_MAX_PATH]; char name[256]; int i = 0; while (true) { ke::SafeSprintf(name, sizeof(name), "%s/L%02d%02d%03d.log", g_log_dir.chars(), curTime->tm_mon + 1, curTime->tm_mday, i); build_pathname_r(file, sizeof(file), "%s", name); FILE *pTmpFile = fopen(file, "r"); // open for reading to check whether the file exists if (!pTmpFile) break; fclose(pTmpFile); ++i; } m_LogFile = file; // Log logfile start FILE *fp = fopen(m_LogFile.chars(), "w"); if (!fp) { ALERT(at_logged, "[AMXX] Unexpected fatal logging error. AMXX Logging disabled.\n"); SET_LOCALINFO("amxx_logging", "0"); } else { fprintf(fp, "AMX Mod X log file started (file \"%s\") (version \"%s\")\n", name, AMXX_VERSION); fclose(fp); } } void CLog::UseFile(const ke::AString &fileName) { static char file[PLATFORM_MAX_PATH]; m_LogFile = build_pathname_r(file, sizeof(file), "%s/%s", g_log_dir.chars(), fileName.chars()); } void CLog::SetLogType(const char* localInfo) { m_LogType = atoi(get_localinfo(localInfo, "1")); if (m_LogType < 0 || m_LogType > 3) { SET_LOCALINFO(localInfo, "1"); m_LogType = 1; print_srvconsole("[AMXX] Invalid amxx_logging value; setting back to 1..."); } } void CLog::MapChange() { // create dir if not existing char file[PLATFORM_MAX_PATH]; #if defined(__linux__) || defined(__APPLE__) mkdir(build_pathname_r(file, sizeof(file), "%s", g_log_dir.chars()), 0700); #else mkdir(build_pathname_r(file, sizeof(file), "%s", g_log_dir.chars())); #endif SetLogType("amxx_logging"); m_LoggedErrMap = false; if (m_LogType == 2) { // create new logfile CreateNewFile(); } else if (m_LogType == 1) { Log("-------- Mapchange to %s --------", STRING(gpGlobals->mapname)); } else { return; } } void CLog::Log(const char *fmt, ...) { static char file[PLATFORM_MAX_PATH]; if (m_LogType == 1 || m_LogType == 2) { // get time time_t td; time(&td); tm *curTime = localtime(&td); char date[32]; strftime(date, 31, "%m/%d/%Y - %H:%M:%S", curTime); // msg static char msg[3072]; va_list arglst; va_start(arglst, fmt); vsnprintf(msg, 3071, fmt, arglst); va_end(arglst); FILE *pF = NULL; if (m_LogType == 2) { pF = fopen(m_LogFile.chars(), "a+"); if (!pF) { CreateNewFile(); pF = fopen(m_LogFile.chars(), "a+"); if (!pF) { ALERT(at_logged, "[AMXX] Unexpected fatal logging error (couldn't open %s for a+). AMXX Logging disabled for this map.\n", m_LogFile.chars()); m_LogType = 0; return; } } } else { build_pathname_r(file, sizeof(file), "%s/L%04d%02d%02d.log", g_log_dir.chars(), (curTime->tm_year + 1900), curTime->tm_mon + 1, curTime->tm_mday); pF = fopen(file, "a+"); } if (pF) { fprintf(pF, "L %s: %s\n", date, msg); fclose(pF); } else { ALERT(at_logged, "[AMXX] Unexpected fatal logging error (couldn't open %s for a+). AMXX Logging disabled for this map.\n", file); m_LogType = 0; return; } // print on server console print_srvconsole("L %s: %s\n", date, msg); } else if (m_LogType == 3) { // build message static char msg_[3072]; va_list arglst; va_start(arglst, fmt); vsnprintf(msg_, 3071, fmt, arglst); va_end(arglst); ALERT(at_logged, "%s\n", msg_); } } void CLog::LogError(const char *fmt, ...) { static char file[PLATFORM_MAX_PATH]; static char name[256]; if (m_FoundError) { return; } // get time time_t td; time(&td); tm *curTime = localtime(&td); char date[32]; strftime(date, 31, "%m/%d/%Y - %H:%M:%S", curTime); // msg static char msg[3072]; va_list arglst; va_start(arglst, fmt); vsnprintf(msg, sizeof(msg)-1, fmt, arglst); va_end(arglst); FILE *pF = NULL; ke::SafeSprintf(name, sizeof(name), "%s/error_%04d%02d%02d.log", g_log_dir.chars(), curTime->tm_year + 1900, curTime->tm_mon + 1, curTime->tm_mday); build_pathname_r(file, sizeof(file), "%s", name); pF = fopen(file, "a+"); if (pF) { if (!m_LoggedErrMap) { fprintf(pF, "L %s: Start of error session.\n", date); fprintf(pF, "L %s: Info (map \"%s\") (file \"%s\")\n", date, STRING(gpGlobals->mapname), name); m_LoggedErrMap = true; } fprintf(pF, "L %s: %s\n", date, msg); fclose(pF); } else { ALERT(at_logged, "[AMXX] Unexpected fatal logging error (couldn't open %s for a+). AMXX Error Logging disabled for this map.\n", file); m_FoundError = true; return; } // print on server console print_srvconsole("L %s: %s\n", date, msg); }