DragonNest/Server/ServiceManagerEx/ServerReporter.cpp
Cussrro 47f7895977 Revert "修复编码问题"
This reverts commit 9e69c01767.
2024-12-21 10:04:04 +08:00

560 lines
No EOL
14 KiB
C++

#include "StdAfx.h"
#include "ServerReporter.h"
#include "LogBuilder.h"
#include "DataManager.h"
#include "ServiceManager.h"
namespace ServerReport
{
// CReportView
CReportView::CReportView(const wstring& d)
: day(d)
{
}
CReportView::~CReportView()
{
for each (View* pView in views)
{
delete pView;
}
}
void CReportView::AddView(View* pView)
{
views.push_back(pView);
}
const wstring& CReportView::GetDay() const
{
return day;
}
const vector<View*>& CReportView::GetViews() const
{
return views;
}
// CServerReporter
CServerReporter::CServerReporter(void)
{
}
CServerReporter::~CServerReporter(void)
{
}
void CServerReporter::Report(size_t days, bool detail, OUT wstring& report)
{
vector<CReportView*> temp;
Report(days, detail, temp);
wstringstream ss;
for each (CReportView* pReport in temp)
{
ss << L"<" << pReport->GetDay() << L">" << L"\r\n\r\n";
for each (View* pView in pReport->GetViews())
{
ss << pView->overview.str();
ss << pView->detailview.str();
}
ss << L"\r\n\r\n";
delete pReport;
}
report = ss.str();
}
void CServerReporter::Report(size_t days, bool detail, OUT vector<CReportView*>& report)
{
map<wstring, wstring> times;
GetReportTime(days, times);
is_dbdelay = false;
map<wstring, wstring>::const_reverse_iterator it = times.rbegin();
for (; it != times.rend(); ++it)
{
CReportView* pReport = BuildReport(it->first, it->second, detail);
if (!pReport)
continue;
report.push_back(pReport);
}
}
CReportView* CServerReporter::BuildReport(const wstring& day, const wstring& filename, bool detail) const
{
CReportView* pReport = new CReportView(day);
View* pExceptionView = new View();
View* pDBSystemErrorView = new View();
View* pDBErrorView = new View();
View* pDBDelayView = new View();
View* pGameDelayView = new View();
View* pVillageDelayView = new View();
try
{
ParseExceptionLog(filename, detail, pExceptionView->overview, pExceptionView->detailview);
ParseDBSystemErrorLog(filename, detail, pDBSystemErrorView->overview, pDBSystemErrorView->detailview);
ParseDBErrorLog(filename, detail, pDBErrorView->overview, pDBErrorView->detailview);
ParseDBDelayLog(filename, detail, pDBDelayView->overview, pDBDelayView->detailview, (bool)is_dbdelay);
ParseGameDelayLog(filename, detail, pGameDelayView->overview, pGameDelayView->detailview);
ParseVillageDelayLog(filename, detail, pVillageDelayView->overview, pVillageDelayView->detailview);
}
catch (...)
{
delete pExceptionView;
delete pDBSystemErrorView;
delete pDBErrorView;
delete pDBDelayView;
delete pGameDelayView;
delete pVillageDelayView;
delete pReport;
g_Log.Log(LogType::_FILELOG, L"BuildExceptionReport failed. [day:%s]\n", day.c_str());
return NULL;
}
pReport->AddView(pExceptionView);
pReport->AddView(pDBSystemErrorView);
pReport->AddView(pDBErrorView);
pReport->AddView(pDBDelayView);
pReport->AddView(pGameDelayView);
pReport->AddView(pVillageDelayView);
return pReport;
}
void CServerReporter::ParseExceptionLog(const wstring& filename, bool detail, OUT wstringstream& overview, OUT wstringstream& detailview) const
{
static const wstring exceptionLog(L"log\\ExceptionReport_");
CLogBuilder builder;
log_error error = builder.Load(exceptionLog + filename);
if (error == error_size_overflow)
{
overview << L"ExceptionReport_" << filename << L" file is too large.\r\n";
return;
}
map<wstring, VECTOR_EXCEPTION*> terminated;
map<wstring, VECTOR_EXCEPTION*> sessionDump;
const vector<LogInfo*>& logs = builder.GetLogs();
for each (const LogInfo* pLog in logs)
{
//terminated
size_t pos = pLog->text.find(L"Terminated");
if (pos != wstring::npos)
{
pos = pLog->text.find(L"[SID:");
if (pos == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_t1) %s\n", pLog->text.c_str());
continue;
}
size_t pos_end = pLog->text.find(L"]", pos);
if (pos_end == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_t2) %s\n", pLog->text.c_str());
continue;
}
wstring strId = pLog->text.substr(pos + 5, pos_end - pos - 5);
int sid = _wtoi(strId.c_str());
const TServerExcuteData* pExecuteData = g_pServiceManager->GetServerExecuteData(sid);
if (!pExecuteData)
{
g_Log.Log(LogType::_ERROR, L"Server data not found. SID[%d]", sid);
continue;
}
const TNetLauncher* pNetLauncherData = g_pServiceManager->GetLauncherInfo(pExecuteData->nAssignedLauncherID);
if (!pNetLauncherData)
{
g_Log.Log(LogType::_ERROR, L"NetLauncher data not found. NID[%d]\n", pExecuteData->nAssignedLauncherID);
continue;
}
VECTOR_EXCEPTION* list = NULL;
map<wstring, VECTOR_EXCEPTION*>::iterator it = terminated.find(pExecuteData->wszType);
if (it == terminated.end())
{
list = new VECTOR_EXCEPTION;
terminated.insert(make_pair(pExecuteData->wszType, list));
}
else
{
list = it->second;
}
ExceptionLog log;
log.time = pLog->date;
if (log.time.size() >= 11)
log.time.substr(11, 8);
log.type = pExecuteData->wszType;
log.sid = strId;
log.ip = pNetLauncherData->szIP;
list->push_back(log);
continue;
}
//session dump
pos = pLog->text.find(L"Exception");
if (pos != wstring::npos)
{
pos = pLog->text.find(L"MID[");
if (pos == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_e1) %s\n", pLog->text.c_str());
continue;
}
size_t pos_end = pLog->text.find(L"]", pos);
if (pos_end == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_e2) %s\n", pLog->text.c_str());
continue;
}
wstring strId = pLog->text.substr(pos + 4, pos_end - pos - 4);
int sid = _wtoi(strId.c_str());
const TServerExcuteData* pExecuteData = g_pServiceManager->GetServerExecuteData(sid);
if (!pExecuteData)
{
g_Log.Log(LogType::_ERROR, L"Server data not found. SID[%d]\n", sid);
continue;
}
const TNetLauncher* pNetLauncherData = g_pServiceManager->GetLauncherInfo(pExecuteData->nAssignedLauncherID);
if (!pNetLauncherData)
{
g_Log.Log(LogType::_ERROR, L"NetLauncher data not found. NID[%d]\n", pExecuteData->nAssignedLauncherID);
continue;
}
VECTOR_EXCEPTION* list = NULL;
map<wstring, VECTOR_EXCEPTION*>::iterator it = sessionDump.find(pExecuteData->wszType);
if (it == sessionDump.end())
{
list = new VECTOR_EXCEPTION;
sessionDump.insert(make_pair(pExecuteData->wszType, list));
}
else
{
list = it->second;
}
ExceptionLog log;
log.time = pLog->date;
if (log.time.size() >= 11)
log.time.substr(11, 8);
log.type = pExecuteData->wszType;
log.sid = strId;
log.ip = pNetLauncherData->szIP;
list->push_back(log);
continue;
}
}
for each (map<wstring, VECTOR_EXCEPTION*>::value_type v in terminated)
{
overview << v.first << L" server full dump. " << v.second->size() << L" times.\r\n";
for each (ExceptionLog log in *(v.second))
{
overview << log.time << L" SID:" << log.sid << L" IP:" << log.ip << "\r\n";
}
overview << L"\r\n";
delete v.second;
}
if (sessionDump.empty())
return;
for each (map<wstring, VECTOR_EXCEPTION*>::value_type v in sessionDump)
{
overview << v.first << L" server session dump. " << v.second->size() << L" times.\r\n";
for each (ExceptionLog log in *(v.second))
{
overview << log.time << L" SID:" << log.sid << L" IP:" << log.ip << L"\r\n";
}
overview << L"\r\n";
delete v.second;
}
detailview << L"\r\n";
}
void CServerReporter::ParseDBDelayLog(const wstring& filename, bool detail, OUT wstringstream& overview, OUT wstringstream& detailview, OUT bool& delay) const
{
static const wstring dbLog(L"log\\DBDelay_");
VECTOR_DBDELAY dbdelay;
CLogBuilder builder;
log_error error = builder.Load(dbLog + filename);
if (error == error_size_overflow)
{
overview << L"DBDelay_" << filename << L" file is too large.\r\n";
return;
}
const vector<LogInfo*>& logs = builder.GetLogs();
for each (const LogInfo* pLog in logs)
{
size_t pos = pLog->text.find(L"[Query Over Time:");
if (pos != wstring::npos)
{
size_t pos_end = pLog->text.find(L"]");
if (pos_end == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_d1) %s\n", pLog->text.c_str());
continue;
}
DBDelayLog log;
log.time = pLog->date;
if (log.time.size() >= 11)
log.time.substr(11, 8);
log.query = pLog->text.substr(pos + 17, pos_end - 17);
pos = pLog->text.find(L"MID:");
if (pos == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_d2) %s\n", pLog->text.c_str());
continue;
}
pos_end = pLog->text.find(L" ", pos);
if (pos_end == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_d3) %s\n", pLog->text.c_str());
continue;
}
log.mid = pLog->text.substr(pos + 4, pos_end - pos - 4);
pos = pLog->text.find(L"ThreadID:");
if (pos == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_d4) %s\n", pLog->text.c_str());
continue;
}
pos_end = pLog->text.find(L" ", pos);
if (pos_end == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_d5) %s\n", pLog->text.c_str());
continue;
}
log.tid = pLog->text.substr(pos + 9, pos_end - pos - 9);
pos = pLog->text.find(L"time=");
if (pos == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_d6) %s\n", pLog->text.c_str());
continue;
}
pos_end = pLog->text.find(L" ", pos);
if (pos_end == wstring::npos)
{
g_Log.Log(LogType::_FILELOG, L"Parse failed.(step_d7) %s\n", pLog->text.c_str());
continue;
}
log.elapsed = pLog->text.substr(pos + 5, pos_end - pos - 5);
dbdelay.push_back(log);
}
}
if (dbdelay.empty())
return;
delay = true;
overview << L"DB delayed. " << dbdelay.size() << L" times.\r\n";
if (detail)
{
for each (DBDelayLog log in dbdelay)
{
detailview << log.time << L" [" << log.query << L"]" << L" MID:" << log.mid << L" TID:" << log.tid << L" elapsed:" << log.elapsed << L" ms\r\n";
}
detailview << L"\r\n";
}
}
void CServerReporter::ParseGameDelayLog(const wstring& filename, bool detail, OUT wstringstream& overview, OUT wstringstream& detailview) const
{
static const wstring gameLog(L"log\\GameDelay_");
CLogBuilder builder;
log_error error = builder.Load(gameLog + filename);
if (error == error_size_overflow)
{
overview << L"GameDelay_" << filename << L" file is too large.\r\n";
return;
}
const vector<LogInfo*>& logs = builder.GetLogs();
if (logs.empty())
return;
overview << L"Game delayed. " << logs.size() << L" times.\r\n";
if (detail)
{
for each (const LogInfo* pLog in logs)
{
detailview << pLog->date << L" " << pLog->text << L"\r\n";
}
detailview << L"\r\n";
}
}
void CServerReporter::ParseVillageDelayLog(const wstring& filename, bool detail, OUT wstringstream& overview, OUT wstringstream& detailview) const
{
static const wstring villageLog(L"log\\VillageDelay_");
CLogBuilder builder;
log_error error = builder.Load(villageLog + filename);
if (error == error_size_overflow)
{
overview << L"VillageDelay_" << filename << L" file is too large.\r\n";
return;
}
const vector<LogInfo*>& logs = builder.GetLogs();
if (logs.empty())
return;
overview << L"Village delayed. " << logs.size() << L" times.\r\n";
if (detail)
{
for each (const LogInfo* pLog in logs)
{
detailview << pLog->date << L" " << pLog->text << L"\r\n";
}
detailview << L"\r\n";
}
}
void CServerReporter::ParseDBErrorLog(const wstring& filename, bool detail, OUT wstringstream& overview, OUT wstringstream& detailview) const
{
static const wstring dbLog(L"log\\DBError_");
CLogBuilder builder;
log_error error = builder.Load(dbLog + filename);
if (error == error_size_overflow)
{
overview << L"DBError_" << filename << L" file is too large.\r\n";
return;
}
const vector<LogInfo*>& logs = builder.GetLogs();
if (logs.empty())
return;
overview << L"DB error. " << logs.size() << L" times.\r\n";
if (detail)
{
for each (const LogInfo* pLog in logs)
{
detailview << pLog->date << L" " << pLog->text << L"\r\n";
}
detailview << L"\r\n";
}
}
void CServerReporter::ParseDBSystemErrorLog(const wstring& filename, bool detail, OUT wstringstream& overview, OUT wstringstream& detailview) const
{
static const wstring dbLog(L"log\\DBSystemError_");
CLogBuilder builder;
log_error error = builder.Load(dbLog + filename);
if (error == error_size_overflow)
{
overview << L"DBSystemError_" << filename << L" file is too large.\r\n";
return;
}
const vector<LogInfo*>& logs = builder.GetLogs();
if (logs.empty())
return;
overview << L"DB system error. " << logs.size() << L" times.\r\n";
if (detail)
{
for each (const LogInfo* pLog in logs)
{
detailview << pLog->date << L" " << pLog->text << L"\r\n";
}
detailview << L"\r\n";
}
}
void CServerReporter::GetReportTime(size_t days, OUT map<wstring, wstring>& times) const
{
CTime time = CTime::GetCurrentTime();
CTimeSpan oneDay(1, 0, 0, 0);
for (size_t i = 0; i < days; ++i)
{
times.insert(make_pair(time.Format(L"%Y-%m-%d ").GetBuffer() + ConvertDayOfWeek(time.GetDayOfWeek()),
time.Format(L"%Y-%m-%d").GetBuffer() + wstring(L".log")));
time = time - oneDay;
}
}
wstring CServerReporter::ConvertDayOfWeek(int weekday) const
{
switch (weekday)
{
case 1:
return L"Sunday";
case 2:
return L"Monday";
case 3:
return L"Tuesday";
case 4:
return L"Wednesday";
case 5:
return L"Thursday";
case 6:
return L"Friday";
case 7:
return L"Saturday";
default:
return L"Unknown";
}
}
}