add debug command to track statistics and debug client connections

The `debug` command shows info useful to develpers of the client and
server
This commit is contained in:
Lion Kortlepel
2022-10-26 14:15:56 +02:00
parent 692129cb81
commit c717037895
3 changed files with 96 additions and 0 deletions
+2
View File
@@ -36,6 +36,7 @@ private:
void Command_Status(const std::string& cmd, const std::vector<std::string>& args); void Command_Status(const std::string& cmd, const std::vector<std::string>& args);
void Command_Settings(const std::string& cmd, const std::vector<std::string>& args); void Command_Settings(const std::string& cmd, const std::vector<std::string>& args);
void Command_Clear(const std::string&, const std::vector<std::string>& args); void Command_Clear(const std::string&, const std::vector<std::string>& args);
void Command_Debug(const std::string&, const std::vector<std::string>& args);
void Command_Say(const std::string& FullCommand); void Command_Say(const std::string& FullCommand);
bool EnsureArgsCount(const std::vector<std::string>& args, size_t n); bool EnsureArgsCount(const std::vector<std::string>& args, size_t n);
@@ -52,6 +53,7 @@ private:
{ "status", [this](const auto& a, const auto& b) { Command_Status(a, b); } }, { "status", [this](const auto& a, const auto& b) { Command_Status(a, b); } },
{ "settings", [this](const auto& a, const auto& b) { Command_Settings(a, b); } }, { "settings", [this](const auto& a, const auto& b) { Command_Settings(a, b); } },
{ "clear", [this](const auto& a, const auto& b) { Command_Clear(a, b); } }, { "clear", [this](const auto& a, const auto& b) { Command_Clear(a, b); } },
{ "debug", [this](const auto& a, const auto& b) { Command_Debug(a, b); } },
{ "say", [this](const auto&, const auto&) { Command_Say(""); } }, // shouldn't actually be called { "say", [this](const auto&, const auto&) { Command_Say(""); } }, // shouldn't actually be called
}; };
+93
View File
@@ -9,6 +9,10 @@
#include <boost/spirit/home/qi/directive/lexeme.hpp> #include <boost/spirit/home/qi/directive/lexeme.hpp>
#include <boost/spirit/home/qi/parse.hpp> #include <boost/spirit/home/qi/parse.hpp>
#include <bits/chrono.h>
#include <boost/asio/ip/address.hpp>
#include <fmt/chrono.h>
#include <chrono>
#include <ctime> #include <ctime>
#include <sstream> #include <sstream>
@@ -244,6 +248,7 @@ void TConsole::Command_Help(const std::string&, const std::vector<std::string>&
lua [state id] switches to lua, optionally into a specific state id's lua lua [state id] switches to lua, optionally into a specific state id's lua
settings [command] sets or gets settings for the server, run `settings help` for more info settings [command] sets or gets settings for the server, run `settings help` for more info
status how the server is doing and what it's up to status how the server is doing and what it's up to
debug internal error and debug state of the server (for development)
clear clears the console window)"; clear clears the console window)";
Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString));
} }
@@ -264,6 +269,94 @@ void TConsole::Command_Clear(const std::string&, const std::vector<std::string>&
mCommandline.write("\x1b[;H\x1b[2J"); mCommandline.write("\x1b[;H\x1b[2J");
} }
void TConsole::Command_Debug(const std::string&, const std::vector<std::string>& args) {
if (!EnsureArgsCount(args, 0)) {
return;
}
Application::Console().WriteRaw(fmt::format(R"(Debug info (for developers):
UDP:
Malformed packets: {}
Invalid packets: {})",
Application::MalformedUdpPackets,
Application::InvalidUdpPackets));
Application::Console().WriteRaw(fmt::format(R"( Clients:
Note: All data/second rates are an average across the total time since
connection and do not necessarily reflect the *current* data rate
of that client.
)"));
mLuaEngine->Server().ForEachClient([&](std::weak_ptr<TClient> Client) -> bool {
if (!Client.expired()) {
auto Locked = Client.lock();
std::string State = "";
if (Locked->IsSyncing()) {
State += "Syncing";
}
if (Locked->IsSynced()) {
if (!State.empty()) {
State += " & ";
}
State += "Synced";
}
if (Locked->IsConnected()) {
if (!State.empty()) {
State += " & ";
}
State += "Connected";
}
if (Locked->IsDisconnected()) {
if (!State.empty()) {
State += " & ";
}
State += "Disconnected";
}
auto Now = std::chrono::high_resolution_clock::now();
auto Seconds = std::chrono::duration_cast<std::chrono::seconds>(Now - Locked->ConnectionTime);
std::string ConnectedSince = fmt::format("{:%Y/%m/%d %H:%M:%S}, {:%H:%M:%S} ago ({} seconds)",
fmt::localtime(std::chrono::high_resolution_clock::to_time_t(Locked->ConnectionTime)),
Seconds,
Seconds.count());
Application::Console().WriteRaw(fmt::format(
R"( {} ('{}'):
Roles: {}
Cars: {}
Is guest: {}
Has unicycle: {}
TCP: {} (on port {})
UDP: {} (on port {})
Sent via TCP: {}
Received via TCP: {}
Sent via UDP: {} ({} packets)
Received via UDP: {} ({} packets)
Status: {}
Queued packets: {}
Latest packet: {}s ago
Connected since: {}
Average send: {}/s
Average receive: {}/s)",
Locked->GetID(), Locked->GetName(),
Locked->GetRoles(),
Locked->GetCarCount(),
Locked->IsGuest() ? "yes" : "no",
Locked->GetUnicycleID() == -1 ? "no" : "yes",
Locked->GetTCPSock().remote_endpoint().address() == ip::address::from_string("0.0.0.0") ? "not connected" : "connected", Locked->GetTCPSock().remote_endpoint().port(),
Locked->GetUDPAddr().address() == ip::address::from_string("0.0.0.0") ? "NOT connected" : "connected", Locked->GetUDPAddr().port(),
ToHumanReadableSize(Locked->TcpSent),
ToHumanReadableSize(Locked->TcpReceived),
ToHumanReadableSize(Locked->UdpSent), Locked->UdpPacketsSent,
ToHumanReadableSize(Locked->UdpReceived), Locked->UdpPacketsReceived,
State.empty() ? "None (likely pre-sync)" : State,
Locked->MissedPacketQueueSize(),
Locked->SecondsSinceLastPing(),
ConnectedSince,
ToHumanReadableSize((Locked->TcpSent + Locked->UdpSent) / Seconds.count()),
ToHumanReadableSize((Locked->TcpReceived + Locked->UdpReceived) / Seconds.count())));
} else {
Application::Console().WriteRaw(fmt::format(R"( <expired client>)"));
}
return true;
});
}
void TConsole::Command_Kick(const std::string&, const std::vector<std::string>& args) { void TConsole::Command_Kick(const std::string&, const std::vector<std::string>& args) {
if (!EnsureArgsCount(args, 1, size_t(-1))) { if (!EnsureArgsCount(args, 1, size_t(-1))) {
return; return;
+1
View File
@@ -9,6 +9,7 @@
#include <array> #include <array>
#include <boost/asio/ip/address.hpp> #include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/address_v4.hpp> #include <boost/asio/ip/address_v4.hpp>
#include <chrono>
#include <cstring> #include <cstring>
std::vector<uint8_t> StringToVector(const std::string& Str) { std::vector<uint8_t> StringToVector(const std::string& Str) {