3 * ================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * ================================================================
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License,
10 * version 3.0, as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to
21 * link the code of this program (as well as its derivative works) to
22 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any
23 * Game MODs that run on software by the Valve Corporation. You must
24 * obey the GNU General Public License in all respects for all other
25 * code used. Additionally, AlliedModders LLC grants this exception
26 * to all derivative works. AlliedModders LLC defines further
27 * exceptions, found in LICENSE.txt (as of this writing, version
28 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
34 #include "sourcemod.h"
35 #include "sourcemm_api.h"
36 #include "sm_stringutil.h"
38 #include "systems/LibrarySys.h"
39 #include "sm_version.h"
44 * :TODO: This should be creating the log folder if it doesn't exist
47 ConfigResult Logger::OnSourceModConfigChanged(const char *key,
53 if (strcasecmp(key, "Logging") == 0)
57 if (strcasecmp(value, "on") == 0)
60 } else if (strcasecmp(value, "off") == 0) {
63 UTIL_Format(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
64 return ConfigResult_Reject;
67 if (source == ConfigSource_Console)
69 state ? EnableLogging() : DisableLogging();
71 m_InitialState = state;
74 return ConfigResult_Accept;
75 } else if (strcasecmp(key, "LogMode") == 0) {
76 if (strcasecmp(value, "daily") == 0)
78 m_Mode = LoggingMode_Daily;
79 } else if (strcasecmp(value, "map") == 0) {
80 m_Mode = LoggingMode_PerMap;
81 } else if (strcasecmp(value, "game") == 0) {
82 m_Mode = LoggingMode_Game;
84 UTIL_Format(error, maxlength, "Invalid value: must be [daily|map|game]");
85 return ConfigResult_Reject;
88 return ConfigResult_Accept;
91 return ConfigResult_Ignore;
94 void Logger::OnSourceModStartup(bool late)
99 void Logger::OnSourceModAllShutdown()
104 void Logger::OnSourceModLevelChange(const char *mapName)
109 void Logger::_NewMapFile()
116 /* Append "Log file closed" to previous log file */
124 tm *curtime = localtime(&t);
128 g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i);
129 FILE *fp = fopen(_filename, "r");
137 m_NrmFileName.assign(_filename);
139 FILE *fp = fopen(m_NrmFileName.c_str(), "w");
142 g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n");
147 strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
148 fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SVN_FULL_VERSION);
153 void Logger::_CloseFile()
161 if (!m_NrmFileName.empty())
163 fp = fopen(m_NrmFileName.c_str(), "r+");
166 fseek(fp, 0, SEEK_END);
167 LogMessage("Log file closed.");
170 m_NrmFileName.clear();
177 fp = fopen(m_ErrFileName.c_str(), "r+");
180 fseek(fp, 0, SEEK_END);
181 LogError("Error log file session closed.");
184 m_ErrFileName.clear();
187 void Logger::InitLogger(LoggingMode mode)
190 m_Active = m_InitialState;
194 tm *curtime = localtime(&t);
195 m_CurDay = curtime->tm_mday;
198 g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
199 m_ErrFileName.assign(_filename);
203 case LoggingMode_PerMap:
207 m_DelayedStart = true;
211 case LoggingMode_Daily:
213 g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
214 m_NrmFileName.assign(_filename);
215 m_DailyPrintHdr = true;
226 void Logger::CloseLogger()
231 void Logger::LogMessage(const char *vafmt, ...)
238 if (m_Mode == LoggingMode_Game)
242 _PrintToGameLog(vafmt, ap);
249 m_DelayedStart = false;
256 vsnprintf(msg, sizeof(msg), vafmt, ap);
262 tm *curtime = localtime(&t);
263 strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
266 if (m_Mode == LoggingMode_PerMap)
268 fp = fopen(m_NrmFileName.c_str(), "a+");
272 fp = fopen(m_NrmFileName.c_str(), "a+");
279 if (m_CurDay != curtime->tm_mday)
282 g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
283 m_NrmFileName.assign(_filename);
284 m_CurDay = curtime->tm_mday;
285 m_DailyPrintHdr = true;
287 fp = fopen(m_NrmFileName.c_str(), "a+");
294 m_DailyPrintHdr = false;
295 fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SVN_FULL_VERSION);
297 fprintf(fp, "L %s: %s\n", date, msg);
303 g_SMAPI->ConPrintf("L %s: %s\n", date, msg);
306 g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n");
310 void Logger::LogError(const char *vafmt, ...)
319 tm *curtime = localtime(&t);
322 strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
324 if (curtime->tm_mday != m_CurDay)
327 g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
328 m_ErrFileName.assign(_filename);
329 m_CurDay = curtime->tm_mday;
330 m_ErrMapStart = false;
336 vsnprintf(msg, sizeof(msg), vafmt, ap);
339 FILE *fp = fopen(m_ErrFileName.c_str(), "a+");
344 fprintf(fp, "L %s: SourceMod error session started\n", date);
345 fprintf(fp, "L %s: Info (map \"%s\") (file \"errors_%04d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
346 m_ErrMapStart = true;
348 fprintf(fp, "L %s: %s\n", date, msg);
351 g_SMAPI->ConPrint("[SM] Unexpected fatal logging error. SourceMod logging disabled.\n");
356 g_SMAPI->ConPrintf("L %s: %s\n", date, msg);
359 void Logger::MapChange(const char *mapname)
361 m_CurMapName.assign(mapname);
365 case LoggingMode_Daily:
367 LogMessage("-------- Mapchange to %s --------", mapname);
370 case LoggingMode_PerMap:
384 LogError("Error log file session closed.");
386 m_ErrMapStart = false;
389 void Logger::_PrintToGameLog(const char *fmt, va_list ap)
394 len = vsnprintf(msg, sizeof(msg)-2, fmt, ap);
395 len = (len >= sizeof(msg)) ? (sizeof(msg) - 2) : len;
400 engine->LogPrint(msg);
403 const char *Logger::GetLogFileName(LogType type) const
409 return m_NrmFileName.c_str();
413 return m_ErrFileName.c_str();
422 LoggingMode Logger::GetLoggingMode() const
427 void Logger::EnableLogging()
434 LogMessage("[SM] Logging enabled manually by user.");
437 void Logger::DisableLogging()
443 LogMessage("[SM] Logging disabled manually by user.");
447 void Logger::LogFatal(const char *msg, ...)
449 /* :TODO: make this print all pretty-like
450 * In fact, the pretty log printing function should be abstracted.
451 * It's already implemented twice which is bad.
454 char path[PLATFORM_MAX_PATH];
455 g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
456 FILE *fp = fopen(path, "at");
459 /* We're just doomed, aren't we... */
465 vfprintf(fp, msg, ap);