feat(Core/Logging): rework logging (#4692)

* feat(Core/Logging): rework logging

* correct level for sql.sql

* del unused config options

* Correct build

* correct after merge

* whitespace

20:29:37 1. 'Player.cpp'. Replace (1)
20:29:37 2. 'ObjectMgr.cpp'. Replace (3)

* 1

* correct logging

* correct affter merge

* 1

* 2

* LOG_LEVEL_WARN

* #include "AppenderDB.h"

* 3

* 4

* 5

* 1. 'WorldSocket.cpp'. Replace (1)

* 6

* 1
This commit is contained in:
Kargatum
2021-04-17 16:20:07 +07:00
committed by GitHub
parent b2861be1cd
commit 4af4cbd3d9
246 changed files with 7413 additions and 6807 deletions

View File

@@ -4,12 +4,17 @@
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#include "Config.h"
#include "MapManager.h"
#include "MMapManager.h"
#include "Log.h"
#include "StringFormat.h"
namespace MMAP
{
static char const* const MAP_FILE_NAME_FORMAT = "%s/mmaps/%03i.mmap";
static char const* const TILE_FILE_NAME_FORMAT = "%s/mmaps/%03i%02i%02i.mmtile";
// ######################## MMapManager ########################
MMapManager::~MMapManager()
{
@@ -27,17 +32,14 @@ namespace MMAP
return true;
// load and init dtNavMesh - read parameters from file
uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i.mmap") + 1;
char* fileName = new char[pathLen];
snprintf(fileName, pathLen, (sWorld->GetDataPath() + "mmaps/%03i.mmap").c_str(), mapId);
std::string fileName = acore::StringFormat(MAP_FILE_NAME_FORMAT, sConfigMgr->GetOption<std::string>("DataDir", ".").c_str(), mapId);
FILE* file = fopen(fileName, "rb");
FILE* file = fopen(fileName.c_str(), "rb");
if (!file)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName);
LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName.c_str());
#endif
delete [] fileName;
return false;
}
@@ -47,7 +49,6 @@ namespace MMAP
if (count != 1)
{
;//TC_LOG_DEBUG(LOG_FILTER_MAPS, "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName);
delete [] fileName;
return false;
}
@@ -56,15 +57,12 @@ namespace MMAP
if (DT_SUCCESS != mesh->init(&params))
{
dtFreeNavMesh(mesh);
sLog->outError("MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName);
delete [] fileName;
LOG_ERROR("server", "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName.c_str());
return false;
}
delete [] fileName;
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDetail("MMAP:loadMapData: Loaded %03i.mmap", mapId);
LOG_DEBUG("server", "MMAP:loadMapData: Loaded %03i.mmap", mapId);
#endif
// store inside our map list
@@ -85,7 +83,7 @@ namespace MMAP
Map* map = sMapMgr->FindBaseMap(mapId);
if (!map)
{
sLog->outMisc("ZOMG! MoveMaps: BaseMap not found!");
LOG_INFO("misc", "ZOMG! MoveMaps: BaseMap not found!");
return this->MMapLock;
}
@@ -108,38 +106,31 @@ namespace MMAP
uint32 packedGridPos = packTileID(x, y);
if (mmap->mmapLoadedTiles.find(packedGridPos) != mmap->mmapLoadedTiles.end())
{
sLog->outError("MMAP:loadMap: Asked to load already loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
LOG_ERROR("server", "MMAP:loadMap: Asked to load already loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
return false;
}
// load this tile :: mmaps/MMMXXYY.mmtile
uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile") + 1;
char* fileName = new char[pathLen];
snprintf(fileName, pathLen, (sWorld->GetDataPath() + "mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y);
FILE* file = fopen(fileName, "rb");
std::string fileName = acore::StringFormat(TILE_FILE_NAME_FORMAT, sConfigMgr->GetOption<std::string>("DataDir", ".").c_str(), mapId, x, y);
FILE* file = fopen(fileName.c_str(), "rb");
if (!file)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMap: Could not open mmtile file '%s'", fileName);
#endif
delete [] fileName;
LOG_DEBUG("maps", "MMAP:loadMap: Could not open mmtile file '%s'", fileName.c_str());
return false;
}
delete [] fileName;
// read header
MmapTileHeader fileHeader;
if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || fileHeader.mmapMagic != MMAP_MAGIC)
{
sLog->outError("MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y);
LOG_ERROR("server", "MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y);
fclose(file);
return false;
}
if (fileHeader.mmapVersion != MMAP_VERSION)
{
sLog->outError("MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i",
LOG_ERROR("server", "MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i",
mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION);
fclose(file);
return false;
@@ -151,7 +142,7 @@ namespace MMAP
size_t result = fread(data, fileHeader.size, 1, file);
if (!result)
{
sLog->outError("MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y);
LOG_ERROR("server", "MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y);
fclose(file);
return false;
}
@@ -173,13 +164,13 @@ namespace MMAP
++loadedTiles;
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
dtMeshHeader* header = (dtMeshHeader*)data;
sLog->outDetail("MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y);
LOG_DEBUG("server", "MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y);
#endif
return true;
}
else
{
sLog->outError("MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y);
LOG_ERROR("server", "MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y);
dtFree(data);
return false;
}
@@ -196,7 +187,7 @@ namespace MMAP
{
// file may not exist, therefore not loaded
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y);
LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y);
#endif
return false;
}
@@ -209,7 +200,7 @@ namespace MMAP
{
// file may not exist, therefore not loaded
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
#endif
return false;
}
@@ -228,7 +219,7 @@ namespace MMAP
// this is technically a memory leak
// if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
// we cannot recover from this error - assert out
sLog->outError("MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
LOG_ERROR("server", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
ABORT();
}
else
@@ -236,7 +227,7 @@ namespace MMAP
mmap->mmapLoadedTiles.erase(packedGridPos);
--loadedTiles;
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
LOG_DEBUG("server", "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
#endif
return true;
}
@@ -252,7 +243,7 @@ namespace MMAP
{
// file may not exist, therefore not loaded
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId);
LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId);
#endif
return false;
}
@@ -271,12 +262,12 @@ namespace MMAP
}
if (status != DT_SUCCESS)
sLog->outError("MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
LOG_ERROR("server", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
else
{
--loadedTiles;
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
LOG_DEBUG("server", "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
#endif
}
}
@@ -284,7 +275,7 @@ namespace MMAP
delete mmap;
loadedMMaps.erase(mapId);
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDetail("MMAP:unloadMap: Unloaded %03i.mmap", mapId);
LOG_DEBUG("server", "MMAP:unloadMap: Unloaded %03i.mmap", mapId);
#endif
return true;
@@ -299,7 +290,7 @@ namespace MMAP
{
// file may not exist, therefore not loaded
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId);
LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId);
#endif
return false;
}
@@ -308,7 +299,7 @@ namespace MMAP
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId);
LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId);
#endif
return false;
}
@@ -318,7 +309,7 @@ namespace MMAP
dtFreeNavMeshQuery(query);
mmap->navMeshQueries.erase(instanceId);
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDetail("MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
LOG_DEBUG("server", "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
#endif
return true;
@@ -351,12 +342,12 @@ namespace MMAP
if (DT_SUCCESS != query->init(mmap->navMesh, 1024))
{
dtFreeNavMeshQuery(query);
sLog->outError("MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
LOG_ERROR("server", "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
return nullptr;
}
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDetail("MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
LOG_DEBUG("server", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
#endif
mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query));
}

View File

@@ -7,10 +7,10 @@
#ifndef _MMAP_MANAGER_H
#define _MMAP_MANAGER_H
#include "Common.h"
#include "DetourAlloc.h"
#include "DetourNavMesh.h"
#include "DetourExtended.h"
#include "World.h"
#include <unordered_map>
#include <shared_mutex>

View File

@@ -270,12 +270,12 @@ namespace VMAP
WorldModel* worldmodel = new WorldModel();
if (!worldmodel->readFile(basepath + filename + ".vmo"))
{
sLog->outError("VMapManager2: could not load '%s%s.vmo'", basepath.c_str(), filename.c_str());
LOG_ERROR("server", "VMapManager2: could not load '%s%s.vmo'", basepath.c_str(), filename.c_str());
delete worldmodel;
return nullptr;
}
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_MAPS, "VMapManager2: loading file '%s%s'", basepath.c_str(), filename.c_str());
LOG_DEBUG("maps", "VMapManager2: loading file '%s%s'", basepath.c_str(), filename.c_str());
#endif
model = iLoadedModelFiles.insert(std::pair<std::string, ManagedModel>(filename, ManagedModel())).first;
model->second.setModel(worldmodel);
@@ -291,13 +291,13 @@ namespace VMAP
ModelFileMap::iterator model = iLoadedModelFiles.find(filename);
if (model == iLoadedModelFiles.end())
{
sLog->outError("VMapManager2: trying to unload non-loaded file '%s'", filename.c_str());
LOG_ERROR("server", "VMapManager2: trying to unload non-loaded file '%s'", filename.c_str());
return;
}
if (model->second.decRefCount() == 0)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_MAPS, "VMapManager2: unloading file '%s'", filename.c_str());
LOG_DEBUG("maps", "VMapManager2: unloading file '%s'", filename.c_str());
#endif
delete model->second.getModel();
iLoadedModelFiles.erase(model);

View File

@@ -5,12 +5,12 @@
*/
#include "MapTree.h"
#include "Common.h"
#include "ModelInstance.h"
#include "VMapManager2.h"
#include "VMapDefinitions.h"
#include "Log.h"
#include "Errors.h"
#include <string>
#include <sstream>
#include <iomanip>
@@ -45,7 +45,7 @@ namespace VMAP
void operator()(const Vector3& point, uint32 entry)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) && defined(VMAP_DEBUG)
sLog->outDebug(LOG_FILTER_MAPS, "AreaInfoCallback: trying to intersect '%s'", prims[entry].name.c_str());
LOG_DEBUG("maps", "AreaInfoCallback: trying to intersect '%s'", prims[entry].name.c_str());
#endif
prims[entry].intersectPoint(point, aInfo);
}
@@ -61,7 +61,7 @@ namespace VMAP
void operator()(const Vector3& point, uint32 entry)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) && defined(VMAP_DEBUG)
sLog->outDebug(LOG_FILTER_MAPS, "LocationInfoCallback: trying to intersect '%s'", prims[entry].name.c_str());
LOG_DEBUG("maps", "LocationInfoCallback: trying to intersect '%s'", prims[entry].name.c_str());
#endif
if (prims[entry].GetLocationInfo(point, locInfo))
result = true;
@@ -338,7 +338,7 @@ namespace VMAP
}
if (!iTreeValues)
{
sLog->outError("StaticMapTree::LoadMapTile() : tree has not been initialized [%u, %u]", tileX, tileY);
LOG_ERROR("server", "StaticMapTree::LoadMapTile() : tree has not been initialized [%u, %u]", tileX, tileY);
return false;
}
bool result = true;
@@ -364,7 +364,7 @@ namespace VMAP
// acquire model instance
WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name);
if (!model)
sLog->outError("StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY);
LOG_ERROR("server", "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY);
// update tree
uint32 referencedVal;
@@ -376,7 +376,7 @@ namespace VMAP
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) && defined(VMAP_DEBUG)
if (referencedVal > iNTreeValues)
{
sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::LoadMapTile() : invalid tree element (%u/%u)", referencedVal, iNTreeValues);
LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : invalid tree element (%u/%u)", referencedVal, iNTreeValues);
continue;
}
#endif
@@ -388,9 +388,9 @@ namespace VMAP
++iLoadedSpawns[referencedVal];
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) && defined(VMAP_DEBUG)
if (iTreeValues[referencedVal].ID != spawn.ID)
sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::LoadMapTile() : trying to load wrong spawn in node");
LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : trying to load wrong spawn in node");
else if (iTreeValues[referencedVal].name != spawn.name)
sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::LoadMapTile() : name collision on GUID=%u", spawn.ID);
LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : name collision on GUID=%u", spawn.ID);
#endif
}
}
@@ -414,7 +414,7 @@ namespace VMAP
loadedTileMap::iterator tile = iLoadedTiles.find(tileID);
if (tile == iLoadedTiles.end())
{
sLog->outError("StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:%u X:%u Y:%u", iMapID, tileX, tileY);
LOG_ERROR("server", "StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:%u X:%u Y:%u", iMapID, tileX, tileY);
return;
}
if (tile->second) // file associated with tile
@@ -448,7 +448,7 @@ namespace VMAP
else
{
if (!iLoadedSpawns.count(referencedNode))
sLog->outError("StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID);
LOG_ERROR("server", "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID);
else if (--iLoadedSpawns[referencedNode] == 0)
{
iTreeValues[referencedNode].setUnloaded();

View File

@@ -44,14 +44,14 @@ void LoadGameObjectModelList()
FILE* model_list_file = fopen((sWorld->GetDataPath() + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb");
if (!model_list_file)
{
sLog->outError("Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS);
LOG_ERROR("server", "Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS);
return;
}
char magic[8];
if (fread(magic, 1, 8, model_list_file) != 8 || memcmp(magic, VMAP::VMAP_MAGIC, 8) != 0)
{
sLog->outError("File '%s' has wrong header, expected %s.", VMAP::GAMEOBJECT_MODELS, VMAP::VMAP_MAGIC);
LOG_ERROR("maps", "File '%s' has wrong header, expected %s.", VMAP::GAMEOBJECT_MODELS, VMAP::VMAP_MAGIC);
return;
}
@@ -72,13 +72,13 @@ void LoadGameObjectModelList()
|| fread(&v1, sizeof(Vector3), 1, model_list_file) != 1
|| fread(&v2, sizeof(Vector3), 1, model_list_file) != 1)
{
sLog->outError("File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS);
LOG_ERROR("server", "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS);
break;
}
if (v1.isNaN() || v2.isNaN())
{
sLog->outError("File '%s' Model '%s' has invalid v1%s v2%s values!",
LOG_ERROR("maps", "File '%s' Model '%s' has invalid v1%s v2%s values!",
VMAP::GAMEOBJECT_MODELS, std::string(buff, name_length).c_str(), v1.toString().c_str(), v2.toString().c_str());
continue;
}
@@ -87,8 +87,9 @@ void LoadGameObjectModelList()
}
fclose(model_list_file);
sLog->outString(">> Loaded %u GameObject models in %u ms", uint32(model_list.size()), GetMSTimeDiffToNow(oldMSTime));
sLog->outString();
LOG_INFO("server", ">> Loaded %u GameObject models in %u ms", uint32(model_list.size()), GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server", " ");
}
GameObjectModel::~GameObjectModel()
@@ -107,7 +108,7 @@ bool GameObjectModel::initialize(const GameObject& go, const GameObjectDisplayIn
// ignore models with no bounds
if (mdl_box == G3D::AABox::zero())
{
sLog->outError("GameObject model %s has zero bounds, loading skipped", it->second.name.c_str());
LOG_ERROR("server", "GameObject model %s has zero bounds, loading skipped", it->second.name.c_str());
return false;
}

View File

@@ -27,7 +27,7 @@ namespace
{
if (!replace)
{
sLog->outError("> Config: Option '%s' is exist! Option key - '%s'", optionName.c_str(), itr->second.c_str());
LOG_ERROR("server", "> Config: Option '%s' is exist! Option key - '%s'", optionName.c_str(), itr->second.c_str());
return;
}
@@ -92,7 +92,7 @@ namespace
}
catch (const std::exception& e)
{
sLog->outError("> Config: %s", e.what());
LOG_ERROR("server", "> Config: %s", e.what());
}
return false;
@@ -134,7 +134,7 @@ T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLog
{
if (showLogs)
{
sLog->outError("> Config: Missing name %s in config, add \"%s = %s\"",
LOG_ERROR("server", "> Config: Missing name %s in config, add \"%s = %s\"",
name.c_str(), name.c_str(), acore::ToString(def).c_str());
}
@@ -146,7 +146,7 @@ T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLog
{
if (showLogs)
{
sLog->outError("> Config: Bad value defined for name '%s', going to use '%s' instead",
LOG_ERROR("server", "> Config: Bad value defined for name '%s', going to use '%s' instead",
name.c_str(), acore::ToString(def).c_str());
}
@@ -164,7 +164,7 @@ std::string ConfigMgr::GetValueDefault<std::string>(std::string const& name, std
{
if (showLogs)
{
sLog->outError("> Config: Missing name %s in config, add \"%s = %s\"",
LOG_ERROR("server", "> Config: Missing name %s in config, add \"%s = %s\"",
name.c_str(), name.c_str(), def.c_str());
}
@@ -190,7 +190,7 @@ bool ConfigMgr::GetOption<bool>(std::string const& name, bool const& def, bool s
{
if (showLogs)
{
sLog->outError("> Config: Bad value defined for name '%s', going to use '%s' instead",
LOG_ERROR("server", "> Config: Bad value defined for name '%s', going to use '%s' instead",
name.c_str(), def ? "true" : "false");
}
@@ -299,13 +299,13 @@ bool ConfigMgr::LoadModulesConfigs()
return false;
// Print modules configurations
sLog->outString();
sLog->outString("Using modules configuration:");
LOG_INFO("server", " ");
LOG_INFO("server", "Using modules configuration:");
for (auto const& itr : moduleConfigFiles)
sLog->outString("> %s", itr.c_str());
LOG_INFO("server", "> %s", itr.c_str());
sLog->outString("");
LOG_INFO("server", " ");
return true;
}

View File

@@ -19,14 +19,14 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st
std::string const dbString = sConfigMgr->GetOption<std::string>(name + "DatabaseInfo", "");
if (dbString.empty())
{
sLog->outSQLDriver("Database %s not specified in configuration file!", name.c_str());
LOG_INFO("sql.driver", "Database %s not specified in configuration file!", name.c_str());
return false;
}
uint8 const asyncThreads = sConfigMgr->GetOption<uint8>(name + "Database.WorkerThreads", 1);
if (asyncThreads < 1 || asyncThreads > 32)
{
sLog->outSQLDriver("%s database: invalid number of worker threads specified. Please pick a value between 1 and 32.", name.c_str());
LOG_INFO("sql.driver", "%s database: invalid number of worker threads specified. Please pick a value between 1 and 32.", name.c_str());
return false;
}
@@ -46,7 +46,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st
auto sleepThread = [&]()
{
sLog->outSQLDriver("> Retrying after %u seconds", durationSecs.count());
LOG_INFO("sql.driver", "> Retrying after %u seconds", static_cast<uint32>(durationSecs.count()));
std::this_thread::sleep_for(durationSecs);
};
@@ -72,7 +72,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st
// If the error wasn't handled quit
if (error)
{
sLog->outSQLDriver("DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile for specific errors", name.c_str());
LOG_ERROR("sql.driver", "DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile for specific errors", name.c_str());
return false;
}
}
@@ -90,7 +90,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st
{
if (!pool.PrepareStatements())
{
sLog->outSQLDriver("Could not prepare statements of the %s database, see log for details.", name.c_str());
LOG_ERROR("sql.driver", "Could not prepare statements of the %s database, see log for details.", name.c_str());
return false;
}

View File

@@ -38,8 +38,8 @@ uint32 DatabaseWorkerPool<T>::Open()
{
WPFatal(_connectionInfo.get(), "Connection info was not set!");
sLog->outSQLDriver("Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.",
GetDatabaseName(), _async_threads, _synch_threads);
LOG_INFO("sql.driver", "Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.",
GetDatabaseName(), _async_threads, _synch_threads);
uint32 error = OpenConnections(IDX_ASYNC, _async_threads);
@@ -52,17 +52,19 @@ uint32 DatabaseWorkerPool<T>::Open()
if (!error)
{
sLog->outSQLDriver("DatabasePool '%s' opened successfully. %u total connections running.",
GetDatabaseName(), (_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC]));
LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. %u total connections running.",
GetDatabaseName(), (_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC]));
}
LOG_INFO("sql.driver", " ");
return error;
}
template <class T>
void DatabaseWorkerPool<T>::Close()
{
sLog->outSQLDriver("Closing down DatabasePool '%s'.", GetDatabaseName());
LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName());
//! Shuts down delaythreads for this connection pool by underlying deactivate().
//! The next dequeue attempt in the worker thread tasks will result in an error,
@@ -78,8 +80,8 @@ void DatabaseWorkerPool<T>::Close()
t->Close(); //! Closes the actualy MySQL connection.
}
sLog->outSQLDriver("Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.",
GetDatabaseName());
LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.",
GetDatabaseName());
//! Shut down the synchronous connections
//! There's no need for locking the connection, because DatabaseWorkerPool<>::Close
@@ -92,7 +94,7 @@ void DatabaseWorkerPool<T>::Close()
delete _queue;
delete _mqueue;
sLog->outSQLDriver("All connections on DatabasePool '%s' closed.", GetDatabaseName());
LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName());
}
template <class T>
@@ -125,7 +127,7 @@ uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConne
{
if (mysql_get_server_version(t->GetHandle()) < MIN_MYSQL_SERVER_VERSION)
{
sLog->outSQLDriver("Not support MySQL versions below 5.7");
LOG_ERROR("sql.driver", "Not support MySQL versions below 5.7");
error = 1;
}
}
@@ -299,10 +301,10 @@ void DatabaseWorkerPool<T>::CommitTransaction(SQLTransaction transaction)
switch (transaction->GetSize())
{
case 0:
sLog->outSQLDriver("Transaction contains 0 queries. Not executing.");
LOG_INFO("sql.driver", "Transaction contains 0 queries. Not executing.");
return;
case 1:
sLog->outSQLDriver("Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
LOG_INFO("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
break;
default:
break;

View File

@@ -32,7 +32,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_TINY))
{
sLog->outSQLDriver("Warning: GetUInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetUInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type));
return 0;
}
#endif
@@ -50,7 +50,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_TINY))
{
sLog->outSQLDriver("Warning: GetInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type));
return 0;
}
#endif
@@ -75,7 +75,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR))
{
sLog->outSQLDriver("Warning: GetUInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetUInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type));
return 0;
}
#endif
@@ -93,7 +93,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR))
{
sLog->outSQLDriver("Warning: GetInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type));
return 0;
}
#endif
@@ -111,7 +111,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG))
{
sLog->outSQLDriver("Warning: GetUInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetUInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type));
return 0;
}
#endif
@@ -129,7 +129,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG))
{
sLog->outSQLDriver("Warning: GetInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type));
return 0;
}
#endif
@@ -147,7 +147,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT))
{
sLog->outSQLDriver("Warning: GetUInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetUInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type));
return 0;
}
#endif
@@ -165,7 +165,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT))
{
sLog->outSQLDriver("Warning: GetInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type));
return 0;
}
#endif
@@ -183,7 +183,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_FLOAT))
{
sLog->outSQLDriver("Warning: GetFloat() on non-float field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetFloat() on non-float field. Using type: %s.", FieldTypeToString(data.type));
return 0.0f;
}
#endif
@@ -201,7 +201,7 @@ public:
#ifdef ACORE_DEBUG
if (!IsType(MYSQL_TYPE_DOUBLE))
{
sLog->outSQLDriver("Warning: GetDouble() on non-double field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Warning: GetDouble() on non-double field. Using type: %s.", FieldTypeToString(data.type));
return 0.0f;
}
#endif
@@ -219,7 +219,7 @@ public:
#ifdef ACORE_DEBUG
if (IsNumeric())
{
sLog->outSQLDriver("Error: GetCString() on numeric field. Using type: %s.", FieldTypeToString(data.type));
LOG_INFO("sql.driver", "Error: GetCString() on numeric field. Using type: %s.", FieldTypeToString(data.type));
return nullptr;
}
#endif
@@ -331,7 +331,7 @@ protected:
MYSQL_TYPE_SET:
*/
default:
sLog->outSQLDriver("SQL::SizeForType(): invalid field type %u", uint32(field->type));
LOG_INFO("sql.driver", "SQL::SizeForType(): invalid field type %u", uint32(field->type));
return 0;
}
}

View File

@@ -93,4 +93,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_INS_CHAR_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
// 0: string, 1: string, 2: string // Complete name: "Login_Insert_Failed_Account_Login_due_password_IP_Logging"
PrepareStatement(LOGIN_INS_FALP_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES ((SELECT id FROM account WHERE username = ?), 0, 1, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
// DB logging
PrepareStatement(LOGIN_INS_LOG, "INSERT INTO logs (time, realm, type, level, string) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC);
}

View File

@@ -111,6 +111,8 @@ enum LoginDatabaseStatements
LOGIN_SEL_ACCOUNT_MUTE_INFO,
LOGIN_DEL_ACCOUNT_MUTED,
LOGIN_INS_LOG,
MAX_LOGINDATABASE_STATEMENTS
};

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "AppenderDB.h"
#include "DatabaseEnv.h"
#include "LogMessage.h"
#include "PreparedStatement.h"
AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level, AppenderFlags /*flags*/, std::vector<std::string_view> const& /*args*/)
: Appender(id, name, level), realmId(0), enabled(false) { }
AppenderDB::~AppenderDB() { }
void AppenderDB::_write(LogMessage const* message)
{
// Avoid infinite loop, PExecute triggers Logging with "sql.sql" type
if (!enabled || (message->type.find("sql") != std::string::npos))
return;
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG);
stmt->setUInt64(0, message->mtime);
stmt->setUInt32(1, realmId);
stmt->setString(2, message->type);
stmt->setUInt8(3, uint8(message->level));
stmt->setString(4, message->text);
LoginDatabase.Execute(stmt);
}
void AppenderDB::setRealmId(uint32 _realmId)
{
enabled = true;
realmId = _realmId;
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef APPENDERDB_H
#define APPENDERDB_H
#include "Appender.h"
class AppenderDB : public Appender
{
public:
static constexpr AppenderType type = APPENDER_DB;
AppenderDB(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args);
~AppenderDB();
void setRealmId(uint32 realmId) override;
AppenderType getType() const override { return type; }
private:
uint32 realmId;
bool enabled;
void _write(LogMessage const* message) override;
};
#endif

View File

@@ -68,7 +68,7 @@ uint32 MySQLConnection::Open()
MYSQL* mysqlInit = mysql_init(nullptr);
if (!mysqlInit)
{
sLog->outError("Could not initialize Mysql connection to database `%s`", m_connectionInfo.database.c_str());
LOG_ERROR("sql.sql", "Could not initialize Mysql connection to database `%s`", m_connectionInfo.database.c_str());
return false;
}
@@ -121,18 +121,17 @@ uint32 MySQLConnection::Open()
{
if (!m_reconnecting)
{
sLog->outSQLDriver("MySQL client library: %s", mysql_get_client_info());
sLog->outSQLDriver("MySQL server ver: %s ", mysql_get_server_info(m_Mysql));
LOG_INFO("sql.sql", "MySQL client library: %s", mysql_get_client_info());
LOG_INFO("sql.sql", "MySQL server ver: %s ", mysql_get_server_info(m_Mysql));
if (mysql_get_server_version(m_Mysql) != mysql_get_client_version())
{
sLog->outSQLDriver("[WARNING] MySQL client/server version mismatch; may conflict with behaviour of prepared statements.");
LOG_WARN("sql.sql", "[WARNING] MySQL client/server version mismatch; may conflict with behaviour of prepared statements.");
}
}
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDetail("Connected to MySQL database at %s", m_connectionInfo.host.c_str());
#endif
LOG_INFO("sql.sql", "Connected to MySQL database at %s", m_connectionInfo.host.c_str());
mysql_autocommit(m_Mysql, 1);
// set connection properties to UTF8 to properly handle locales for different
@@ -141,7 +140,7 @@ uint32 MySQLConnection::Open()
return 0;
}
sLog->outError("Could not connect to MySQL database at %s: %s", m_connectionInfo.host.c_str(), mysql_error(mysqlInit));
LOG_ERROR("sql.sql", "Could not connect to MySQL database at %s: %s", m_connectionInfo.host.c_str(), mysql_error(mysqlInit));
uint32 errorCode = mysql_errno(mysqlInit);
mysql_close(mysqlInit);
return errorCode;
@@ -158,29 +157,23 @@ bool MySQLConnection::Execute(const char* sql)
if (!m_Mysql)
return false;
uint32 _s = getMSTime();
if (mysql_query(m_Mysql, sql))
{
uint32 _s = 0;
if (sLog->GetSQLDriverQueryLogging())
_s = getMSTime();
uint32 lErrno = mysql_errno(m_Mysql);
if (mysql_query(m_Mysql, sql))
{
uint32 lErrno = mysql_errno(m_Mysql);
LOG_ERROR("sql.sql", "SQL: %s", sql);
LOG_ERROR("sql.sql", "ERROR: [%u] %s", lErrno, mysql_error(m_Mysql));
sLog->outSQLDriver("SQL: %s", sql);
sLog->outSQLDriver("ERROR: [%u] %s", lErrno, mysql_error(m_Mysql));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(sql); // Try again
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(sql); // Try again
return false;
}
else if (sLog->GetSQLDriverQueryLogging())
{
sLog->outSQLDriver("[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql);
}
return false;
}
LOG_DEBUG("sql.sql", "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql);
return true;
}
@@ -201,14 +194,12 @@ bool MySQLConnection::Execute(PreparedStatement* stmt)
MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
uint32 _s = 0;
if (sLog->GetSQLDriverQueryLogging())
_s = getMSTime();
uint32 _s = getMSTime();
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
{
uint32 lErrno = mysql_errno(m_Mysql);
sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(stmt); // Try again
@@ -220,7 +211,7 @@ bool MySQLConnection::Execute(PreparedStatement* stmt)
if (mysql_stmt_execute(msql_STMT))
{
uint32 lErrno = mysql_errno(m_Mysql);
sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(stmt); // Try again
@@ -229,8 +220,7 @@ bool MySQLConnection::Execute(PreparedStatement* stmt)
return false;
}
if (sLog->GetSQLDriverQueryLogging())
sLog->outSQLDriver("[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str());
LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str());
m_mStmt->ClearParameters();
return true;
@@ -254,14 +244,12 @@ bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES** pResult, uint6
MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
uint32 _s = 0;
if (sLog->GetSQLDriverQueryLogging())
_s = getMSTime();
uint32 _s = getMSTime();
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
{
uint32 lErrno = mysql_errno(m_Mysql);
sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again
@@ -273,8 +261,8 @@ bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES** pResult, uint6
if (mysql_stmt_execute(msql_STMT))
{
uint32 lErrno = mysql_errno(m_Mysql);
sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s",
m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s",
m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again
@@ -283,8 +271,7 @@ bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES** pResult, uint6
return false;
}
if (sLog->GetSQLDriverQueryLogging())
sLog->outSQLDriver("[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str());
LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str());
m_mStmt->ClearParameters();
@@ -318,32 +305,28 @@ bool MySQLConnection::_Query(const char* sql, MYSQL_RES** pResult, MYSQL_FIELD**
return false;
{
uint32 _s = 0;
if (sLog->GetSQLDriverQueryLogging())
_s = getMSTime();
uint32 _s = getMSTime();
if (mysql_query(m_Mysql, sql))
{
uint32 lErrno = mysql_errno(m_Mysql);
sLog->outSQLDriver("SQL: %s", sql);
sLog->outSQLDriver("ERROR: [%u] %s", lErrno, mysql_error(m_Mysql));
LOG_ERROR("sql.sql", "SQL: %s", sql);
LOG_ERROR("sql.sql", "ERROR: [%u] %s", lErrno, mysql_error(m_Mysql));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(sql, pResult, pFields, pRowCount, pFieldCount); // We try again
return false;
}
else if (sLog->GetSQLDriverQueryLogging())
{
sLog->outSQLDriver("[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql);
}
LOG_DEBUG("sql.sql", "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql);
*pResult = mysql_store_result(m_Mysql);
*pRowCount = mysql_affected_rows(m_Mysql);
*pFieldCount = mysql_field_count(m_Mysql);
}
if (!*pResult )
if (!*pResult)
return false;
if (!*pRowCount)
@@ -392,7 +375,7 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
ASSERT(stmt);
if (!Execute(stmt))
{
sLog->outSQLDriver("[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size());
LOG_INFO("sql.driver", "[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size());
RollbackTransaction();
return false;
}
@@ -404,7 +387,7 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
ASSERT(sql);
if (!Execute(sql))
{
sLog->outSQLDriver("[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size());
LOG_INFO("sql.driver", "[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size());
RollbackTransaction();
return false;
}
@@ -427,7 +410,7 @@ MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index)
ASSERT(index < m_stmts.size());
MySQLPreparedStatement* ret = m_stmts[index];
if (!ret)
sLog->outSQLDriver("ERROR: Could not fetch prepared statement %u on database `%s`, connection type: %s.",
LOG_INFO("sql.driver", "ERROR: Could not fetch prepared statement %u on database `%s`, connection type: %s.",
index, m_connectionInfo.database.c_str(), (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
return ret;
@@ -453,16 +436,16 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection
MYSQL_STMT* stmt = mysql_stmt_init(m_Mysql);
if (!stmt)
{
sLog->outSQLDriver("[ERROR]: In mysql_stmt_init() id: %u, sql: \"%s\"", index, sql);
sLog->outSQLDriver("[ERROR]: %s", mysql_error(m_Mysql));
LOG_INFO("sql.driver", "[ERROR]: In mysql_stmt_init() id: %u, sql: \"%s\"", index, sql);
LOG_INFO("sql.driver", "[ERROR]: %s", mysql_error(m_Mysql));
m_prepareError = true;
}
else
{
if (mysql_stmt_prepare(stmt, sql, static_cast<unsigned long>(strlen(sql))))
{
sLog->outSQLDriver("[ERROR]: In mysql_stmt_prepare() id: %u, sql: \"%s\"", index, sql);
sLog->outSQLDriver("[ERROR]: %s", mysql_stmt_error(stmt));
LOG_INFO("sql.driver", "[ERROR]: In mysql_stmt_prepare() id: %u, sql: \"%s\"", index, sql);
LOG_INFO("sql.driver", "[ERROR]: %s", mysql_stmt_error(stmt));
mysql_stmt_close(stmt);
m_prepareError = true;
}
@@ -506,9 +489,9 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo)
mysql_close(GetHandle());
if (this->Open()) // Don't remove 'this' pointer unless you want to skip loading all prepared statements....
{
sLog->outSQLDriver("Connection to the MySQL server is active.");
LOG_INFO("sql.driver", "Connection to the MySQL server is active.");
if (oldThreadId != mysql_thread_id(GetHandle()))
sLog->outSQLDriver("Successfully reconnected to %s @%s:%s (%s).",
LOG_INFO("sql.driver", "Successfully reconnected to %s @%s:%s (%s).",
m_connectionInfo.database.c_str(), m_connectionInfo.host.c_str(), m_connectionInfo.port_or_socket.c_str(),
(m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
@@ -531,17 +514,17 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo)
// Outdated table or database structure - terminate core
case ER_BAD_FIELD_ERROR:
case ER_NO_SUCH_TABLE:
sLog->outError("Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders.");
LOG_ERROR("server", "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders.");
std::this_thread::sleep_for(10s);
std::abort();
return false;
case ER_PARSE_ERROR:
sLog->outError("Error while parsing SQL. Core fix required.");
LOG_ERROR("server", "Error while parsing SQL. Core fix required.");
std::this_thread::sleep_for(10s);
std::abort();
return false;
default:
sLog->outError("Unhandled MySQL errno %u. Unexpected behaviour possible.", errNo);
LOG_ERROR("server", "Unhandled MySQL errno %u. Unexpected behaviour possible.", errNo);
return false;
}
}

View File

@@ -73,7 +73,7 @@ void PreparedStatement::BindParameters()
}
#ifdef _DEBUG
if (i < m_stmt->m_paramCount)
sLog->outSQLDriver("[WARNING]: BindParameters() for statement %u did not bind all allocated parameters", m_index);
LOG_INFO("sql.driver", "[WARNING]: BindParameters() for statement %u did not bind all allocated parameters", m_index);
#endif
}
@@ -246,7 +246,7 @@ void MySQLPreparedStatement::ClearParameters()
static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 paramCount)
{
sLog->outError("Attempted to bind parameter %u%s on a PreparedStatement %u (statement has only %u parameters)", uint32(index) + 1, (index == 1 ? "st" : (index == 2 ? "nd" : (index == 3 ? "rd" : "nd"))), stmtIndex, paramCount);
LOG_ERROR("server", "Attempted to bind parameter %u%s on a PreparedStatement %u (statement has only %u parameters)", uint32(index) + 1, (index == 1 ? "st" : (index == 2 ? "nd" : (index == 3 ? "rd" : "nd"))), stmtIndex, paramCount);
return false;
}
@@ -256,7 +256,7 @@ bool MySQLPreparedStatement::CheckValidIndex(uint8 index)
ASSERT(index < m_paramCount || ParamenterIndexAssertFail(m_stmt->m_index, index, m_paramCount));
if (m_paramsSet[index])
sLog->outSQLDriver("[WARNING] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->m_index, index);
LOG_INFO("sql.driver", "[WARNING] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->m_index, index);
return true;
}

View File

@@ -13,7 +13,7 @@ bool SQLQueryHolder::SetQuery(size_t index, const char* sql)
{
if (m_queries.size() <= index)
{
sLog->outError("Query index (%u) out of range (size: %u) for query: %s", uint32(index), (uint32)m_queries.size(), sql);
LOG_ERROR("server", "Query index (%u) out of range (size: %u) for query: %s", uint32(index), (uint32)m_queries.size(), sql);
return false;
}
@@ -33,7 +33,7 @@ bool SQLQueryHolder::SetPQuery(size_t index, const char* format, ...)
{
if (!format)
{
sLog->outError("Query (index: %u) is empty.", uint32(index));
LOG_ERROR("server", "Query (index: %u) is empty.", uint32(index));
return false;
}
@@ -45,7 +45,7 @@ bool SQLQueryHolder::SetPQuery(size_t index, const char* format, ...)
if (res == -1)
{
sLog->outError("SQL Query truncated (and not execute) for format: %s", format);
LOG_ERROR("server", "SQL Query truncated (and not execute) for format: %s", format);
return false;
}
@@ -56,7 +56,7 @@ bool SQLQueryHolder::SetPreparedQuery(size_t index, PreparedStatement* stmt)
{
if (m_queries.size() <= index)
{
sLog->outError("Query index (%u) out of range (size: %u) for prepared statement", uint32(index), (uint32)m_queries.size());
LOG_ERROR("server", "Query index (%u) out of range (size: %u) for prepared statement", uint32(index), (uint32)m_queries.size());
return false;
}

View File

@@ -47,7 +47,7 @@ PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES* result, uint64
//- This is where we store the (entire) resultset
if (mysql_stmt_store_result(m_stmt))
{
sLog->outSQLDriver("%s:mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
LOG_INFO("sql.driver", "%s:mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
delete[] m_rBind;
delete[] m_isNull;
delete[] m_length;
@@ -77,7 +77,7 @@ PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES* result, uint64
//- This is where we bind the bind the buffer to the statement
if (mysql_stmt_bind_result(m_stmt, m_rBind))
{
sLog->outSQLDriver("%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
LOG_INFO("sql.driver", "%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
delete[] m_rBind;
delete[] m_isNull;
delete[] m_length;

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "Appender.h"
#include "LogMessage.h"
#include "StringFormat.h"
#include <sstream>
Appender::Appender(uint8 _id, std::string const& _name, LogLevel _level /* = LOG_LEVEL_DISABLED */, AppenderFlags _flags /* = APPENDER_FLAGS_NONE */):
id(_id), name(_name), level(_level), flags(_flags) { }
Appender::~Appender() { }
uint8 Appender::getId() const
{
return id;
}
std::string const& Appender::getName() const
{
return name;
}
LogLevel Appender::getLogLevel() const
{
return level;
}
AppenderFlags Appender::getFlags() const
{
return flags;
}
void Appender::setLogLevel(LogLevel _level)
{
level = _level;
}
void Appender::write(LogMessage* message)
{
if (!level || level < message->level)
return;
std::ostringstream ss;
if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP)
ss << message->getTimeStr() << ' ';
if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL)
ss << acore::StringFormat("%-5s ", Appender::getLogLevelString(message->level));
if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE)
ss << '[' << message->type << "] ";
message->prefix = ss.str();
_write(message);
}
char const* Appender::getLogLevelString(LogLevel level)
{
switch (level)
{
case LOG_LEVEL_FATAL:
return "FATAL";
case LOG_LEVEL_ERROR:
return "ERROR";
case LOG_LEVEL_WARN:
return "WARN";
case LOG_LEVEL_INFO:
return "INFO";
case LOG_LEVEL_DEBUG:
return "DEBUG";
case LOG_LEVEL_TRACE:
return "TRACE";
default:
return "DISABLED";
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef APPENDER_H
#define APPENDER_H
#include "Define.h"
#include "LogCommon.h"
#include <stdexcept>
#include <string>
#include <vector>
struct LogMessage;
class Appender
{
public:
Appender(uint8 _id, std::string const& name, LogLevel level = LOG_LEVEL_DISABLED, AppenderFlags flags = APPENDER_FLAGS_NONE);
virtual ~Appender();
uint8 getId() const;
std::string const& getName() const;
virtual AppenderType getType() const = 0;
LogLevel getLogLevel() const;
AppenderFlags getFlags() const;
void setLogLevel(LogLevel);
void write(LogMessage* message);
static char const* getLogLevelString(LogLevel level);
virtual void setRealmId(uint32 /*realmId*/) { }
private:
virtual void _write(LogMessage const* /*message*/) = 0;
uint8 id;
std::string name;
LogLevel level;
AppenderFlags flags;
};
class InvalidAppenderArgsException : public std::length_error
{
public:
explicit InvalidAppenderArgsException(std::string const& message) : std::length_error(message) { }
};
#endif

View File

@@ -0,0 +1,191 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "AppenderConsole.h"
#include "LogMessage.h"
#include "SmartEnum.h"
#include "StringFormat.h"
#include "StringConvert.h"
#include "Util.h"
#include "Tokenize.h"
#include <sstream>
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
#include <Windows.h>
#endif
AppenderConsole::AppenderConsole(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args)
: Appender(id, name, level, flags), _colored(false)
{
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
_colors[i] = ColorTypes(NUM_COLOR_TYPES);
if (3 < args.size())
InitColors(name, args[3]);
}
void AppenderConsole::InitColors(std::string const& name, std::string_view str)
{
if (str.empty())
{
_colored = false;
return;
}
std::vector<std::string_view> colorStrs = acore::Tokenize(str, ' ', false);
if (colorStrs.size() != NUM_ENABLED_LOG_LEVELS)
{
throw InvalidAppenderArgsException(acore::StringFormat("Log::CreateAppenderFromConfig: Invalid color data '%s' for console appender %s (expected %u entries, got %zu)",
std::string(str).c_str(), name.c_str(), NUM_ENABLED_LOG_LEVELS, colorStrs.size()));
}
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
{
if (Optional<uint8> color = acore::StringTo<uint8>(colorStrs[i]); color && EnumUtils::IsValid<ColorTypes>(*color))
_colors[i] = static_cast<ColorTypes>(*color);
else
{
throw InvalidAppenderArgsException(acore::StringFormat("Log::CreateAppenderFromConfig: Invalid color '%s' for log level %s on console appender %s",
std::string(colorStrs[i]).c_str(), EnumUtils::ToTitle(static_cast<LogLevel>(i)), name.c_str()));
}
}
_colored = true;
}
void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color)
{
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
static WORD WinColorFG[NUM_COLOR_TYPES] =
{
0, // BLACK
FOREGROUND_RED, // RED
FOREGROUND_GREEN, // GREEN
FOREGROUND_RED | FOREGROUND_GREEN, // BROWN
FOREGROUND_BLUE, // BLUE
FOREGROUND_RED | FOREGROUND_BLUE, // MAGENTA
FOREGROUND_GREEN | FOREGROUND_BLUE, // CYAN
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // WHITE
// YELLOW
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
// RED_BOLD
FOREGROUND_RED | FOREGROUND_INTENSITY,
// GREEN_BOLD
FOREGROUND_GREEN | FOREGROUND_INTENSITY,
FOREGROUND_BLUE | FOREGROUND_INTENSITY, // BLUE_BOLD
// MAGENTA_BOLD
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
// CYAN_BOLD
FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
// WHITE_BOLD
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
};
HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
SetConsoleTextAttribute(hConsole, WinColorFG[color]);
#else
enum ANSITextAttr
{
TA_NORMAL = 0,
TA_BOLD = 1,
TA_BLINK = 5,
TA_REVERSE = 7
};
enum ANSIFgTextAttr
{
FG_BLACK = 30,
FG_RED,
FG_GREEN,
FG_BROWN,
FG_BLUE,
FG_MAGENTA,
FG_CYAN,
FG_WHITE,
FG_YELLOW
};
enum ANSIBgTextAttr
{
BG_BLACK = 40,
BG_RED,
BG_GREEN,
BG_BROWN,
BG_BLUE,
BG_MAGENTA,
BG_CYAN,
BG_WHITE
};
static uint8 UnixColorFG[NUM_COLOR_TYPES] =
{
FG_BLACK, // BLACK
FG_RED, // RED
FG_GREEN, // GREEN
FG_BROWN, // BROWN
FG_BLUE, // BLUE
FG_MAGENTA, // MAGENTA
FG_CYAN, // CYAN
FG_WHITE, // WHITE
FG_YELLOW, // YELLOW
FG_RED, // LRED
FG_GREEN, // LGREEN
FG_BLUE, // LBLUE
FG_MAGENTA, // LMAGENTA
FG_CYAN, // LCYAN
FG_WHITE // LWHITE
};
fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < NUM_COLOR_TYPES ? ";1" : ""));
#endif
}
void AppenderConsole::ResetColor(bool stdout_stream)
{
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
#else
fprintf((stdout_stream ? stdout : stderr), "\x1b[0m");
#endif
}
void AppenderConsole::_write(LogMessage const* message)
{
bool stdout_stream = !(message->level == LOG_LEVEL_ERROR || message->level == LOG_LEVEL_FATAL);
if (_colored)
{
uint8 index;
switch (message->level)
{
case LOG_LEVEL_TRACE:
index = 5;
break;
case LOG_LEVEL_DEBUG:
index = 4;
break;
case LOG_LEVEL_INFO:
index = 3;
break;
case LOG_LEVEL_WARN:
index = 2;
break;
case LOG_LEVEL_FATAL:
index = 0;
break;
default:
index = 1;
break;
}
SetColor(stdout_stream, _colors[index]);
utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
ResetColor(stdout_stream);
}
else
utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef APPENDERCONSOLE_H
#define APPENDERCONSOLE_H
#include "Appender.h"
// EnumUtils: DESCRIBE THIS
enum ColorTypes
{
BLACK,
RED,
GREEN,
BROWN,
BLUE,
MAGENTA,
CYAN,
GREY,
YELLOW,
LRED,
LGREEN,
LBLUE,
LMAGENTA,
LCYAN,
WHITE,
NUM_COLOR_TYPES // SKIP
};
class AppenderConsole : public Appender
{
public:
static constexpr AppenderType type = APPENDER_CONSOLE;
AppenderConsole(uint8 _id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args);
void InitColors(std::string const& name, std::string_view init_str);
AppenderType getType() const override { return type; }
private:
void SetColor(bool stdout_stream, ColorTypes color);
void ResetColor(bool stdout_stream);
void _write(LogMessage const* message) override;
bool _colored;
ColorTypes _colors[NUM_ENABLED_LOG_LEVELS];
};
#endif

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "AppenderFile.h"
#include "Log.h"
#include "LogMessage.h"
#include "StringConvert.h"
#include "Util.h"
#include <algorithm>
AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args) :
Appender(id, name, level, flags),
logfile(nullptr),
_logDir(sLog->GetLogsDir()),
_maxFileSize(0),
_fileSize(0)
{
if (args.size() < 4)
throw InvalidAppenderArgsException(acore::StringFormat("Log::CreateAppenderFromConfig: Missing file name for appender %s", name.c_str()));
_fileName.assign(args[3]);
std::string mode = "a";
if (4 < args.size())
mode.assign(args[4]);
if (flags & APPENDER_FLAGS_USE_TIMESTAMP)
{
size_t dot_pos = _fileName.find_last_of('.');
if (dot_pos != std::string::npos)
_fileName.insert(dot_pos, sLog->GetLogsTimestamp());
else
_fileName += sLog->GetLogsTimestamp();
}
if (5 < args.size())
{
if (Optional<uint32> size = acore::StringTo<uint32>(args[5]))
_maxFileSize = *size;
else
throw InvalidAppenderArgsException(acore::StringFormat("Log::CreateAppenderFromConfig: Invalid size '%s' for appender %s", std::string(args[5]).c_str(), name.c_str()));
}
_dynamicName = std::string::npos != _fileName.find("%s");
_backup = (flags & APPENDER_FLAGS_MAKE_FILE_BACKUP) != 0;
if (!_dynamicName)
logfile = OpenFile(_fileName, mode, (mode == "w") && _backup);
}
AppenderFile::~AppenderFile()
{
CloseFile();
}
void AppenderFile::_write(LogMessage const* message)
{
bool exceedMaxSize = _maxFileSize > 0 && (_fileSize.load() + message->Size()) > _maxFileSize;
if (_dynamicName)
{
char namebuf[ACORE_PATH_MAX];
snprintf(namebuf, ACORE_PATH_MAX, _fileName.c_str(), message->param1.c_str());
// always use "a" with dynamic name otherwise it could delete the log we wrote in last _write() call
FILE* file = OpenFile(namebuf, "a", _backup || exceedMaxSize);
if (!file)
return;
fprintf(file, "%s%s\n", message->prefix.c_str(), message->text.c_str());
fflush(file);
_fileSize += uint64(message->Size());
fclose(file);
return;
}
else if (exceedMaxSize)
logfile = OpenFile(_fileName, "w", true);
if (!logfile)
return;
fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str());
fflush(logfile);
_fileSize += uint64(message->Size());
}
FILE* AppenderFile::OpenFile(std::string const& filename, std::string const& mode, bool backup)
{
std::string fullName(_logDir + filename);
if (backup)
{
CloseFile();
std::string newName(fullName);
newName.push_back('.');
newName.append(LogMessage::getTimeStr(time(nullptr)));
std::replace(newName.begin(), newName.end(), ':', '-');
rename(fullName.c_str(), newName.c_str()); // no error handling... if we couldn't make a backup, just ignore
}
if (FILE* ret = fopen(fullName.c_str(), mode.c_str()))
{
_fileSize = ftell(ret);
return ret;
}
return nullptr;
}
void AppenderFile::CloseFile()
{
if (logfile)
{
fclose(logfile);
logfile = nullptr;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef APPENDERFILE_H
#define APPENDERFILE_H
#include "Appender.h"
#include <atomic>
class AppenderFile : public Appender
{
public:
static constexpr AppenderType type = APPENDER_FILE;
AppenderFile(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args);
~AppenderFile();
FILE* OpenFile(std::string const& name, std::string const& mode, bool backup);
AppenderType getType() const override { return type; }
private:
void CloseFile();
void _write(LogMessage const* message) override;
FILE* logfile;
std::string _fileName;
std::string _logDir;
bool _dynamicName;
bool _backup;
uint64 _maxFileSize;
std::atomic<uint64> _fileSize;
};
#endif

View File

@@ -1,130 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
#ifndef AZEROTHCORE_ILOG_H
#define AZEROTHCORE_ILOG_H
class WorldPacket;
enum DebugLogFilters
{
LOG_FILTER_NONE = 0x00000000,
LOG_FILTER_UNITS = 0x00000001, // Anything related to units that doesn't fit in other categories. ie. creature formations
LOG_FILTER_PETS = 0x00000002,
LOG_FILTER_VEHICLES = 0x00000004,
LOG_FILTER_TSCR = 0x00000008, // C++ AI, instance scripts, etc.
LOG_FILTER_DATABASE_AI = 0x00000010, // SmartAI, EventAI, CreatureAI
LOG_FILTER_MAPSCRIPTS = 0x00000020,
LOG_FILTER_NETWORKIO = 0x00000040, // Anything packet/netcode related
LOG_FILTER_SPELLS_AURAS = 0x00000080,
LOG_FILTER_ACHIEVEMENTSYS = 0x00000100,
LOG_FILTER_CONDITIONSYS = 0x00000200,
LOG_FILTER_POOLSYS = 0x00000400,
LOG_FILTER_AUCTIONHOUSE = 0x00000800,
LOG_FILTER_BATTLEGROUND = 0x00001000, // Anything related to arena's and battlegrounds
LOG_FILTER_OUTDOORPVP = 0x00002000,
LOG_FILTER_CHATSYS = 0x00004000,
LOG_FILTER_LFG = 0x00008000,
LOG_FILTER_MAPS = 0x00010000, // Maps, instances, grids, cells, visibility
LOG_FILTER_PLAYER_LOADING = 0x00020000, // Debug output from Player::_Load functions
LOG_FILTER_PLAYER_ITEMS = 0x00040000, // Anything item related
LOG_FILTER_PLAYER_SKILLS = 0x00080000, // Skills related
LOG_FILTER_LOOT = 0x00100000, // Loot related
LOG_FILTER_GUILD = 0x00200000, // Guild related
LOG_FILTER_TRANSPORTS = 0x00400000, // Transport related
LOG_FILTER_WARDEN = 0x00800000, // Warden related
LOG_FILTER_BATTLEFIELD = 0x01000000, // Battlefield related
LOG_FILTER_MODULES = 0x02000000, // Modules debug
LOG_FILTER_CLOSE_SOCKET = 0x04000000, // Whenever KickPlayer() or CloseSocket() are called
};
enum LogTypes
{
LOG_TYPE_STRING = 0,
LOG_TYPE_ERROR = 1,
LOG_TYPE_BASIC = 2,
LOG_TYPE_DETAIL = 3,
LOG_TYPE_DEBUG = 4,
LOG_TYPE_CHAR = 5,
LOG_TYPE_WORLD = 6,
LOG_TYPE_RA = 7,
LOG_TYPE_GM = 8,
LOG_TYPE_CRASH = 9,
LOG_TYPE_CHAT = 10,
LOG_TYPE_PERF = 11,
LOG_TYPE_MULTITH = 12,
MAX_LOG_TYPES
};
enum LogLevel
{
LOGL_NORMAL = 0,
LOGL_BASIC,
LOGL_DETAIL,
LOGL_DEBUG
};
const int LogLevels = int(LOGL_DEBUG) + 1;
enum ColorTypes
{
BLACK,
RED,
GREEN,
BROWN,
BLUE,
MAGENTA,
CYAN,
GREY,
YELLOW,
LRED,
LGREEN,
LBLUE,
LMAGENTA,
LCYAN,
WHITE
};
const int Colors = int(WHITE) + 1;
class ILog
{
public:
virtual ~ILog() {}
virtual void Initialize() = 0;
virtual void ReloadConfig() = 0;
virtual void InitColors(const std::string& init_str) = 0;
virtual void SetColor(bool stdout_stream, ColorTypes color) = 0;
virtual void ResetColor(bool stdout_stream) = 0;
virtual void outDB(LogTypes type, const char* str) = 0;
virtual void outString(const char* str, ...) = 0;
virtual void outString() = 0;
virtual void outStringInLine(const char* str, ...) = 0;
virtual void outError(const char* err, ...) = 0;
virtual void outCrash(const char* err, ...) = 0;
virtual void outBasic(const char* str, ...) = 0;
virtual void outDetail(const char* str, ...) = 0;
virtual void outSQLDev(const char* str, ...) = 0;
virtual void outDebug(DebugLogFilters f, const char* str, ...) = 0;
virtual void outStaticDebug(const char* str, ...) = 0;
virtual void outErrorDb(const char* str, ...) = 0;
virtual void outChar(const char* str, ...) = 0;
virtual void outCommand(uint32 account, const char* str, ...) = 0;
virtual void outChat(const char* str, ...) = 0;
virtual void outRemote(const char* str, ...) = 0;
virtual void outSQLDriver(const char* str, ...) = 0;
virtual void outMisc(const char* str, ...) = 0;
virtual void outCharDump(const char* str, uint32 account_id, uint32 guid, const char* name) = 0;
virtual void SetLogLevel(char* Level) = 0;
virtual void SetLogFileLevel(char* Level) = 0;
virtual void SetSQLDriverQueryLogging(bool newStatus) = 0;
virtual void SetRealmID(uint32 id) = 0;
virtual bool IsOutDebug() const = 0;
virtual bool IsOutCharDump() const = 0;
virtual bool GetLogDB() const = 0;
virtual void SetLogDB(bool enable) = 0;
virtual bool GetSQLDriverQueryLogging() const = 0;
};
#endif //AZEROTHCORE_ILOG_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,120 +1,256 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef AZEROTHCORE_LOG_H
#define AZEROTHCORE_LOG_H
#ifndef _LOG_H__
#define _LOG_H__
#include "Common.h"
#include "ILog.h"
#include <ace/Task.h>
#include "Define.h"
#include "LogCommon.h"
#include "StringFormat.h"
class Log : public ILog
#include <memory>
#include <unordered_map>
#include <vector>
class Appender;
class Logger;
struct LogMessage;
#define LOGGER_ROOT "root"
typedef Appender*(*AppenderCreatorFn)(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& extraArgs);
template <class AppenderImpl>
Appender* CreateAppender(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& extraArgs)
{
return new AppenderImpl(id, name, level, flags, extraArgs);
}
class Log
{
typedef std::unordered_map<std::string, Logger> LoggerMap;
private:
Log();
~Log();
Log(Log const&) = delete;
Log(Log&&) = delete;
Log& operator=(Log const&) = delete;
Log& operator=(Log&&) = delete;
public:
Log();
~Log();
static Log* instance();
void Initialize();
void LoadFromConfig();
void Close();
bool ShouldLog(std::string const& type, LogLevel level) const;
bool SetLogLevel(std::string const& name, int32 level, bool isLogger = true);
void ReloadConfig();
template<typename Format, typename... Args>
inline void outMessage(std::string const& filter, LogLevel const level, Format&& fmt, Args&&... args)
{
outMessage(filter, level, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
void InitColors(const std::string& init_str);
void SetColor(bool stdout_stream, ColorTypes color);
void ResetColor(bool stdout_stream);
template<typename Format, typename... Args>
void outCommand(uint32 account, Format&& fmt, Args&&... args)
{
if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
return;
void outDB(LogTypes type, const char* str);
void outString(const char* str, ...) ATTR_PRINTF(2, 3);
void outString();
void outStringInLine(const char* str, ...) ATTR_PRINTF(2, 3);
void outError(const char* err, ...) ATTR_PRINTF(2, 3);
void outCrash(const char* err, ...) ATTR_PRINTF(2, 3);
void outBasic(const char* str, ...) ATTR_PRINTF(2, 3);
void outDetail(const char* str, ...) ATTR_PRINTF(2, 3);
void outSQLDev(const char* str, ...) ATTR_PRINTF(2, 3);
void outDebug(DebugLogFilters f, const char* str, ...) ATTR_PRINTF(3, 4);
void outStaticDebug(const char* str, ...) ATTR_PRINTF(2, 3);
void outErrorDb(const char* str, ...) ATTR_PRINTF(2, 3);
void outChar(const char* str, ...) ATTR_PRINTF(2, 3);
void outCommand(uint32 account, const char* str, ...) ATTR_PRINTF(3, 4);
void outChat(const char* str, ...) ATTR_PRINTF(2, 3);
void outRemote(const char* str, ...) ATTR_PRINTF(2, 3);
void outSQLDriver(const char* str, ...) ATTR_PRINTF(2, 3);
void outMisc(const char* str, ...) ATTR_PRINTF(2, 3); // pussywizard
void outCharDump(const char* str, uint32 account_id, uint32 guid, const char* name);
outCommand(acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...), std::to_string(account));
}
static void outTimestamp(FILE* file);
static std::string GetTimestampStr();
void outCharDump(char const* str, uint32 account_id, uint64 guid, char const* name);
void SetLogLevel(char* Level);
void SetLogFileLevel(char* Level);
void SetSQLDriverQueryLogging(bool newStatus) { m_sqlDriverQueryLogging = newStatus; }
void SetRealmID(uint32 id) { realm = id; }
void SetRealmId(uint32 id);
[[nodiscard]] bool IsOutDebug() const { return m_logLevel > 2 || (m_logFileLevel > 2 && logfile); }
[[nodiscard]] bool IsOutCharDump() const { return m_charLog_Dump; }
template<class AppenderImpl>
void RegisterAppender()
{
RegisterAppender(AppenderImpl::type, &CreateAppender<AppenderImpl>);
}
std::string const& GetLogsDir() const { return m_logsDir; }
std::string const& GetLogsTimestamp() const { return m_logsTimestamp; }
// Deprecated functions
template<typename Format, typename... Args>
inline void outString(Format&& fmt, Args&& ... args)
{
outMessage("server", LOG_LEVEL_INFO, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
inline void outString()
{
outMessage("server", LOG_LEVEL_INFO, " ");
}
template<typename Format, typename... Args>
inline void outError(Format&& fmt, Args&& ... args)
{
outMessage("server", LOG_LEVEL_ERROR, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
template<typename Format, typename... Args>
void outErrorDb(Format&& fmt, Args&& ... args)
{
if (!ShouldLog("sql.sql", LOG_LEVEL_ERROR))
return;
outMessage("sql.sql", LOG_LEVEL_ERROR, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
template<typename Format, typename... Args>
inline void outBasic(Format&& fmt, Args&& ... args)
{
outMessage("server", LOG_LEVEL_INFO, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
template<typename Format, typename... Args>
inline void outDetail(Format&& fmt, Args&& ... args)
{
outMessage("server", LOG_LEVEL_INFO, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
template<typename Format, typename... Args>
void outSQLDev(Format&& fmt, Args&& ... args)
{
if (!ShouldLog("sql.dev", LOG_LEVEL_INFO))
return;
outMessage("sql.dev", LOG_LEVEL_INFO, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
template<typename Format, typename... Args>
void outSQLDriver(Format&& fmt, Args&& ... args)
{
if (!ShouldLog("sql.driver", LOG_LEVEL_INFO))
return;
outMessage("sql.driver", LOG_LEVEL_INFO, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
template<typename Format, typename... Args>
inline void outMisc(Format&& fmt, Args&& ... args)
{
outMessage("server", LOG_LEVEL_INFO, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
template<typename Format, typename... Args>
void outDebug(DebugLogFilters filter, Format&& fmt, Args&& ... args)
{
if (!(_debugLogMask & filter))
return;
if (!ShouldLog("server", LOG_LEVEL_DEBUG))
return;
outMessage("server", LOG_LEVEL_DEBUG, acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
[[nodiscard]] bool GetLogDB() const { return m_enableLogDB; }
void SetLogDB(bool enable) { m_enableLogDB = enable; }
[[nodiscard]] bool GetSQLDriverQueryLogging() const { return m_sqlDriverQueryLogging; }
private:
FILE* openLogFile(char const* configFileName, char const* configTimeStampFlag, char const* mode);
FILE* openGmlogPerAccount(uint32 account);
static std::string GetTimestampStr();
void write(std::unique_ptr<LogMessage>&& msg) const;
FILE* raLogfile;
FILE* logfile;
FILE* gmLogfile;
FILE* charLogfile;
FILE* dberLogfile;
FILE* chatLogfile;
FILE* sqlLogFile;
FILE* sqlDevLogFile;
FILE* miscLogFile;
Logger const* GetLoggerByType(std::string const& type) const;
Appender* GetAppenderByName(std::string_view name);
uint8 NextAppenderId();
void CreateAppenderFromConfig(std::string const& name);
void CreateLoggerFromConfig(std::string const& name);
void ReadAppendersFromConfig();
void ReadLoggersFromConfig();
void RegisterAppender(uint8 index, AppenderCreatorFn appenderCreateFn);
void outMessage(std::string const& filter, LogLevel level, std::string&& message);
void outCommand(std::string&& message, std::string&& param1);
std::unordered_map<uint8, AppenderCreatorFn> appenderFactory;
std::unordered_map<uint8, std::unique_ptr<Appender>> appenders;
std::unordered_map<std::string, std::unique_ptr<Logger>> loggers;
uint8 AppenderId;
LogLevel highestLogLevel;
// cache values for after initilization use (like gm log per account case)
std::string m_logsDir;
std::string m_logsTimestamp;
// gm log control
bool m_gmlog_per_account;
std::string m_gmlog_filename_format;
bool m_enableLogDB;
uint32 realm;
// log coloring
bool m_colored;
ColorTypes m_colors[4];
// log levels:
// false: errors only, true: full query logging
bool m_sqlDriverQueryLogging;
// log levels:
// 0 minimum/string, 1 basic/error, 2 detail, 3 full/debug
uint8 m_dbLogLevel;
uint8 m_logLevel;
uint8 m_logFileLevel;
bool m_dbChar;
bool m_dbRA;
bool m_dbGM;
bool m_dbChat;
bool m_charLog_Dump;
bool m_charLog_Dump_Separate;
std::string m_dumpsDir;
DebugLogFilters m_DebugLogMask;
// Deprecated debug filter logs
DebugLogFilters _debugLogMask;
};
std::unique_ptr<ILog>& getLogInstance();
#define sLog Log::instance()
#define sLog getLogInstance()
#define LOG_EXCEPTION_FREE(filterType__, level__, ...) \
{ \
try \
{ \
sLog->outMessage(filterType__, level__, __VA_ARGS__); \
} \
catch (std::exception const& e) \
{ \
sLog->outMessage("server", LOG_LEVEL_ERROR, "Wrong format occurred (%s) at %s:%u.", \
e.what(), __FILE__, __LINE__); \
} \
}
#ifdef PERFORMANCE_PROFILING
#define LOG_MESSAGE_BODY(filterType__, level__, ...) ((void)0)
#elif AC_PLATFORM != AC_PLATFORM_WINDOWS
void check_args(char const*, ...) ATTR_PRINTF(1, 2);
void check_args(std::string const&, ...);
// This will catch format errors on build time
#define LOG_MESSAGE_BODY(filterType__, level__, ...) \
do { \
if (sLog->ShouldLog(filterType__, level__)) \
{ \
if (false) \
check_args(__VA_ARGS__); \
\
LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
} \
} while (0)
#else
#define LOG_MESSAGE_BODY(filterType__, level__, ...) \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
do { \
if (sLog->ShouldLog(filterType__, level__)) \
LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
} while (0) \
__pragma(warning(pop))
#endif
// Fatal - 1
#define LOG_FATAL(filterType__, ...) \
LOG_MESSAGE_BODY(filterType__, LogLevel::LOG_LEVEL_FATAL, __VA_ARGS__)
// Error - 2
#define LOG_ERROR(filterType__, ...) \
LOG_MESSAGE_BODY(filterType__, LogLevel::LOG_LEVEL_ERROR, __VA_ARGS__)
// Warning - 3
#define LOG_WARN(filterType__, ...) \
LOG_MESSAGE_BODY(filterType__, LogLevel::LOG_LEVEL_WARN, __VA_ARGS__)
// Info - 4
#define LOG_INFO(filterType__, ...) \
LOG_MESSAGE_BODY(filterType__, LogLevel::LOG_LEVEL_INFO, __VA_ARGS__)
// Debug - 5
#define LOG_DEBUG(filterType__, ...) \
LOG_MESSAGE_BODY(filterType__, LogLevel::LOG_LEVEL_DEBUG, __VA_ARGS__)
// Trace - 6
#define LOG_TRACE(filterType__, ...) \
LOG_MESSAGE_BODY(filterType__, LogLevel::LOG_LEVEL_TRACE, __VA_ARGS__)
#define LOG_CHAR_DUMP(message__, accountId__, guid__, name__) \
sLog->outCharDump(message__, accountId__, guid__, name__)
#define LOG_GM(accountId__, ...) \
sLog->outCommand(accountId__, __VA_ARGS__)
#endif // _LOG_H__

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef LogCommon_h__
#define LogCommon_h__
#include "Define.h"
// EnumUtils: DESCRIBE THIS
enum LogLevel : uint8
{
LOG_LEVEL_DISABLED,
LOG_LEVEL_FATAL,
LOG_LEVEL_ERROR,
LOG_LEVEL_WARN,
LOG_LEVEL_INFO,
LOG_LEVEL_DEBUG,
LOG_LEVEL_TRACE,
NUM_ENABLED_LOG_LEVELS = LOG_LEVEL_TRACE, // SKIP
LOG_LEVEL_INVALID = 0xFF // SKIP
};
// EnumUtils: DESCRIBE THIS
enum AppenderType : uint8
{
APPENDER_NONE,
APPENDER_CONSOLE,
APPENDER_FILE,
APPENDER_DB,
APPENDER_INVALID = 0xFF // SKIP
};
enum AppenderFlags : uint8
{
APPENDER_FLAGS_NONE = 0x00,
APPENDER_FLAGS_PREFIX_TIMESTAMP = 0x01,
APPENDER_FLAGS_PREFIX_LOGLEVEL = 0x02,
APPENDER_FLAGS_PREFIX_LOGFILTERTYPE = 0x04,
APPENDER_FLAGS_USE_TIMESTAMP = 0x08,
APPENDER_FLAGS_MAKE_FILE_BACKUP = 0x10
};
// Dprecated debug log filters need delte later
enum DebugLogFilters
{
LOG_FILTER_NONE = 0x00000000,
LOG_FILTER_UNITS = 0x00000001, // Anything related to units that doesn't fit in other categories. ie. creature formations
LOG_FILTER_PETS = 0x00000002,
LOG_FILTER_VEHICLES = 0x00000004,
LOG_FILTER_TSCR = 0x00000008, // C++ AI, instance scripts, etc.
LOG_FILTER_DATABASE_AI = 0x00000010, // SmartAI, EventAI, CreatureAI
LOG_FILTER_MAPSCRIPTS = 0x00000020,
LOG_FILTER_NETWORKIO = 0x00000040, // Anything packet/netcode related
LOG_FILTER_SPELLS_AURAS = 0x00000080,
LOG_FILTER_ACHIEVEMENTSYS = 0x00000100,
LOG_FILTER_CONDITIONSYS = 0x00000200,
LOG_FILTER_POOLSYS = 0x00000400,
LOG_FILTER_AUCTIONHOUSE = 0x00000800,
LOG_FILTER_BATTLEGROUND = 0x00001000, // Anything related to arena's and battlegrounds
LOG_FILTER_OUTDOORPVP = 0x00002000,
LOG_FILTER_CHATSYS = 0x00004000,
LOG_FILTER_LFG = 0x00008000,
LOG_FILTER_MAPS = 0x00010000, // Maps, instances, grids, cells, visibility
LOG_FILTER_PLAYER_LOADING = 0x00020000, // Debug output from Player::_Load functions
LOG_FILTER_PLAYER_ITEMS = 0x00040000, // Anything item related
LOG_FILTER_PLAYER_SKILLS = 0x00080000, // Skills related
LOG_FILTER_LOOT = 0x00100000, // Loot related
LOG_FILTER_GUILD = 0x00200000, // Guild related
LOG_FILTER_TRANSPORTS = 0x00400000, // Transport related
LOG_FILTER_WARDEN = 0x00800000, // Warden related
LOG_FILTER_BATTLEFIELD = 0x01000000, // Battlefield related
LOG_FILTER_MODULES = 0x02000000, // Modules debug
LOG_FILTER_CLOSE_SOCKET = 0x04000000, // Whenever KickPlayer() or CloseSocket() are called
};
#endif // LogCommon_h__

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "LogMessage.h"
#include "StringFormat.h"
#include "Util.h"
LogMessage::LogMessage(LogLevel _level, std::string const& _type, std::string&& _text)
: level(_level), type(_type), text(std::forward<std::string>(_text)), mtime(time(nullptr))
{
}
LogMessage::LogMessage(LogLevel _level, std::string const& _type, std::string&& _text, std::string&& _param1)
: level(_level), type(_type), text(std::forward<std::string>(_text)), param1(std::forward<std::string>(_param1)), mtime(time(nullptr))
{
}
std::string LogMessage::getTimeStr(time_t time)
{
tm aTm;
localtime_r(&time, &aTm);
return acore::StringFormat("%04d-%02d-%02d_%02d:%02d:%02d", aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
}
std::string LogMessage::getTimeStr() const
{
return getTimeStr(mtime);
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef LogMessage_h__
#define LogMessage_h__
#include "Define.h"
#include "LogCommon.h"
#include <string>
#include <ctime>
struct LogMessage
{
LogMessage(LogLevel _level, std::string const& _type, std::string&& _text);
LogMessage(LogLevel _level, std::string const& _type, std::string&& _text, std::string&& _param1);
LogMessage(LogMessage const& /*other*/) = delete;
LogMessage& operator=(LogMessage const& /*other*/) = delete;
static std::string getTimeStr(time_t time);
std::string getTimeStr() const;
LogLevel const level;
std::string const type;
std::string const text;
std::string prefix;
std::string param1;
time_t mtime;
///@ Returns size of the log message content in bytes
uint32 Size() const
{
return static_cast<uint32>(prefix.size() + text.size());
}
};
#endif // LogMessage_h__

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "LogOperation.h"
#include "Logger.h"
#include "LogMessage.h"
LogOperation::LogOperation(Logger const* _logger, std::unique_ptr<LogMessage>&& _msg) : logger(_logger), msg(std::forward<std::unique_ptr<LogMessage>>(_msg))
{
}
LogOperation::~LogOperation()
{
}
int LogOperation::call()
{
logger->write(msg.get());
return 0;
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef LOGOPERATION_H
#define LOGOPERATION_H
#include "Define.h"
#include <memory>
class Logger;
struct LogMessage;
class LogOperation
{
public:
LogOperation(Logger const* _logger, std::unique_ptr<LogMessage>&& _msg);
~LogOperation();
int call();
protected:
Logger const* logger;
std::unique_ptr<LogMessage> msg;
};
#endif

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "Logger.h"
#include "Appender.h"
#include "LogMessage.h"
Logger::Logger(std::string const& _name, LogLevel _level): name(_name), level(_level) { }
std::string const& Logger::getName() const
{
return name;
}
LogLevel Logger::getLogLevel() const
{
return level;
}
void Logger::addAppender(uint8 id, Appender* appender)
{
appenders[id] = appender;
}
void Logger::delAppender(uint8 id)
{
appenders.erase(id);
}
void Logger::setLogLevel(LogLevel _level)
{
level = _level;
}
void Logger::write(LogMessage* message) const
{
if (!level || level < message->level || message->text.empty())
{
//fprintf(stderr, "Logger::write: Logger %s, Level %u. Msg %s Level %u WRONG LEVEL MASK OR EMPTY MSG\n", getName().c_str(), getLogLevel(), message.text.c_str(), message.level);
return;
}
for (std::pair<uint8 const, Appender*> const& appender : appenders)
if (appender.second)
appender.second->write(message);
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef LOGGER_H
#define LOGGER_H
#include "Define.h"
#include "LogCommon.h"
#include <unordered_map>
#include <string>
class Appender;
struct LogMessage;
class Logger
{
public:
Logger(std::string const& name, LogLevel level);
void addAppender(uint8 type, Appender* appender);
void delAppender(uint8 type);
std::string const& getName() const;
LogLevel getLogLevel() const;
void setLogLevel(LogLevel level);
void write(LogMessage* message) const;
private:
std::string name;
LogLevel level;
std::unordered_map<uint8, Appender*> appenders;
};
#endif

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "AppenderConsole.h"
#include "Define.h"
#include "SmartEnum.h"
#include <stdexcept>
namespace acore::Impl::EnumUtilsImpl
{
/********************************************************************\
|* data for enum 'ColorTypes' in 'AppenderConsole.h' auto-generated *|
\********************************************************************/
template <>
EnumText EnumUtils<ColorTypes>::ToString(ColorTypes value)
{
switch (value)
{
case BLACK: return { "BLACK", "BLACK", "" };
case RED: return { "RED", "RED", "" };
case GREEN: return { "GREEN", "GREEN", "" };
case BROWN: return { "BROWN", "BROWN", "" };
case BLUE: return { "BLUE", "BLUE", "" };
case MAGENTA: return { "MAGENTA", "MAGENTA", "" };
case CYAN: return { "CYAN", "CYAN", "" };
case GREY: return { "GREY", "GREY", "" };
case YELLOW: return { "YELLOW", "YELLOW", "" };
case LRED: return { "LRED", "LRED", "" };
case LGREEN: return { "LGREEN", "LGREEN", "" };
case LBLUE: return { "LBLUE", "LBLUE", "" };
case LMAGENTA: return { "LMAGENTA", "LMAGENTA", "" };
case LCYAN: return { "LCYAN", "LCYAN", "" };
case WHITE: return { "WHITE", "WHITE", "" };
default: throw std::out_of_range("value");
}
}
template <>
size_t EnumUtils<ColorTypes>::Count() { return 15; }
template <>
ColorTypes EnumUtils<ColorTypes>::FromIndex(size_t index)
{
switch (index)
{
case 0: return BLACK;
case 1: return RED;
case 2: return GREEN;
case 3: return BROWN;
case 4: return BLUE;
case 5: return MAGENTA;
case 6: return CYAN;
case 7: return GREY;
case 8: return YELLOW;
case 9: return LRED;
case 10: return LGREEN;
case 11: return LBLUE;
case 12: return LMAGENTA;
case 13: return LCYAN;
case 14: return WHITE;
default: throw std::out_of_range("index");
}
}
template <>
size_t EnumUtils<ColorTypes>::ToIndex(ColorTypes value)
{
switch (value)
{
case BLACK: return 0;
case RED: return 1;
case GREEN: return 2;
case BROWN: return 3;
case BLUE: return 4;
case MAGENTA: return 5;
case CYAN: return 6;
case GREY: return 7;
case YELLOW: return 8;
case LRED: return 9;
case LGREEN: return 10;
case LBLUE: return 11;
case LMAGENTA: return 12;
case LCYAN: return 13;
case WHITE: return 14;
default: throw std::out_of_range("value");
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "LogCommon.h"
#include "Define.h"
#include "SmartEnum.h"
#include <stdexcept>
namespace acore::Impl::EnumUtilsImpl
{
/************************************************************\
|* data for enum 'LogLevel' in 'LogCommon.h' auto-generated *|
\************************************************************/
template <>
EnumText EnumUtils<LogLevel>::ToString(LogLevel value)
{
switch (value)
{
case LOG_LEVEL_DISABLED: return { "LOG_LEVEL_DISABLED", "LOG_LEVEL_DISABLED", "" };
case LOG_LEVEL_FATAL: return { "LOG_LEVEL_FATAL", "LOG_LEVEL_FATAL", "" };
case LOG_LEVEL_ERROR: return { "LOG_LEVEL_ERROR", "LOG_LEVEL_ERROR", "" };
case LOG_LEVEL_WARN: return { "LOG_LEVEL_WARN", "LOG_LEVEL_WARN", "" };
case LOG_LEVEL_INFO: return { "LOG_LEVEL_INFO", "LOG_LEVEL_INFO", "" };
case LOG_LEVEL_DEBUG: return { "LOG_LEVEL_DEBUG", "LOG_LEVEL_DEBUG", "" };
case LOG_LEVEL_TRACE: return { "LOG_LEVEL_TRACE", "LOG_LEVEL_TRACE", "" };
default: throw std::out_of_range("value");
}
}
template <>
size_t EnumUtils<LogLevel>::Count() { return 7; }
template <>
LogLevel EnumUtils<LogLevel>::FromIndex(size_t index)
{
switch (index)
{
case 0: return LOG_LEVEL_DISABLED;
case 1: return LOG_LEVEL_FATAL;
case 2: return LOG_LEVEL_ERROR;
case 3: return LOG_LEVEL_WARN;
case 4: return LOG_LEVEL_INFO;
case 5: return LOG_LEVEL_DEBUG;
case 6: return LOG_LEVEL_TRACE;
default: throw std::out_of_range("index");
}
}
template <>
size_t EnumUtils<LogLevel>::ToIndex(LogLevel value)
{
switch (value)
{
case LOG_LEVEL_DISABLED: return 0;
case LOG_LEVEL_FATAL: return 1;
case LOG_LEVEL_ERROR: return 2;
case LOG_LEVEL_WARN: return 3;
case LOG_LEVEL_INFO: return 4;
case LOG_LEVEL_DEBUG: return 5;
case LOG_LEVEL_TRACE: return 6;
default: throw std::out_of_range("value");
}
}
/****************************************************************\
|* data for enum 'AppenderType' in 'LogCommon.h' auto-generated *|
\****************************************************************/
template <>
EnumText EnumUtils<AppenderType>::ToString(AppenderType value)
{
switch (value)
{
case APPENDER_NONE: return { "APPENDER_NONE", "APPENDER_NONE", "" };
case APPENDER_CONSOLE: return { "APPENDER_CONSOLE", "APPENDER_CONSOLE", "" };
case APPENDER_FILE: return { "APPENDER_FILE", "APPENDER_FILE", "" };
case APPENDER_DB: return { "APPENDER_DB", "APPENDER_DB", "" };
default: throw std::out_of_range("value");
}
}
template <>
size_t EnumUtils<AppenderType>::Count() { return 4; }
template <>
AppenderType EnumUtils<AppenderType>::FromIndex(size_t index)
{
switch (index)
{
case 0: return APPENDER_NONE;
case 1: return APPENDER_CONSOLE;
case 2: return APPENDER_FILE;
case 3: return APPENDER_DB;
default: throw std::out_of_range("index");
}
}
template <>
size_t EnumUtils<AppenderType>::ToIndex(AppenderType value)
{
switch (value)
{
case APPENDER_NONE: return 0;
case APPENDER_CONSOLE: return 1;
case APPENDER_FILE: return 2;
case APPENDER_DB: return 3;
default: throw std::out_of_range("value");
}
}
}

View File

@@ -65,5 +65,5 @@ void ByteBuffer::hexlike(bool outString) const
}
o << " ";
sLog->outString("%s", o.str().c_str());
LOG_INFO("server", "%s", o.str().c_str());
}

View File

@@ -242,7 +242,7 @@ bool WinServiceRun()
if (!StartServiceCtrlDispatcher(serviceTable))
{
sLog->outError("StartService Failed. Error [%u]", ::GetLastError());
LOG_ERROR("server", "StartService Failed. Error [%u]", ::GetLastError());
return false;
}
return true;

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef IteratorPair_h__
#define IteratorPair_h__
#include "Define.h"
#include <utility>
namespace acore
{
/**
* @class IteratorPair
*
* @brief Utility class to enable range for loop syntax for multimap.equal_range uses
*/
template<class iterator>
class IteratorPair
{
public:
constexpr IteratorPair() : _iterators() { }
constexpr IteratorPair(iterator first, iterator second) : _iterators(first, second) { }
constexpr IteratorPair(std::pair<iterator, iterator> iterators) : _iterators(iterators) { }
constexpr iterator begin() const { return _iterators.first; }
constexpr iterator end() const { return _iterators.second; }
private:
std::pair<iterator, iterator> _iterators;
};
namespace Containers
{
template<class M>
inline auto MapEqualRange(M& map, typename M::key_type const& key) -> IteratorPair<decltype(map.begin())>
{
return { map.equal_range(key) };
}
}
//! namespace Containers
}
//! namespace acore
#endif // IteratorPair_h__

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef TRINITY_SMARTENUM_H
#define TRINITY_SMARTENUM_H
#include "IteratorPair.h"
#include <iterator>
struct EnumText
{
EnumText(char const* c, char const* t, char const* d) : Constant(c), Title(t), Description(d) { }
// Enum constant of the value
char const* const Constant;
// Human-readable title of the value
char const* const Title;
// Human-readable description of the value
char const* const Description;
};
namespace acore::Impl::EnumUtilsImpl
{
template <typename Enum>
struct EnumUtils
{
static size_t Count();
static EnumText ToString(Enum value);
static Enum FromIndex(size_t index);
static size_t ToIndex(Enum index);
};
}
class EnumUtils
{
public:
template <typename Enum>
static size_t Count() { return acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::Count(); }
template <typename Enum>
static EnumText ToString(Enum value) { return acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToString(value); }
template <typename Enum>
static Enum FromIndex(size_t index) { return acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::FromIndex(index); }
template <typename Enum>
static uint32 ToIndex(Enum value) { return acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);}
template<typename Enum>
static bool IsValid(Enum value)
{
try
{
acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);
return true;
} catch (...)
{
return false;
}
}
template<typename Enum>
static bool IsValid(std::underlying_type_t<Enum> value) { return IsValid(static_cast<Enum>(value)); }
template <typename Enum>
class Iterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = Enum;
using pointer = Enum*;
using reference = Enum&;
using difference_type = std::ptrdiff_t;
Iterator() : _index(EnumUtils::Count<Enum>()) {}
explicit Iterator(size_t index) : _index(index) { }
bool operator==(const Iterator& other) const { return other._index == _index; }
bool operator!=(const Iterator& other) const { return !operator==(other); }
difference_type operator-(Iterator const& other) const { return _index - other._index; }
bool operator<(const Iterator& other) const { return _index < other._index; }
bool operator<=(const Iterator& other) const { return _index <= other._index; }
bool operator>(const Iterator& other) const { return _index > other._index; }
bool operator>=(const Iterator& other) const { return _index >= other._index; }
value_type operator[](difference_type d) const { return FromIndex<Enum>(_index + d); }
value_type operator*() const { return operator[](0); }
Iterator& operator+=(difference_type d) { _index += d; return *this; }
Iterator& operator++() { return operator+=(1); }
Iterator operator++(int) { Iterator i = *this; operator++(); return i; }
Iterator operator+(difference_type d) const { Iterator i = *this; i += d; return i; }
Iterator& operator-=(difference_type d) { _index -= d; return *this; }
Iterator& operator--() { return operator-=(1); }
Iterator operator--(int) { Iterator i = *this; operator--(); return i; }
Iterator operator-(difference_type d) const { Iterator i = *this; i -= d; return i; }
private:
difference_type _index;
};
template <typename Enum>
static Iterator<Enum> Begin() { return Iterator<Enum>(0); }
template <typename Enum>
static Iterator<Enum> End() { return Iterator<Enum>(); }
template <typename Enum>
static acore::IteratorPair<Iterator<Enum>> Iterate() { return { Begin<Enum>(), End<Enum>() }; }
template <typename Enum>
static char const* ToConstant(Enum value) { return ToString(value).Constant; }
template <typename Enum>
static char const* ToTitle(Enum value) { return ToString(value).Title; }
template <typename Enum>
static char const* ToDescription(Enum value) { return ToString(value).Description; }
};
#endif

View File

@@ -13,7 +13,6 @@
#include <vector>
#include <queue>
#include <memory>
#include <optional>
#include <set>
#include <utility>
#include "Util.h"

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
*/
#include "Tokenize.h"
std::vector<std::string_view> acore::Tokenize(std::string_view str, char sep, bool keepEmpty)
{
std::vector<std::string_view> tokens;
size_t start = 0;
for (size_t end = str.find(sep); end != std::string_view::npos; end = str.find(sep, start))
{
if (keepEmpty || (start < end))
tokens.push_back(str.substr(start, end - start));
start = end + 1;
}
if (keepEmpty || (start < str.length()))
tokens.push_back(str.substr(start));
return tokens;
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
*/
#ifndef _ACORE_TOKENIZE_H_
#define _ACORE_TOKENIZE_H_
#include "Common.h"
#include <string_view>
namespace acore
{
std::vector<std::string_view> Tokenize(std::string_view str, char sep, bool keepEmpty);
/* this would return string_view into temporary otherwise */
std::vector<std::string_view> Tokenize(std::string&&, char, bool) = delete;
std::vector<std::string_view> Tokenize(std::string const&&, char, bool) = delete;
/* the delete overload means we need to make this explicit */
inline std::vector<std::string_view> Tokenize(char const* str, char sep, bool keepEmpty) { return Tokenize(std::string_view(str ? str : ""), sep, keepEmpty); }
}
#endif // _ACORE_TOKENIZE_H_