From c71703789518e5ecb540c838b7503b1073c65915 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 26 Oct 2022 14:15:56 +0200 Subject: [PATCH] add `debug` command to track statistics and debug client connections The `debug` command shows info useful to develpers of the client and server --- include/TConsole.h | 2 + src/TConsole.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++++ src/TNetwork.cpp | 1 + 3 files changed, 96 insertions(+) diff --git a/include/TConsole.h b/include/TConsole.h index 22a3b01..099b490 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -36,6 +36,7 @@ private: void Command_Status(const std::string& cmd, const std::vector& args); void Command_Settings(const std::string& cmd, const std::vector& args); void Command_Clear(const std::string&, const std::vector& args); + void Command_Debug(const std::string&, const std::vector& args); void Command_Say(const std::string& FullCommand); bool EnsureArgsCount(const std::vector& args, size_t n); @@ -52,6 +53,7 @@ private: { "status", [this](const auto& a, const auto& b) { Command_Status(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); } }, + { "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 }; diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 2fe2e28..3b15542 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -9,6 +9,10 @@ #include #include +#include +#include +#include +#include #include #include @@ -244,6 +248,7 @@ void TConsole::Command_Help(const std::string&, const std::vector& 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 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)"; Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); } @@ -264,6 +269,94 @@ void TConsole::Command_Clear(const std::string&, const std::vector& mCommandline.write("\x1b[;H\x1b[2J"); } +void TConsole::Command_Debug(const std::string&, const std::vector& 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 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(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"( )")); + } + return true; + }); +} + void TConsole::Command_Kick(const std::string&, const std::vector& args) { if (!EnsureArgsCount(args, 1, size_t(-1))) { return; diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index d9dc363..d68f334 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include std::vector StringToVector(const std::string& Str) {