diff --git a/common/debug.cpp b/common/debug.cpp new file mode 100644 index 000000000..fc7a4cc16 --- /dev/null +++ b/common/debug.cpp @@ -0,0 +1,272 @@ +#include +#include + +#ifdef _WINDOWS + #include + + #define snprintf _snprintf + #define vsnprintf _vsnprintf + #define strncasecmp _strnicmp + #define strcasecmp _stricmp + + #include + #include + #include + +namespace ConsoleColor { + enum Colors { + Black = 0, + Blue = 1, + Green = 2, + Cyan = 3, + Red = 4, + Magenta = 5, + Brown = 6, + LightGray = 7, + DarkGray = 8, + LightBlue = 9, + LightGreen = 10, + LightCyan = 11, + LightRed = 12, + LightMagenta = 13, + Yellow = 14, + White = 15, + }; +} + +#else + + #include + #include + +#endif + +#include "eqemu_logsys.h" +#include "debug.h" +#include "misc_functions.h" +#include "platform.h" +#include "eqemu_logsys.h" +#include "string_util.h" + +#ifndef va_copy + #define va_copy(d,s) ((d) = (s)) +#endif + +static volatile bool logFileValid = false; +static EQEmuLog realLogFile; +EQEmuLog *LogFile = &realLogFile; + +static const char* FileNames[EQEmuLog::MaxLogID] = { "logs/eqemu", "logs/eqemu", "logs/eqemu_error", "logs/eqemu_debug", "logs/eqemu_quest", "logs/eqemu_commands", "logs/crash" }; +static const char* LogNames[EQEmuLog::MaxLogID] = { "Status", "Normal", "Error", "Debug", "Quest", "Command", "Crash" }; + +EQEmuLog::EQEmuLog() +{ + pLogStatus[EQEmuLog::LogIDs::Status] = LOG_LEVEL_STATUS; + pLogStatus[EQEmuLog::LogIDs::Normal] = LOG_LEVEL_NORMAL; + pLogStatus[EQEmuLog::LogIDs::Error] = LOG_LEVEL_ERROR; + pLogStatus[EQEmuLog::LogIDs::Debug] = LOG_LEVEL_DEBUG; + pLogStatus[EQEmuLog::LogIDs::Quest] = LOG_LEVEL_QUEST; + pLogStatus[EQEmuLog::LogIDs::Commands] = LOG_LEVEL_COMMANDS; + pLogStatus[EQEmuLog::LogIDs::Crash] = LOG_LEVEL_CRASH; + logFileValid = true; +} + +EQEmuLog::~EQEmuLog() +{ + logFileValid = false; + for (int i = 0; i < MaxLogID; i++) { + LockMutex lock(&MLog[i]); //to prevent termination race + if (fp[i]) { + fclose(fp[i]); + } + } +} + +bool EQEmuLog::open(LogIDs id) +{ + if (!logFileValid) { + return false; + } + if (id >= MaxLogID) { + return false; + } + LockMutex lock(&MOpen); + if (pLogStatus[id] & 4) { + return false; + } + if (fp[id]) { + //cerr<<"Warning: LogFile already open"<= MaxLogID) { + return false; + } + + bool dofile = false; + if (pLogStatus[id] & 1) { + dofile = open(id); + } + if (!(dofile || pLogStatus[id] & 2)) { + return false; + } + LockMutex lock(&MLog[id]); + if (!logFileValid) { + return false; //check again for threading race reasons (to avoid two mutexes) + } + + va_list argptr, tmpargptr; + va_start(argptr, fmt); + + logger.Log(id, vStringFormat(fmt, argptr).c_str()); + + return true; +} + +//write with Prefix and a VA_list +bool EQEmuLog::writePVA(LogIDs id, const char *prefix, const char *fmt, va_list argptr) +{ + if (!logFileValid) { + return false; + } + if (id >= MaxLogID) { + return false; + } + bool dofile = false; + if (pLogStatus[id] & 1) { + dofile = open(id); + } + if (!(dofile || pLogStatus[id] & 2)) { + return false; + } + LockMutex lock(&MLog[id]); + if (!logFileValid) { + return false; //check again for threading race reasons (to avoid two mutexes) + } + time_t aclock; + struct tm *newtime; + time( &aclock ); /* Get time in seconds */ + newtime = localtime( &aclock ); /* Convert time to struct */ + va_list tmpargptr; + if (dofile) { + #ifndef NO_PIDLOG + fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] %s", newtime->tm_mon + 1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, prefix); + #else + fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] %s", getpid(), newtime->tm_mon + 1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, prefix); + #endif + va_copy(tmpargptr, argptr); + vfprintf( fp[id], fmt, tmpargptr ); + } + if (pLogStatus[id] & 2) { + if (pLogStatus[id] & 8) { + fprintf(stderr, "[%s] %s", LogNames[id], prefix); + vfprintf( stderr, fmt, argptr ); + } + /* Console Output */ + else { + + +#ifdef _WINDOWS + HANDLE console_handle; + console_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + CONSOLE_FONT_INFOEX info = { 0 }; + info.cbSize = sizeof(info); + info.dwFontSize.Y = 12; // leave X as zero + info.FontWeight = FW_NORMAL; + wcscpy(info.FaceName, L"Lucida Console"); + SetCurrentConsoleFontEx(console_handle, NULL, &info); + + if (id == EQEmuLog::LogIDs::Status){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::Yellow); } + if (id == EQEmuLog::LogIDs::Error){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightRed); } + if (id == EQEmuLog::LogIDs::Normal){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightGreen); } + if (id == EQEmuLog::LogIDs::Debug){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::Yellow); } + if (id == EQEmuLog::LogIDs::Quest){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightCyan); } + if (id == EQEmuLog::LogIDs::Commands){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightMagenta); } + if (id == EQEmuLog::LogIDs::Crash){ SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::LightRed); } +#endif + + fprintf(stdout, "[%s] %s", LogNames[id], prefix); + vfprintf(stdout, fmt, argptr); + +#ifdef _WINDOWS + /* Always set back to white*/ + SetConsoleTextAttribute(console_handle, ConsoleColor::Colors::White); +#endif + } + } + va_end(argptr); + if (dofile) { + fprintf(fp[id], "\n"); + } + if (pLogStatus[id] & 2) { + if (pLogStatus[id] & 8) { + fprintf(stderr, "\n"); + } else { + fprintf(stdout, "\n"); + } + } + if (dofile) { + fflush(fp[id]); + } + return true; +} + +bool EQEmuLog::writeNTS(LogIDs id, bool dofile, const char *fmt, ...) +{ + va_list argptr, tmpargptr; + va_start(argptr, fmt); + if (dofile) { + va_copy(tmpargptr, argptr); + vfprintf( fp[id], fmt, tmpargptr ); + } + if (pLogStatus[id] & 2) { + if (pLogStatus[id] & 8) { + vfprintf( stderr, fmt, argptr ); + } else { + vfprintf( stdout, fmt, argptr ); + } + } + va_end(argptr); + return true; +}; \ No newline at end of file diff --git a/common/debug.h b/common/debug.h new file mode 100644 index 000000000..5c32eadce --- /dev/null +++ b/common/debug.h @@ -0,0 +1,132 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// Debug Levels +#ifndef EQDEBUG +#define EQDEBUG 1 +#else +////// File/Console options +// 0 <= Quiet mode Errors to file Status and Normal ignored +// 1 >= Status and Normal to console, Errors to file +// 2 >= Status, Normal, and Error to console and logfile +// 3 >= Lite debug +// 4 >= Medium debug +// 5 >= Debug release (Anything higher is not recommended for regular use) +// 6 == (Reserved for special builds) Login opcode debug All packets dumped +// 7 == (Reserved for special builds) Chat Opcode debug All packets dumped +// 8 == (Reserved for special builds) World opcode debug All packets dumped +// 9 == (Reserved for special builds) Zone Opcode debug All packets dumped +// 10 >= More than you ever wanted to know +// +///// +// Add more below to reserve for file's functions ect. +///// +// Any setup code based on defines should go here +// +#endif + + +#if defined(_DEBUG) && defined(WIN32) + #ifndef _CRTDBG_MAP_ALLOC + #include + #include + #endif +#endif + +#ifndef EQDEBUG_H +#define EQDEBUG_H + +#ifndef _WINDOWS + #define DebugBreak() if(0) {} +#endif + +#define _WINSOCKAPI_ //stupid windows, trying to fix the winsock2 vs. winsock issues +#if defined(WIN32) && ( defined(PACKETCOLLECTOR) || defined(COLLECTOR) ) + // Packet Collector on win32 requires winsock.h due to latest pcap.h + // winsock.h must come before windows.h + #include +#endif + +#ifdef _WINDOWS + #include + #include +#endif + +#include "logsys.h" + +#include "../common/mutex.h" +#include +#include + + +class EQEmuLog { +public: + EQEmuLog(); + ~EQEmuLog(); + + enum LogIDs { + Status = 0, /* This must stay the first entry in this list */ + Normal, /* Normal Logs */ + Error, /* Error Logs */ + Debug, /* Debug Logs */ + Quest, /* Quest Logs */ + Commands, /* Issued Comamnds */ + Crash, /* Crash Logs */ + Save, /* Client Saves */ + MaxLogID /* Max, used in functions to get the max log ID */ + }; + + bool write(LogIDs id, const char *fmt, ...); + bool writePVA(LogIDs id, const char *prefix, const char *fmt, va_list args); +private: + bool open(LogIDs id); + bool writeNTS(LogIDs id, bool dofile, const char *fmt, ...); // no error checking, assumes is open, no locking, no timestamp, no newline + + Mutex MOpen; + Mutex MLog[MaxLogID]; + FILE* fp[MaxLogID]; + +/* LogStatus: bitwise variable + 1 = output to file + 2 = output to stdout + 4 = fopen error, dont retry + 8 = use stderr instead (2 must be set) +*/ + uint8 pLogStatus[MaxLogID]; + +}; + +extern EQEmuLog* LogFile; + +#ifdef _EQDEBUG +class PerformanceMonitor { +public: + PerformanceMonitor(int64* ip) { + p = ip; + QueryPerformanceCounter(&tmp); + } + ~PerformanceMonitor() { + LARGE_INTEGER tmp2; + QueryPerformanceCounter(&tmp2); + *p += tmp2.QuadPart - tmp.QuadPart; + } + LARGE_INTEGER tmp; + int64* p; +}; +#endif +#endif