core/Logger.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
child 2289 44045ead61cd
permissions -rw-r--r--
Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourceMod
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include <time.h>
ds@1952
    33
#include "sourcemod.h"
ds@1952
    34
#include "sourcemm_api.h"
ds@1952
    35
#include "sm_stringutil.h"
ds@1952
    36
#include "Logger.h"
ds@1952
    37
#include "systems/LibrarySys.h"
ds@1952
    38
#include "TimerSys.h"
ds@1952
    39
#include "sm_version.h"
ds@1952
    40
ds@1952
    41
Logger g_Logger;
ds@1952
    42
ds@1952
    43
/**
ds@1952
    44
 * :TODO: This should be creating the log folder if it doesn't exist
ds@1952
    45
 */
ds@1952
    46
ds@1952
    47
ConfigResult Logger::OnSourceModConfigChanged(const char *key, 
ds@1952
    48
									  const char *value, 
ds@1952
    49
									  ConfigSource source,
ds@1952
    50
									  char *error, 
ds@1952
    51
									  size_t maxlength)
ds@1952
    52
{
ds@1952
    53
	if (strcasecmp(key, "Logging") == 0)
ds@1952
    54
	{
ds@1952
    55
		bool state;
ds@1952
    56
ds@1952
    57
		if (strcasecmp(value, "on") == 0)
ds@1952
    58
		{
ds@1952
    59
			state = true;
ds@1952
    60
		} else if (strcasecmp(value, "off") == 0) {
ds@1952
    61
			state = false;
ds@1952
    62
		} else {
ds@1952
    63
			UTIL_Format(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
ds@1952
    64
			return ConfigResult_Reject;
ds@1952
    65
		}
ds@1952
    66
ds@1952
    67
		if (source == ConfigSource_Console)
ds@1952
    68
		{
ds@1952
    69
			state ? EnableLogging() : DisableLogging();
ds@1952
    70
		} else {
ds@1952
    71
			m_InitialState = state;
ds@1952
    72
		}
ds@1952
    73
ds@1952
    74
		return ConfigResult_Accept;
ds@1952
    75
	} else if (strcasecmp(key, "LogMode") == 0) {
ds@1952
    76
		if (strcasecmp(value, "daily") == 0) 
ds@1952
    77
		{
ds@1952
    78
			m_Mode = LoggingMode_Daily;
ds@1952
    79
		} else if (strcasecmp(value, "map") == 0) {
ds@1952
    80
			m_Mode = LoggingMode_PerMap;
ds@1952
    81
		} else if (strcasecmp(value, "game") == 0) {
ds@1952
    82
			m_Mode = LoggingMode_Game;
ds@1952
    83
		} else {
ds@1952
    84
			UTIL_Format(error, maxlength, "Invalid value: must be [daily|map|game]");
ds@1952
    85
			return ConfigResult_Reject;
ds@1952
    86
		}
ds@1952
    87
ds@1952
    88
		return ConfigResult_Accept;
ds@1952
    89
	}
ds@1952
    90
ds@1952
    91
	return ConfigResult_Ignore;
ds@1952
    92
}
ds@1952
    93
ds@1952
    94
void Logger::OnSourceModStartup(bool late)
ds@1952
    95
{
ds@1952
    96
	InitLogger(m_Mode);
ds@1952
    97
}
ds@1952
    98
ds@1952
    99
void Logger::OnSourceModAllShutdown()
ds@1952
   100
{
ds@1952
   101
	CloseLogger();
ds@1952
   102
}
ds@1952
   103
ds@1952
   104
void Logger::OnSourceModLevelChange(const char *mapName)
ds@1952
   105
{
ds@1952
   106
	MapChange(mapName);
ds@1952
   107
}
ds@1952
   108
ds@1952
   109
void Logger::_NewMapFile()
ds@1952
   110
{
ds@1952
   111
	if (!m_Active)
ds@1952
   112
	{
ds@1952
   113
		return;
ds@1952
   114
	}
ds@1952
   115
ds@1952
   116
	/* Append "Log file closed" to previous log file */
ds@1952
   117
	_CloseFile();
ds@1952
   118
	
ds@1952
   119
	char _filename[256];
ds@1952
   120
	int i = 0;
ds@1952
   121
ds@1952
   122
	time_t t;
ds@1952
   123
	GetAdjustedTime(&t);
ds@1952
   124
	tm *curtime = localtime(&t);
ds@1952
   125
ds@1952
   126
	while (true)
ds@1952
   127
	{
ds@1952
   128
		g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i);
ds@1952
   129
		FILE *fp = fopen(_filename, "r");
ds@1952
   130
		if (!fp)
ds@1952
   131
		{
ds@1952
   132
			break;
ds@1952
   133
		}
ds@1952
   134
		fclose(fp);
ds@1952
   135
		i++;
ds@1952
   136
	}
ds@1952
   137
	m_NrmFileName.assign(_filename);
ds@1952
   138
ds@1952
   139
	FILE *fp = fopen(m_NrmFileName.c_str(), "w");
ds@1952
   140
	if (!fp)
ds@1952
   141
	{
ds@1952
   142
		char error[255];
ds@1952
   143
		g_LibSys.GetPlatformError(error, sizeof(error));
ds@1952
   144
		LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
ds@1952
   145
		LogFatal("[SM] Platform returned error: \"%s\"", error);
ds@1952
   146
		LogFatal("[SM] Logging has been disabled.");
ds@1952
   147
		m_Active = false;
ds@1952
   148
		return;
ds@1952
   149
	} else {
ds@1952
   150
		char date[32];
ds@1952
   151
		strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
ds@1952
   152
		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);
ds@1952
   153
		fclose(fp);
ds@1952
   154
	}
ds@1952
   155
}
ds@1952
   156
ds@1952
   157
void Logger::_CloseFile()
ds@1952
   158
{
ds@1952
   159
	if (!m_Active)
ds@1952
   160
	{
ds@1952
   161
		return;
ds@1952
   162
	}
ds@1952
   163
ds@1952
   164
	FILE *fp = NULL;
ds@1952
   165
	if (!m_NrmFileName.empty())
ds@1952
   166
	{
ds@1952
   167
		fp = fopen(m_NrmFileName.c_str(), "r+");
ds@1952
   168
		if (fp)
ds@1952
   169
		{
ds@1952
   170
			fseek(fp, 0, SEEK_END);
ds@1952
   171
			LogMessage("Log file closed.");
ds@1952
   172
			fclose(fp);
ds@1952
   173
		}
ds@1952
   174
		m_NrmFileName.clear();
ds@1952
   175
	}
ds@1952
   176
ds@1952
   177
	if (!m_ErrMapStart)
ds@1952
   178
	{
ds@1952
   179
		return;
ds@1952
   180
	}
ds@1952
   181
	fp = fopen(m_ErrFileName.c_str(), "r+");
ds@1952
   182
	if (fp)
ds@1952
   183
	{
ds@1952
   184
		fseek(fp, 0, SEEK_END);
ds@1952
   185
		LogError("Error log file session closed.");
ds@1952
   186
		fclose(fp);
ds@1952
   187
	}
ds@1952
   188
	m_ErrFileName.clear();
ds@1952
   189
}
ds@1952
   190
ds@1952
   191
void Logger::InitLogger(LoggingMode mode)
ds@1952
   192
{
ds@1952
   193
	m_Mode = mode;
ds@1952
   194
	m_Active = m_InitialState;
ds@1952
   195
ds@1952
   196
	time_t t;
ds@1952
   197
	GetAdjustedTime(&t);
ds@1952
   198
	tm *curtime = localtime(&t);
ds@1952
   199
	m_CurDay = curtime->tm_mday;
ds@1952
   200
ds@1952
   201
	char _filename[256];
ds@1952
   202
	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);
ds@1952
   203
	m_ErrFileName.assign(_filename);
ds@1952
   204
ds@1952
   205
	switch (m_Mode)
ds@1952
   206
	{
ds@1952
   207
	case LoggingMode_PerMap:
ds@1952
   208
		{
ds@1952
   209
			if (!m_Active)
ds@1952
   210
			{
ds@1952
   211
				m_DelayedStart = true;
ds@1952
   212
			}
ds@1952
   213
			break;
ds@1952
   214
		}
ds@1952
   215
	case LoggingMode_Daily:
ds@1952
   216
		{
ds@1952
   217
			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);
ds@1952
   218
			m_NrmFileName.assign(_filename);
ds@1952
   219
			m_DailyPrintHdr = true;
ds@1952
   220
			break;
ds@1952
   221
		}
ds@1952
   222
	default:
ds@1952
   223
		{
ds@1952
   224
			/* do nothing... */
ds@1952
   225
			break;
ds@1952
   226
		}
ds@1952
   227
	}
ds@1952
   228
}
ds@1952
   229
ds@1952
   230
void Logger::CloseLogger()
ds@1952
   231
{
ds@1952
   232
	_CloseFile();
ds@1952
   233
}
ds@1952
   234
ds@1952
   235
void Logger::LogToOpenFile(FILE *fp, const char *msg, ...)
ds@1952
   236
{
ds@1952
   237
	if (!m_Active)
ds@1952
   238
	{
ds@1952
   239
		return;
ds@1952
   240
	}
ds@1952
   241
ds@1952
   242
	va_list ap;
ds@1952
   243
	va_start(ap, msg);
ds@1952
   244
	LogToOpenFileEx(fp, msg, ap);
ds@1952
   245
	va_end(ap);
ds@1952
   246
}
ds@1952
   247
ds@1952
   248
void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
ds@1952
   249
{
ds@1952
   250
	if (!m_Active)
ds@1952
   251
	{
ds@1952
   252
		return;
ds@1952
   253
	}
ds@1952
   254
ds@1952
   255
	char buffer[3072];
ds@1952
   256
	UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
ds@1952
   257
ds@1952
   258
	char date[32];
ds@1952
   259
	time_t t;
ds@1952
   260
	GetAdjustedTime(&t);
ds@1952
   261
	tm *curtime = localtime(&t);
ds@1952
   262
	strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
ds@1952
   263
ds@1952
   264
	fprintf(fp, "L %s: %s\n", date, buffer);
ds@1952
   265
	g_SMAPI->ConPrintf("L %s: %s\n", date, buffer);
ds@1952
   266
}
ds@1952
   267
ds@1952
   268
void Logger::LogMessage(const char *vafmt, ...)
ds@1952
   269
{
ds@1952
   270
	if (!m_Active)
ds@1952
   271
	{
ds@1952
   272
		return;
ds@1952
   273
	}
ds@1952
   274
ds@1952
   275
	if (m_Mode == LoggingMode_Game)
ds@1952
   276
	{
ds@1952
   277
		va_list ap;
ds@1952
   278
		va_start(ap, vafmt);
ds@1952
   279
		_PrintToGameLog(vafmt, ap);
ds@1952
   280
		va_end(ap);
ds@1952
   281
		return;
ds@1952
   282
	}
ds@1952
   283
ds@1952
   284
	if (m_DelayedStart)
ds@1952
   285
	{
ds@1952
   286
		m_DelayedStart = false;
ds@1952
   287
		_NewMapFile();
ds@1952
   288
	}
ds@1952
   289
ds@1952
   290
	time_t t;
ds@1952
   291
	GetAdjustedTime(&t);
ds@1952
   292
	tm *curtime = localtime(&t);
ds@1952
   293
ds@1952
   294
	FILE *fp = NULL;
ds@1952
   295
	if (m_Mode == LoggingMode_PerMap)
ds@1952
   296
	{
ds@1952
   297
		fp = fopen(m_NrmFileName.c_str(), "a+");
ds@1952
   298
		if (!fp)
ds@1952
   299
		{
ds@1952
   300
			_NewMapFile();
ds@1952
   301
			fp = fopen(m_NrmFileName.c_str(), "a+");
ds@1952
   302
			if (!fp)
ds@1952
   303
			{
ds@1952
   304
				goto print_error;
ds@1952
   305
			}
ds@1952
   306
		}
ds@1952
   307
	} else {
ds@1952
   308
		if (m_CurDay != curtime->tm_mday)
ds@1952
   309
		{
ds@1952
   310
			char _filename[256];
ds@1952
   311
			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);
ds@1952
   312
			m_NrmFileName.assign(_filename);
ds@1952
   313
			m_CurDay = curtime->tm_mday;
ds@1952
   314
			m_DailyPrintHdr = true;
ds@1952
   315
		}
ds@1952
   316
		fp = fopen(m_NrmFileName.c_str(), "a+");
ds@1952
   317
	}
ds@1952
   318
ds@1952
   319
	if (fp)
ds@1952
   320
	{
ds@1952
   321
		if (m_DailyPrintHdr)
ds@1952
   322
		{
ds@1952
   323
			char date[32];
ds@1952
   324
			m_DailyPrintHdr = false;
ds@1952
   325
			strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
ds@1952
   326
			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);
ds@1952
   327
	 	}
ds@1952
   328
		va_list ap;
ds@1952
   329
		va_start(ap, vafmt);
ds@1952
   330
		LogToOpenFileEx(fp, vafmt, ap);
ds@1952
   331
		va_end(ap);
ds@1952
   332
		fclose(fp);
ds@1952
   333
	} else {
ds@1952
   334
		goto print_error;
ds@1952
   335
	}
ds@1952
   336
ds@1952
   337
	return;
ds@1952
   338
print_error:
ds@1952
   339
	char error[255];
ds@1952
   340
	g_LibSys.GetPlatformError(error, sizeof(error));
ds@1952
   341
	LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
ds@1952
   342
	LogFatal("[SM] Platform returned error: \"%s\"", error);
ds@1952
   343
	LogFatal("[SM] Logging has been disabled.");
ds@1952
   344
	m_Active = false;
ds@1952
   345
}
ds@1952
   346
ds@1952
   347
void Logger::LogError(const char *vafmt, ...)
ds@1952
   348
{
ds@1952
   349
	if (!m_Active)
ds@1952
   350
	{
ds@1952
   351
		return;
ds@1952
   352
	}
ds@1952
   353
ds@1952
   354
	time_t t;
ds@1952
   355
	GetAdjustedTime(&t);
ds@1952
   356
	tm *curtime = localtime(&t);
ds@1952
   357
ds@1952
   358
	if (curtime->tm_mday != m_CurDay)
ds@1952
   359
	{
ds@1952
   360
		char _filename[256];
ds@1952
   361
		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);
ds@1952
   362
		m_ErrFileName.assign(_filename);
ds@1952
   363
		m_CurDay = curtime->tm_mday;
ds@1952
   364
		m_ErrMapStart = false;
ds@1952
   365
	}
ds@1952
   366
ds@1952
   367
	FILE *fp = fopen(m_ErrFileName.c_str(), "a+");
ds@1952
   368
	if (fp)
ds@1952
   369
	{
ds@1952
   370
		if (!m_ErrMapStart)
ds@1952
   371
		{
ds@1952
   372
			char date[32];
ds@1952
   373
			strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
ds@1952
   374
			fprintf(fp, "L %s: SourceMod error session started\n", date);
ds@1952
   375
			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);
ds@1952
   376
			m_ErrMapStart = true;
ds@1952
   377
		}
ds@1952
   378
		va_list ap;
ds@1952
   379
		va_start(ap, vafmt);
ds@1952
   380
		LogToOpenFileEx(fp, vafmt, ap);
ds@1952
   381
		va_end(ap);
ds@1952
   382
		fclose(fp);
ds@1952
   383
	}
ds@1952
   384
	else
ds@1952
   385
	{
ds@1952
   386
		char error[255];
ds@1952
   387
		g_LibSys.GetPlatformError(error, sizeof(error));
ds@1952
   388
		LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
ds@1952
   389
		LogFatal("[SM] Platform returned error: \"%s\"", error);
ds@1952
   390
		LogFatal("[SM] Logging has been disabled.");
ds@1952
   391
		m_Active = false;
ds@1952
   392
		return;
ds@1952
   393
	}
ds@1952
   394
}
ds@1952
   395
ds@1952
   396
void Logger::MapChange(const char *mapname)
ds@1952
   397
{
ds@1952
   398
	m_CurMapName.assign(mapname);
ds@1952
   399
ds@1952
   400
	switch (m_Mode)
ds@1952
   401
	{
ds@1952
   402
	case LoggingMode_Daily:
ds@1952
   403
		{
ds@1952
   404
			LogMessage("-------- Mapchange to %s --------", mapname);
ds@1952
   405
			break;
ds@1952
   406
		}
ds@1952
   407
	case LoggingMode_PerMap:
ds@1952
   408
		{
ds@1952
   409
			_NewMapFile();
ds@1952
   410
			break;
ds@1952
   411
		}
ds@1952
   412
	default:
ds@1952
   413
		{
ds@1952
   414
			/* Do nothing... */
ds@1952
   415
			break;
ds@1952
   416
		}
ds@1952
   417
	}
ds@1952
   418
ds@1952
   419
	if (m_ErrMapStart)
ds@1952
   420
	{
ds@1952
   421
		LogError("Error log file session closed.");
ds@1952
   422
	}
ds@1952
   423
	m_ErrMapStart = false;
ds@1952
   424
}
ds@1952
   425
ds@1952
   426
void Logger::_PrintToGameLog(const char *fmt, va_list ap)
ds@1952
   427
{
ds@1952
   428
	char msg[3072];
ds@1952
   429
	size_t len;
ds@1952
   430
ds@1952
   431
	len = vsnprintf(msg, sizeof(msg)-2, fmt, ap);
ds@1952
   432
	len = (len >= sizeof(msg)) ? (sizeof(msg) - 2) : len;
ds@1952
   433
ds@1952
   434
	msg[len++] = '\n';
ds@1952
   435
	msg[len] = '\0';
ds@1952
   436
ds@1952
   437
	Engine_LogPrintWrapper(msg);
ds@1952
   438
}
ds@1952
   439
ds@1952
   440
const char *Logger::GetLogFileName(LogType type) const
ds@1952
   441
{
ds@1952
   442
	switch (type)
ds@1952
   443
	{
ds@1952
   444
	case LogType_Normal:
ds@1952
   445
		{
ds@1952
   446
			return m_NrmFileName.c_str();
ds@1952
   447
		}
ds@1952
   448
	case LogType_Error:
ds@1952
   449
		{
ds@1952
   450
			return m_ErrFileName.c_str();
ds@1952
   451
		}
ds@1952
   452
	default:
ds@1952
   453
		{
ds@1952
   454
			return "";
ds@1952
   455
		}
ds@1952
   456
	}
ds@1952
   457
}
ds@1952
   458
ds@1952
   459
LoggingMode Logger::GetLoggingMode() const
ds@1952
   460
{
ds@1952
   461
	return m_Mode;
ds@1952
   462
}
ds@1952
   463
ds@1952
   464
void Logger::EnableLogging()
ds@1952
   465
{
ds@1952
   466
	if (m_Active)
ds@1952
   467
	{
ds@1952
   468
		return;
ds@1952
   469
	}
ds@1952
   470
	m_Active = true;
ds@1952
   471
	LogMessage("[SM] Logging enabled manually by user.");
ds@1952
   472
}
ds@1952
   473
ds@1952
   474
void Logger::DisableLogging()
ds@1952
   475
{
ds@1952
   476
	if (!m_Active)
ds@1952
   477
	{
ds@1952
   478
		return;
ds@1952
   479
	}
ds@1952
   480
	LogMessage("[SM] Logging disabled manually by user.");
ds@1952
   481
	m_Active = false;
ds@1952
   482
}
ds@1952
   483
ds@1952
   484
void Logger::LogFatal(const char *msg, ...)
ds@1952
   485
{
ds@1952
   486
	/* :TODO: make this print all pretty-like
ds@1952
   487
	 * In fact, the pretty log printing function should be abstracted. 
ds@1952
   488
	 * It's already implemented twice which is bad.
ds@1952
   489
	 */
ds@1952
   490
ds@1952
   491
	va_list ap;
ds@1952
   492
	char path[PLATFORM_MAX_PATH];
ds@1952
   493
ds@1952
   494
	g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
ds@1952
   495
ds@1952
   496
	FILE *fp = fopen(path, "at");
ds@1952
   497
	if (fp)
ds@1952
   498
	{
ds@1952
   499
		m_Active = true;
ds@1952
   500
		va_start(ap, msg);
ds@1952
   501
		LogToOpenFileEx(fp, msg, ap);
ds@1952
   502
		va_end(ap);
ds@1952
   503
		m_Active = false;
ds@1952
   504
		fclose(fp);
ds@1952
   505
	}
ds@1952
   506
}
ds@1952
   507
ds@1952
   508
bool g_in_game_log_hook = false;
ds@1952
   509
ds@1952
   510
void Engine_LogPrintWrapper(const char *msg)
ds@1952
   511
{
ds@1952
   512
	if (g_in_game_log_hook)
ds@1952
   513
	{
ds@1952
   514
		ENGINE_CALL(LogPrint)(msg);
ds@1952
   515
	}
ds@1952
   516
	else
ds@1952
   517
	{
ds@1952
   518
		engine->LogPrint(msg);
ds@1952
   519
	}
ds@1952
   520
}