mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-01 15:26:59 +00:00
Sentry: add multiple more logging mechanisms, add [CHAT]
This commit is contained in:
parent
5330013dc3
commit
8fada3ac04
@ -1,6 +1,7 @@
|
||||
# v2.3.0
|
||||
|
||||
- ADDED logging of errors to the backend
|
||||
- ADDED logging of various errors, crashes and exceptions to the backend
|
||||
- ADDED `[CHAT]` messages to server console
|
||||
|
||||
# v2.2.0
|
||||
|
||||
|
@ -126,6 +126,8 @@ void RegisterThread(const std::string str);
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
void LogChatMessage(const std::string& name, int id, const std::string& msg);
|
||||
|
||||
#define Biggest 30000
|
||||
std::string Comp(std::string Data);
|
||||
std::string DeComp(std::string Compressed);
|
||||
|
@ -59,10 +59,18 @@ inline void _assert([[maybe_unused]] const char* file, [[maybe_unused]] const ch
|
||||
#define AssertNotReachable() _assert(__FILE__, __func__, __LINE__, "reached unreachable code", false)
|
||||
#else
|
||||
// In release build, these macros turn into NOPs. The compiler will optimize these out.
|
||||
#define Assert(x) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define AssertNotReachable() \
|
||||
do { \
|
||||
} while (false)
|
||||
#define Assert(cond) \
|
||||
do { \
|
||||
if (!result) { \
|
||||
Sentry.LogAssert(#cond, _file_basename, _line, __func__); \
|
||||
}
|
||||
}
|
||||
while (false)
|
||||
#define AssertNotReachable() \
|
||||
do { \
|
||||
if (!result) { \
|
||||
Sentry.LogAssert("code is unreachable", _file_basename, _line, __func__); \
|
||||
}
|
||||
}
|
||||
while (false)
|
||||
#endif // DEBUG
|
||||
|
@ -3,8 +3,9 @@
|
||||
|
||||
#include <sentry.h>
|
||||
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
// TODO possibly use attach_stacktrace
|
||||
|
||||
@ -18,9 +19,9 @@ public:
|
||||
void SetupUser();
|
||||
void Log(sentry_level_t level, const std::string& logger, const std::string& text);
|
||||
void LogError(const std::string& text, const std::string& file, const std::string& line);
|
||||
void SetExtra(const std::string& key, const sentry_value_t& value);
|
||||
void SetExtra(const std::string& key, const std::string& value);
|
||||
void SetContext(const std::string& context_name, const std::unordered_map<std::string, std::string>& map);
|
||||
void LogException(const std::exception& e, const std::string& file, const std::string& line);
|
||||
void LogAssert(const std::string& condition_string, const std::string& file, const std::string& line, const std::string& function);
|
||||
void AddErrorBreadcrumb(const std::string& msg, const std::string& file, const std::string& line);
|
||||
// cleared when Logged
|
||||
void SetTransaction(const std::string& id);
|
||||
@ -29,6 +30,7 @@ public:
|
||||
private:
|
||||
bool mValid { true };
|
||||
std::mutex mMutex;
|
||||
sentry_value_t mContext;
|
||||
};
|
||||
|
||||
#endif // SENTRY_H
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <zlib.h>
|
||||
|
||||
@ -86,3 +87,15 @@ std::string ThreadName() {
|
||||
void RegisterThread(const std::string str) {
|
||||
threadNameMap[std::this_thread::get_id()] = str;
|
||||
}
|
||||
|
||||
void LogChatMessage(const std::string& name, int id, const std::string& msg) {
|
||||
std::stringstream ss;
|
||||
ss << "[CHAT] ";
|
||||
if (id != -1) {
|
||||
ss << "(" << id << ") <" << name << ">";
|
||||
} else {
|
||||
ss << name << "";
|
||||
}
|
||||
ss << msg;
|
||||
Application::Console().Write(ss.str());
|
||||
}
|
||||
|
@ -124,15 +124,16 @@ std::string Http::POST(const std::string& host, const std::string& target, const
|
||||
|
||||
http::read(stream, buffer, response);
|
||||
|
||||
Sentry.SetExtra("reponse-code", std::to_string(response.result_int()));
|
||||
|
||||
std::unordered_map<std::string, std::string> response_data;
|
||||
response_data["reponse-code"] = std::to_string(response.result_int());
|
||||
for (const auto& header : response.base()) {
|
||||
// need to do explicit casts to convert string_view to string
|
||||
// since string_view may not be null-terminated (and in fact isn't, here)
|
||||
std::string KeyString(header.name_string());
|
||||
std::string ValueString(header.value());
|
||||
Sentry.SetExtra(KeyString, ValueString);
|
||||
response_data[KeyString] = ValueString;
|
||||
}
|
||||
Sentry.SetContext("https-post-data", response_data);
|
||||
|
||||
std::stringstream result;
|
||||
result << response;
|
||||
|
@ -43,8 +43,9 @@ void THeartbeatThread::operator()() {
|
||||
if (T.size() > std::string("YOU_SHALL_NOT_PASS").size()
|
||||
&& Application::Settings.Key.size() == 36) {
|
||||
auto Lock = Sentry.CreateExclusiveContext();
|
||||
Sentry.SetExtra("response-body", T);
|
||||
Sentry.SetExtra("request-body", Body);
|
||||
Sentry.SetContext("heartbeat",
|
||||
{ { "response-body", T },
|
||||
{ "request-body", Body } });
|
||||
Sentry.SetTransaction(transaction);
|
||||
Sentry.Log(SENTRY_LEVEL_ERROR, "default", "wrong backend response format");
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ bool CheckLua(lua_State* L, int r) {
|
||||
warn(a + " | " + msg);
|
||||
return false;
|
||||
}
|
||||
// What the fuck, what do we do?!
|
||||
// This should never happen since it's not directly called from "userspace" Lua.
|
||||
AssertNotReachable();
|
||||
}
|
||||
return true;
|
||||
@ -127,7 +127,10 @@ bool CheckLua(lua_State* L, int r) {
|
||||
int lua_RegisterEvent(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
auto MaybeScript = Engine().GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
if (!MaybeScript.has_value()) {
|
||||
error("RegisterEvent: There is no script associated with this lua_State.");
|
||||
return 0;
|
||||
}
|
||||
TLuaFile& Script = MaybeScript.value();
|
||||
if (Args == 2 && lua_isstring(L, 1) && lua_isstring(L, 2)) {
|
||||
Script.RegisterEvent(lua_tostring(L, 1), lua_tostring(L, 2));
|
||||
@ -139,7 +142,10 @@ int lua_RegisterEvent(lua_State* L) {
|
||||
int lua_TriggerEventL(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
auto MaybeScript = Engine().GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
if (!MaybeScript.has_value()) {
|
||||
error("TriggerEvent: There is no script associated with this lua_State.");
|
||||
return 0;
|
||||
}
|
||||
TLuaFile& Script = MaybeScript.value();
|
||||
if (Args > 0) {
|
||||
if (lua_isstring(L, 1)) {
|
||||
@ -155,7 +161,10 @@ int lua_TriggerEventL(lua_State* L) {
|
||||
int lua_TriggerEventG(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
auto MaybeScript = Engine().GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
if (!MaybeScript.has_value()) {
|
||||
error("TriggerGlobalEvent: There is no script associated with this lua_State.");
|
||||
return 0;
|
||||
}
|
||||
TLuaFile& Script = MaybeScript.value();
|
||||
if (Args > 0) {
|
||||
if (lua_isstring(L, 1)) {
|
||||
@ -194,8 +203,11 @@ void CallAsync(TLuaFile* lua, const std::string& Func, int U) {
|
||||
|
||||
int lua_StopThread(lua_State* L) {
|
||||
auto MaybeScript = Engine().GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
// ugly, but whatever, this is safe as fuck
|
||||
if (!MaybeScript.has_value()) {
|
||||
error("StopThread: There is no script associated with this lua_State.");
|
||||
return 0;
|
||||
}
|
||||
// ugly, but whatever, this is very safe
|
||||
MaybeScript.value().get().SetStopThread(true);
|
||||
return 0;
|
||||
}
|
||||
@ -209,7 +221,10 @@ int lua_CreateThread(lua_State* L) {
|
||||
int U = int(lua_tointeger(L, 2));
|
||||
if (U > 0 && U < 501) {
|
||||
auto MaybeScript = Engine().GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
if (!MaybeScript.has_value()) {
|
||||
error("CreateThread: There is no script associated with this lua_State.");
|
||||
return 0;
|
||||
}
|
||||
TLuaFile& Script = MaybeScript.value();
|
||||
std::thread t1(CallAsync, &Script, STR, U);
|
||||
t1.detach();
|
||||
@ -397,7 +412,9 @@ int lua_sendChat(lua_State* L) {
|
||||
if (lua_isstring(L, 2)) {
|
||||
int ID = int(lua_tointeger(L, 1));
|
||||
if (ID == -1) {
|
||||
std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2));
|
||||
auto msg = std::string(lua_tostring(L, 2));
|
||||
LogChatMessage("<Server> (to everyone) ", -1, msg);
|
||||
std::string Packet = "C:Server: " + msg;
|
||||
Engine().Network().SendToAll(nullptr, Packet, true, true);
|
||||
} else {
|
||||
auto MaybeClient = GetClient(Engine().Server(), ID);
|
||||
@ -405,7 +422,9 @@ int lua_sendChat(lua_State* L) {
|
||||
auto c = MaybeClient.value().lock();
|
||||
if (!c->IsSynced())
|
||||
return 0;
|
||||
std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2));
|
||||
auto msg = std::string(lua_tostring(L, 2));
|
||||
LogChatMessage("<Server> (to \"" + c->GetName() + "\")", -1, msg);
|
||||
std::string Packet = "C:Server: " + msg;
|
||||
Engine().Network().Respond(*c, Packet, true);
|
||||
} else
|
||||
SendError(Engine(), L, ("SendChatMessage invalid argument [1] invalid ID"));
|
||||
|
@ -298,15 +298,17 @@ void TNetwork::Authentication(SOCKET TCPSock) {
|
||||
ClientKick(*Client, "Backend returned invalid auth response format.");
|
||||
error("Backend returned invalid auth response format. This should never happen.");
|
||||
auto Lock = Sentry.CreateExclusiveContext();
|
||||
Sentry.SetExtra("response-body", Rc);
|
||||
Sentry.SetExtra("key", RequestString);
|
||||
Sentry.SetContext("auth",
|
||||
{ { "response-body", Rc },
|
||||
{ "key", RequestString } });
|
||||
Sentry.SetTransaction(Application::GetBackendUrlForAuth() + Target);
|
||||
Sentry.Log(SENTRY_LEVEL_ERROR, "default", "auth: wrong backend response format");
|
||||
return;
|
||||
} else if (Rc == "0") {
|
||||
auto Lock = Sentry.CreateExclusiveContext();
|
||||
Sentry.SetExtra("response-body", Rc);
|
||||
Sentry.SetExtra("key", RequestString);
|
||||
Sentry.SetContext("auth",
|
||||
{ { "response-body", Rc },
|
||||
{ "key", RequestString } });
|
||||
Sentry.SetTransaction(Application::GetBackendUrlForAuth() + Target);
|
||||
Sentry.Log(SENTRY_LEVEL_INFO, "default", "backend returned 0 instead of json");
|
||||
}
|
||||
|
@ -49,18 +49,20 @@ void TSentry::LogError(const std::string& text, const std::string& file, const s
|
||||
Log(SENTRY_LEVEL_ERROR, "default", file + ": " + text);
|
||||
}
|
||||
|
||||
void TSentry::SetExtra(const std::string& key, const sentry_value_t& value) {
|
||||
void TSentry::SetContext(const std::string& context_name, const std::unordered_map<std::string, std::string>& map) {
|
||||
if (!mValid) {
|
||||
return;
|
||||
}
|
||||
sentry_set_extra(key.c_str(), value);
|
||||
}
|
||||
|
||||
void TSentry::SetExtra(const std::string& key, const std::string& value) {
|
||||
if (!mValid) {
|
||||
return;
|
||||
mContext = sentry_value_new_object();
|
||||
for (const auto& pair : map) {
|
||||
std::string key = pair.first;
|
||||
if (key == "type") {
|
||||
// `type` is reserved
|
||||
key = "_type";
|
||||
}
|
||||
sentry_value_set_by_key(mContext, key.c_str(), sentry_value_new_string(pair.second.c_str()));
|
||||
}
|
||||
SetExtra(key.c_str(), sentry_value_new_string(value.c_str()));
|
||||
sentry_set_context(context_name.c_str(), mContext);
|
||||
}
|
||||
|
||||
void TSentry::LogException(const std::exception& e, const std::string& file, const std::string& line) {
|
||||
@ -68,7 +70,17 @@ void TSentry::LogException(const std::exception& e, const std::string& file, con
|
||||
return;
|
||||
}
|
||||
SetTransaction(file + ":" + line);
|
||||
Log(SENTRY_LEVEL_ERROR, "exceptions", std::string(e.what()) + " @ " + file + ":" + line);
|
||||
Log(SENTRY_LEVEL_FATAL, "exceptions", std::string(e.what()) + " @ " + file + ":" + line);
|
||||
}
|
||||
|
||||
void TSentry::LogAssert(const std::string& condition_string, const std::string& file, const std::string& line, const std::string& function) {
|
||||
if (!mValid) {
|
||||
return;
|
||||
}
|
||||
SetTransaction(file + ":" + line + ":" + function);
|
||||
std::stringstream ss;
|
||||
ss << "\"" << condition_string << "\" failed @ " << file << ":" << line;
|
||||
Log(SENTRY_LEVEL_FATAL, "asserts", ss.str());
|
||||
}
|
||||
|
||||
void TSentry::AddErrorBreadcrumb(const std::string& msg, const std::string& file, const std::string& line) {
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <any>
|
||||
#include <sstream>
|
||||
|
||||
#undef GetObject //Fixes Windows
|
||||
#undef GetObject // Fixes Windows
|
||||
|
||||
#include "Json.h"
|
||||
|
||||
@ -126,6 +126,7 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::string Pac
|
||||
if (Packet.length() < 4 || Packet.find(':', 3) == std::string::npos)
|
||||
break;
|
||||
Res = TriggerLuaEvent("onChatMessage", false, nullptr, std::make_unique<TLuaArg>(TLuaArg { { LockedClient->GetID(), LockedClient->GetName(), Packet.substr(Packet.find(':', 3) + 1) } }), true);
|
||||
LogChatMessage(LockedClient->GetName(), LockedClient->GetID(), Packet.substr(Packet.find(':', 3) + 1)); // FIXME: this needs to be adjusted once lua is merged
|
||||
if (std::any_cast<int>(Res))
|
||||
break;
|
||||
Network.SendToAll(nullptr, Packet, true, true);
|
||||
@ -324,9 +325,10 @@ void TServer::Apply(TClient& c, int VID, const std::string& pckt) {
|
||||
if (VD.empty()) {
|
||||
error("Tried to apply change to vehicle that does not exist");
|
||||
auto Lock = Sentry.CreateExclusiveContext();
|
||||
Sentry.SetExtra("packet", Packet);
|
||||
Sentry.SetExtra("vehicle-id", std::to_string(VID));
|
||||
Sentry.SetExtra("client-car-count", std::to_string(c.GetCarCount()));
|
||||
Sentry.SetContext("vehicle-change",
|
||||
{ { "packet", Packet },
|
||||
{ "vehicle-id", std::to_string(VID) },
|
||||
{ "client-car-count", std::to_string(c.GetCarCount()) } });
|
||||
Sentry.LogError("attempt to apply change to nonexistent vehicle", _file_basename, _line);
|
||||
return;
|
||||
}
|
||||
@ -335,7 +337,8 @@ void TServer::Apply(TClient& c, int VID, const std::string& pckt) {
|
||||
FoundPos = VD.find('{');
|
||||
if (FoundPos == std::string::npos) {
|
||||
auto Lock = Sentry.CreateExclusiveContext();
|
||||
Sentry.SetExtra("packet", VD);
|
||||
Sentry.SetContext("vehicle-change-packet",
|
||||
{ { "packet", VD } });
|
||||
Sentry.LogError("malformed packet", _file_basename, _line);
|
||||
error("Malformed packet received, no '{' found");
|
||||
return;
|
||||
|
Loading…
x
Reference in New Issue
Block a user