Cleanup eqemu_logsys code and automatically inject new logging categories into the database if they do not exist

This commit is contained in:
Akkadius 2018-10-20 22:29:59 -05:00
parent 8115db3576
commit ab8075d629
4 changed files with 569 additions and 339 deletions

1
.gitignore vendored
View File

@ -40,3 +40,4 @@ logs/
vcpkg/
.idea/*
*cbp

View File

@ -2063,51 +2063,91 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
return atoi(row[0]);
}
void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings)
{
void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) {
// log_settings previously initialized to '0' by EQEmuLogSys::LoadLogSettingsDefaults()
std::string query =
"SELECT "
"log_category_id, "
"log_category_description, "
"log_to_console, "
"log_to_file, "
"log_to_gmsay "
"FROM "
"logsys_categories "
"ORDER BY log_category_id";
"SELECT "
"log_category_id, "
"log_category_description, "
"log_to_console, "
"log_to_file, "
"log_to_gmsay "
"FROM "
"logsys_categories "
"ORDER BY log_category_id";
auto results = QueryDatabase(query);
int log_category = 0;
int log_category_id = 0;
LogSys.file_logs_enabled = false;
int categories_in_database[1000] = {};
for (auto row = results.begin(); row != results.end(); ++row) {
log_category = atoi(row[0]);
if (log_category <= Logs::None || log_category >= Logs::MaxCategoryID)
log_category_id = atoi(row[0]);
if (log_category_id <= Logs::None || log_category_id >= Logs::MaxCategoryID) {
continue;
}
log_settings[log_category].log_to_console = atoi(row[2]);
log_settings[log_category].log_to_file = atoi(row[3]);
log_settings[log_category].log_to_gmsay = atoi(row[4]);
log_settings[log_category_id].log_to_console = atoi(row[2]);
log_settings[log_category_id].log_to_file = atoi(row[3]);
log_settings[log_category_id].log_to_gmsay = atoi(row[4]);
/* Determine if any output method is enabled for the category
and set it to 1 so it can used to check if category is enabled */
const bool log_to_console = log_settings[log_category].log_to_console > 0;
const bool log_to_file = log_settings[log_category].log_to_file > 0;
const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0;
/**
* Determine if any output method is enabled for the category
* and set it to 1 so it can used to check if category is enabled
*/
const bool log_to_console = log_settings[log_category_id].log_to_console > 0;
const bool log_to_file = log_settings[log_category_id].log_to_file > 0;
const bool log_to_gmsay = log_settings[log_category_id].log_to_gmsay > 0;
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay;
if (is_category_enabled)
log_settings[log_category].is_category_enabled = 1;
if (is_category_enabled) {
log_settings[log_category_id].is_category_enabled = 1;
}
/*
This determines whether or not the process needs to actually file log anything.
If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open
*/
if (log_settings[log_category].log_to_file > 0){
/**
* This determines whether or not the process needs to actually file log anything.
* If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open
*/
if (log_settings[log_category_id].log_to_file > 0) {
LogSys.file_logs_enabled = true;
}
categories_in_database[log_category_id] = 1;
}
/**
* Auto inject categories that don't exist in the database...
*/
for (int log_index = Logs::AA; log_index != Logs::MaxCategoryID; log_index++) {
if (!categories_in_database[log_index]) {
Log(Logs::General,
Logs::Status,
"New Log Category '%s' doesn't exist... Automatically adding to `logsys_categories` table...",
Logs::LogCategoryName[log_index]
);
std::string inject_query = StringFormat(
"INSERT INTO logsys_categories "
"(log_category_id, "
"log_category_description, "
"log_to_console, "
"log_to_file, "
"log_to_gmsay) "
"VALUES "
"(%i, '%s', %i, %i, %i)",
log_index,
EscapeString(Logs::LogCategoryName[log_index]).c_str(),
log_settings[log_category_id].log_to_console,
log_settings[log_category_id].log_to_file,
log_settings[log_category_id].log_to_gmsay
);
QueryDatabase(inject_query);
}
}
}

View File

@ -1,22 +1,23 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net)
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
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* 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
*
*/
#include "eqemu_logsys.h"
#include "platform.h"
#include "string_util.h"
@ -33,106 +34,144 @@
std::ofstream process_log;
#ifdef _WINDOWS
#include <direct.h>
#include <conio.h>
#include <iostream>
#include <dos.h>
#include <windows.h>
#include <process.h>
#include <direct.h>
#include <conio.h>
#include <iostream>
#include <dos.h>
#include <windows.h>
#include <process.h>
#else
#include <unistd.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/stat.h>
#endif
/* Linux ANSI console color defines */
/**
* Linux ANSI console color defines
*/
#define LC_RESET "\033[0m"
#define LC_BLACK "\033[30m" /* Black */
#define LC_RED "\033[31m" /* Red */
#define LC_GREEN "\033[32m" /* Green */
#define LC_YELLOW "\033[33m" /* Yellow */
#define LC_BLUE "\033[34m" /* Blue */
#define LC_MAGENTA "\033[35m" /* Magenta */
#define LC_CYAN "\033[36m" /* Cyan */
#define LC_WHITE "\033[37m" /* White */
#define LC_BLACK "\033[30m" /* Black */
#define LC_RED "\033[31m" /* Red */
#define LC_GREEN "\033[32m" /* Green */
#define LC_YELLOW "\033[33m" /* Yellow */
#define LC_BLUE "\033[34m" /* Blue */
#define LC_MAGENTA "\033[35m" /* Magenta */
#define LC_CYAN "\033[36m" /* Cyan */
#define LC_WHITE "\033[37m" /* White */
namespace Console {
enum Color {
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,
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
Yellow = 14,
White = 15
};
}
enum GameChatColor {
yellow = 15,
red = 13,
light_green = 14,
light_cyan = 258,
light_purple = 5
};
/**
* EQEmuLogSys Constructor
*/
EQEmuLogSys::EQEmuLogSys()
{
on_log_gmsay_hook = [](uint16 log_type, const std::string&) {};
on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
bool file_logs_enabled = false;
int log_platform = 0;
int log_platform = 0;
}
/**
* EQEmuLogSys Deconstructor
*/
EQEmuLogSys::~EQEmuLogSys()
{
}
void EQEmuLogSys::LoadLogSettingsDefaults()
{
/* Get Executable platform currently running this code (Zone/World/etc) */
/**
* Get Executable platform currently running this code (Zone/World/etc)
*/
log_platform = GetExecutablePlatformInt();
/* Zero out Array */
/**
* Zero out Array
*/
memset(log_settings, 0, sizeof(LogSettings) * Logs::LogCategory::MaxCategoryID);
/* Set Defaults */
log_settings[Logs::World_Server].log_to_console = Logs::General;
log_settings[Logs::Zone_Server].log_to_console = Logs::General;
log_settings[Logs::QS_Server].log_to_console = Logs::General;
log_settings[Logs::UCS_Server].log_to_console = Logs::General;
log_settings[Logs::Crash].log_to_console = Logs::General;
log_settings[Logs::MySQLError].log_to_console = Logs::General;
log_settings[Logs::Login_Server].log_to_console = Logs::General;
/**
* Set Defaults
*/
log_settings[Logs::World_Server].log_to_console = Logs::General;
log_settings[Logs::Zone_Server].log_to_console = Logs::General;
log_settings[Logs::QS_Server].log_to_console = Logs::General;
log_settings[Logs::UCS_Server].log_to_console = Logs::General;
log_settings[Logs::Crash].log_to_console = Logs::General;
log_settings[Logs::MySQLError].log_to_console = Logs::General;
log_settings[Logs::Login_Server].log_to_console = Logs::General;
log_settings[Logs::Headless_Client].log_to_console = Logs::General;
/* Set Category enabled status on defaults */
/**
* Set Category enabled status on defaults
*/
log_settings[Logs::World_Server].is_category_enabled = 1;
log_settings[Logs::Zone_Server].is_category_enabled = 1;
log_settings[Logs::QS_Server].is_category_enabled = 1;
log_settings[Logs::UCS_Server].is_category_enabled = 1;
log_settings[Logs::Crash].is_category_enabled = 1;
log_settings[Logs::MySQLError].is_category_enabled = 1;
log_settings[Logs::Zone_Server].is_category_enabled = 1;
log_settings[Logs::QS_Server].is_category_enabled = 1;
log_settings[Logs::UCS_Server].is_category_enabled = 1;
log_settings[Logs::Crash].is_category_enabled = 1;
log_settings[Logs::MySQLError].is_category_enabled = 1;
log_settings[Logs::Login_Server].is_category_enabled = 1;
/* Declare process file names for log writing
If there is no process_file_name declared, no log file will be written, simply
*/
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld)
/**
* Declare process file names for log writing=
*/
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld) {
platform_file_name = "world";
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformQueryServ)
}
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformQueryServ) {
platform_file_name = "query_server";
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone)
}
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) {
platform_file_name = "zone";
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformUCS)
}
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformUCS) {
platform_file_name = "ucs";
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin)
}
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) {
platform_file_name = "login";
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch)
}
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch) {
platform_file_name = "launcher";
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformHC)
}
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformHC) {
platform_file_name = "hc";
}
}
/**
* @param log_category
* @param in_message
* @return
*/
std::string EQEmuLogSys::FormatOutMessageString(uint16 log_category, const std::string &in_message)
{
std::string ret;
@ -144,17 +183,33 @@ std::string EQEmuLogSys::FormatOutMessageString(uint16 log_category, const std::
return ret;
}
/**
* @param debug_level
* @param log_category
* @param message
*/
void EQEmuLogSys::ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message)
{
/* Enabling Netcode based GMSay output creates a feedback loop that ultimately ends in a crash */
if (log_category == Logs::LogCategory::Netcode)
/**
* Enabling Netcode based GMSay output creates a feedback loop that ultimately ends in a crash
*/
if (log_category == Logs::LogCategory::Netcode) {
return;
}
/* Check to see if the process that actually ran this is zone */
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone)
/**
* Check to see if the process that actually ran this is zone
*/
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) {
on_log_gmsay_hook(log_category, message);
}
}
/**
* @param debug_level
* @param log_category
* @param message
*/
void EQEmuLogSys::ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message)
{
if (log_category == Logs::Crash) {
@ -162,7 +217,10 @@ void EQEmuLogSys::ProcessLogWrite(uint16 debug_level, uint16 log_category, const
EQEmuLogSys::SetCurrentTimeStamp(time_stamp);
std::ofstream crash_log;
EQEmuLogSys::MakeDirectory("logs/crashes");
crash_log.open(StringFormat("logs/crashes/crash_%s_%i.log", platform_file_name.c_str(), getpid()), std::ios_base::app | std::ios_base::out);
crash_log.open(
StringFormat("logs/crashes/crash_%s_%i.log", platform_file_name.c_str(), getpid()),
std::ios_base::app | std::ios_base::out
);
crash_log << time_stamp << " " << message << "\n";
crash_log.close();
}
@ -170,11 +228,17 @@ void EQEmuLogSys::ProcessLogWrite(uint16 debug_level, uint16 log_category, const
char time_stamp[80];
EQEmuLogSys::SetCurrentTimeStamp(time_stamp);
if (process_log)
if (process_log) {
process_log << time_stamp << " " << message << std::endl;
}
}
uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category) {
/**
* @param log_category
* @return
*/
uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category)
{
switch (log_category) {
case Logs::Status:
case Logs::Normal:
@ -197,7 +261,12 @@ uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category) {
}
}
std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category) {
/**
* @param log_category
* @return
*/
std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category)
{
switch (log_category) {
case Logs::Status:
case Logs::Normal:
@ -220,52 +289,68 @@ std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category) {
}
}
uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category) {
/**
* @param log_category
* @return
*/
uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
{
switch (log_category) {
case Logs::Status:
case Logs::Normal:
return 15; /* Yellow */
return GameChatColor::yellow;
case Logs::MySQLError:
case Logs::Error:
return 13; /* Red */
return GameChatColor::red;
case Logs::MySQLQuery:
case Logs::Debug:
return 14; /* Light Green */
return GameChatColor::light_green;
case Logs::Quests:
return 258; /* Light Cyan */
return GameChatColor::light_cyan;
case Logs::Commands:
case Logs::Mercenaries:
return 5; /* Light Purple */
return GameChatColor::light_purple;
case Logs::Crash:
return 13; /* Red */
return GameChatColor::red;
default:
return 15; /* Yellow */
return GameChatColor::yellow;
}
}
/**
* @param debug_level
* @param log_category
* @param message
*/
void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message)
{
#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);
SetConsoleTextAttribute(console_handle, EQEmuLogSys::GetWindowsConsoleColorFromCategory(log_category));
std::cout << message << "\n";
SetConsoleTextAttribute(console_handle, Console::Color::White);
#else
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
#endif
#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);
SetConsoleTextAttribute(console_handle, EQEmuLogSys::GetWindowsConsoleColorFromCategory(log_category));
std::cout << message << "\n";
SetConsoleTextAttribute(console_handle, Console::Color::White);
#else
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
#endif
}
/**
* Core logging function
*
* @param debug_level
* @param log_category
* @param message
* @param ...
*/
void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::string message, ...)
{
bool log_to_console = true;
if (log_settings[log_category].log_to_console < debug_level) {
log_to_console = false;
@ -282,8 +367,9 @@ void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::st
}
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay;
if (nothing_to_log)
if (nothing_to_log) {
return;
}
va_list args;
va_start(args, message);
@ -292,20 +378,32 @@ void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::st
std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, output_message);
if (log_to_console) EQEmuLogSys::ProcessConsoleMessage(debug_level, log_category, output_debug_message);
if (log_to_gmsay) EQEmuLogSys::ProcessGMSay(debug_level, log_category, output_debug_message);
if (log_to_file) EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_debug_message);
if (log_to_console) {
EQEmuLogSys::ProcessConsoleMessage(debug_level, log_category, output_debug_message);
}
if (log_to_gmsay) {
EQEmuLogSys::ProcessGMSay(debug_level, log_category, output_debug_message);
}
if (log_to_file) {
EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_debug_message);
}
}
void EQEmuLogSys::SetCurrentTimeStamp(char* time_stamp)
/**
* @param time_stamp
*/
void EQEmuLogSys::SetCurrentTimeStamp(char *time_stamp)
{
time_t raw_time;
struct tm * time_info;
time_t raw_time;
struct tm *time_info;
time(&raw_time);
time_info = localtime(&raw_time);
strftime(time_stamp, 80, "[%m-%d-%Y :: %H:%M:%S]", time_info);
}
/**
* @param directory_name
*/
void EQEmuLogSys::MakeDirectory(const std::string &directory_name)
{
#ifdef _WINDOWS
@ -315,8 +413,9 @@ void EQEmuLogSys::MakeDirectory(const std::string &directory_name)
_mkdir(directory_name.c_str());
#else
struct stat st;
if (stat(directory_name.c_str(), &st) == 0) // exists
if (stat(directory_name.c_str(), &st) == 0) { // exists
return;
}
mkdir(directory_name.c_str(), 0755);
#endif
}
@ -328,29 +427,75 @@ void EQEmuLogSys::CloseFileLogs()
}
}
/**
* @param log_name
*/
void EQEmuLogSys::StartFileLogs(const std::string &log_name)
{
EQEmuLogSys::CloseFileLogs();
/* When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one... */
if (file_logs_enabled == false)
/**
* When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one...
*/
if (!file_logs_enabled) {
return;
}
/**
* Zone
*/
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) {
if (!log_name.empty())
if (!log_name.empty()) {
platform_file_name = log_name;
}
if (platform_file_name.empty())
if (platform_file_name.empty()) {
return;
}
EQEmuLogSys::Out(Logs::General, Logs::Status, "Starting File Log 'logs/%s_%i.log'", platform_file_name.c_str(), getpid());
EQEmuLogSys::Out(
Logs::General,
Logs::Status,
"Starting File Log 'logs/%s_%i.log'",
platform_file_name.c_str(),
getpid());
/**
* Make directory if not exists
*/
EQEmuLogSys::MakeDirectory("logs/zone");
process_log.open(StringFormat("logs/zone/%s_%i.log", platform_file_name.c_str(), getpid()), std::ios_base::app | std::ios_base::out);
} else {
if (platform_file_name.empty())
return;
EQEmuLogSys::Out(Logs::General, Logs::Status, "Starting File Log 'logs/%s_%i.log'", platform_file_name.c_str(), getpid());
process_log.open(StringFormat("logs/%s_%i.log", platform_file_name.c_str(), getpid()), std::ios_base::app | std::ios_base::out);
/**
* Open file pointer
*/
process_log.open(
StringFormat("logs/zone/%s_%i.log", platform_file_name.c_str(), getpid()),
std::ios_base::app | std::ios_base::out
);
}
else {
/**
* All other processes
*/
if (platform_file_name.empty()) {
return;
}
EQEmuLogSys::Out(
Logs::General,
Logs::Status,
"Starting File Log 'logs/%s_%i.log'",
platform_file_name.c_str(),
getpid());
/**
* Open file pointer
*/
process_log.open(
StringFormat("logs/%s_%i.log", platform_file_name.c_str(), getpid()),
std::ios_base::app | std::ios_base::out
);
}
}

View File

@ -1,20 +1,21 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net)
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
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* 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
*
*/
#ifndef EQEMU_LOGSYS_H
@ -34,130 +35,134 @@ namespace Logs {
Detail /* 3 - Use this for extreme detail in logging, usually in extreme debugging in the stack or interprocess communication */
};
/*
If you add to this, make sure you update LogCategoryName
NOTE: Only add to the bottom of the enum because that is the type ID assignment
*/
/**
* If you add to this, make sure you update LogCategoryName
*
* NOTE: Only add to the bottom of the enum because that is the type ID assignment
*/
enum LogCategory {
None = 0,
AA,
AI,
Aggro,
Attack,
Client_Server_Packet,
Combat,
Commands,
Crash,
Debug,
Doors,
Error,
Guilds,
Inventory,
Launcher,
Netcode,
Normal,
Object,
Pathing,
QS_Server,
Quests,
Rules,
Skills,
Spawns,
Spells,
Status,
TCP_Connection,
Tasks,
Tradeskills,
Trading,
Tribute,
UCS_Server,
WebInterface_Server,
World_Server,
Zone_Server,
MySQLError,
MySQLQuery,
Mercenaries,
QuestDebug,
Server_Client_Packet,
Client_Server_Packet_Unhandled,
Server_Client_Packet_With_Dump,
Client_Server_Packet_With_Dump,
Login_Server,
Client_Login,
Headless_Client,
HP_Update,
FixZ,
Food,
Traps,
NPCRoamBox,
NPCScaling,
MaxCategoryID /* Don't Remove this */
};
enum LogCategory {
None = 0,
AA,
AI,
Aggro,
Attack,
Client_Server_Packet,
Combat,
Commands,
Crash,
Debug,
Doors,
Error,
Guilds,
Inventory,
Launcher,
Netcode,
Normal,
Object,
Pathing,
QS_Server,
Quests,
Rules,
Skills,
Spawns,
Spells,
Status,
TCP_Connection,
Tasks,
Tradeskills,
Trading,
Tribute,
UCS_Server,
WebInterface_Server,
World_Server,
Zone_Server,
MySQLError,
MySQLQuery,
Mercenaries,
QuestDebug,
Server_Client_Packet,
Client_Server_Packet_Unhandled,
Server_Client_Packet_With_Dump,
Client_Server_Packet_With_Dump,
Login_Server,
Client_Login,
Headless_Client,
HP_Update,
FixZ,
Food,
Traps,
NPCRoamBox,
MaxCategoryID /* Don't Remove this*/
};
/* If you add to this, make sure you update LogCategory */
static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
"",
"AA",
"AI",
"Aggro",
"Attack",
"Packet :: Client -> Server",
"Combat",
"Commands",
"Crash",
"Debug",
"Doors",
"Error",
"Guilds",
"Inventory",
"Launcher",
"Netcode",
"Normal",
"Object",
"Pathing",
"QS Server",
"Quests",
"Rules",
"Skills",
"Spawns",
"Spells",
"Status",
"TCP Connection",
"Tasks",
"Tradeskills",
"Trading",
"Tribute",
"UCS Server",
"WebInterface Server",
"World Server",
"Zone Server",
"MySQL Error",
"MySQL Query",
"Mercenaries",
"Quest Debug",
"Packet :: Server -> Client",
"Packet :: Client -> Server Unhandled",
"Packet :: Server -> Client (Dump)",
"Packet :: Client -> Server (Dump)",
"Login Server",
"Client Login",
"Headless Client",
"HP Update",
"FixZ",
"Food",
"Traps",
"NPC Roam Box"
};
/**
* If you add to this, make sure you update LogCategory
*/
static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
"",
"AA",
"AI",
"Aggro",
"Attack",
"Packet :: Client -> Server",
"Combat",
"Commands",
"Crash",
"Debug",
"Doors",
"Error",
"Guilds",
"Inventory",
"Launcher",
"Netcode",
"Normal",
"Object",
"Pathing",
"QS Server",
"Quests",
"Rules",
"Skills",
"Spawns",
"Spells",
"Status",
"TCP Connection",
"Tasks",
"Tradeskills",
"Trading",
"Tribute",
"UCS Server",
"WebInterface Server",
"World Server",
"Zone Server",
"MySQL Error",
"MySQL Query",
"Mercenaries",
"Quest Debug",
"Packet :: Server -> Client",
"Packet :: Client -> Server Unhandled",
"Packet :: Server -> Client (Dump)",
"Packet :: Client -> Server (Dump)",
"Login Server",
"Client Login",
"Headless Client",
"HP Update",
"FixZ",
"Food",
"Traps",
"NPC Roam Box",
"NPC Scaling"
};
}
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
LogSys.Out(debug_level, log_category, message, ##__VA_ARGS__);\
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
LogSys.Out(debug_level, log_category, message, ##__VA_ARGS__);\
} while (0)
#define LogF(debug_level, log_category, message, ...) do {\
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
LogSys.OutF(debug_level, log_category, message, ##__VA_ARGS__);\
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
LogSys.OutF(debug_level, log_category, message, ##__VA_ARGS__);\
} while (0)
class EQEmuLogSys {
@ -165,21 +170,30 @@ public:
EQEmuLogSys();
~EQEmuLogSys();
void CloseFileLogs(); /* Close File Logs wherever necessary, either at zone shutdown or entire process shutdown for everything else. This should be handled on deconstructor but to be safe we use it anyways. */
void LoadLogSettingsDefaults(); /* Initializes log_settings and sets some defaults if DB is not present */
void MakeDirectory(const std::string &directory_name); /* Platform independent way of performing a MakeDirectory based on name */
/*
The one and only Logging function that uses a debug level as a parameter, as well as a log_category
log_category - defined in Logs::LogCategory::[]
log_category name resolution works by passing the enum int ID to Logs::LogCategoryName[category_id]
/**
* Close File Logs wherever necessary, either at zone shutdown or entire process shutdown for everything else.
* This should be handled on deconstructor but to be safe we use it anyways.
*/
void CloseFileLogs();
void LoadLogSettingsDefaults();
void MakeDirectory(const std::string &directory_name);
Example: EQEmuLogSys::Out(Logs::General, Logs::Guilds, "This guild has no leader present");
- This would pipe the same category and debug level to all output formats, but the internal memory reference of log_settings would
be checked against to see if that piped output is set to actually process it for the category and debug level
/**
* The one and only Logging function that uses a debug level as a parameter, as well as a log_category
* log_category - defined in Logs::LogCategory::[]
* log_category name resolution works by passing the enum int ID to Logs::LogCategoryName[category_id]
*
* Example: EQEmuLogSys::Out(Logs::General, Logs::Guilds, "This guild has no leader present");
* - This would pipe the same category and debug level to all output formats, but the internal memory reference of log_settings would
* be checked against to see if that piped output is set to actually process it for the category and debug level
*/
void Out(Logs::DebugLevel debug_level, uint16 log_category, std::string message, ...);
void SetCurrentTimeStamp(char* time_stamp); /* Used in file logs to prepend a timestamp entry for logs */
void StartFileLogs(const std::string &log_name = ""); /* Used to declare the processes file log and to keep it open for later use */
/**
* Used in file logs to prepend a timestamp entry for logs
*/
void SetCurrentTimeStamp(char* time_stamp);
void StartFileLogs(const std::string &log_name = "");
template <typename... Args>
void OutF(Logs::DebugLevel debug_level, uint16 log_category, const char *fmt, const Args&... args)
@ -188,16 +202,16 @@ public:
Out(debug_level, log_category, log_str);
}
/*
LogSettings Struct
This struct is the master reference for all settings for each category, and for each output
log_to_file[category_id] = [1-3] - Sets debug level for category to output to file
log_to_console[category_id] = [1-3] - Sets debug level for category to output to console
log_to_gmsay[category_id] = [1-3] - Sets debug level for category to output to gmsay
/**
* LogSettings Struct
*
* This struct is the master reference for all settings for each category, and for each output
*
* log_to_file[category_id] = [1-3] - Sets debug level for category to output to file
* log_to_console[category_id] = [1-3] - Sets debug level for category to output to console
* log_to_gmsay[category_id] = [1-3] - Sets debug level for category to output to gmsay
*
*/
struct LogSettings {
uint8 log_to_file;
uint8 log_to_console;
@ -205,32 +219,62 @@ public:
uint8 is_category_enabled; /* When any log output in a category > 0, set this to 1 as (Enabled) */
};
/* Internally used memory reference for all log settings per category.
These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults.
Database loaded via Database::LoadLogSettings(log_settings)
/**
* Internally used memory reference for all log settings per category
* These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults
* Database loaded via Database::LoadLogSettings(log_settings)
*/
LogSettings log_settings[Logs::LogCategory::MaxCategoryID];
bool file_logs_enabled; /* Set when log settings are loaded to determine if keeping a file open is necessary */
bool file_logs_enabled;
int log_platform; /* Sets Executable platform (Zone/World/UCS) etc. */
/**
* Sets Executable platform (Zone/World/UCS) etc.
*/
int log_platform;
std::string platform_file_name; /* File name used in writing logs */
/**
* File name used in writing logs
*/
std::string platform_file_name;
uint16 GetGMSayColorFromCategory(uint16 log_category); /* GMSay Client Message colors mapped by category */
/**
* GMSay Client Message colors mapped by category
*
* @param log_category
* @return
*/
uint16 GetGMSayColorFromCategory(uint16 log_category);
void OnLogHookCallBackZone(std::function<void(uint16 log_type, const std::string&)> f) { on_log_gmsay_hook = f; }
private:
std::function<void(uint16 log_category, const std::string&)> on_log_gmsay_hook; /* Callback pointer to zone process for hooking logs to zone using GMSay */
std::string FormatOutMessageString(uint16 log_category, const std::string &in_message); /* Formats log messages like '[Category] This is a log message' */
std::string GetLinuxConsoleColorFromCategory(uint16 log_category); /* Linux console color messages mapped by category */
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category); /* Windows console color messages mapped by category */
/**
* Callback pointer to zone process for hooking logs to zone using GMSay
*/
std::function<void(uint16 log_category, const std::string&)> on_log_gmsay_hook;
void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessConsoleMessage called via Log */
void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessGMSay called via Log */
void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessLogWrite called via Log */
/**
* Formats log messages like '[Category] This is a log message'
*/
std::string FormatOutMessageString(uint16 log_category, const std::string &in_message);
/**
* Linux console color messages mapped by category
* @param log_category
* @return
*/
std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
/**
* Windows console color messages mapped by category
*/
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message);
void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message);
void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message);
};
extern EQEmuLogSys LogSys;