diff --git a/TriviaBot/bot/APIHelper.cpp b/TriviaBot/bot/APIHelper.cpp index f4b0703..2e8fd03 100644 --- a/TriviaBot/bot/APIHelper.cpp +++ b/TriviaBot/bot/APIHelper.cpp @@ -1,10 +1,11 @@ -#include "http/HTTPHelper.hpp" +#include "APIHelper.hpp" #include #include #include -#include "APIHelper.hpp" +#include "http/HTTPHelper.hpp" +#include "Logger.hpp" using namespace std::chrono_literals; @@ -25,9 +26,14 @@ void APIHelper::send_message(std::string channel_id, std::string message) { int retries = 0; while (response_code != 200 && retries < 2) { + Logger::write("[send_message] Got non-200 response code, retrying", Logger::LogLevel::Warning); std::this_thread::sleep_for(100ms); // try 3 times. usually enough to prevent 502 bad gateway issues response = http->post_request(url, JSON_CTYPE, data.dump(), &response_code); retries++; } + + if (response_code != 200) { + Logger::write("[send_message] Giving up on sending message", Logger::LogLevel::Warning); + } } \ No newline at end of file diff --git a/TriviaBot/bot/ClientConnection.cpp b/TriviaBot/bot/ClientConnection.cpp index a0a3143..0037dc7 100644 --- a/TriviaBot/bot/ClientConnection.cpp +++ b/TriviaBot/bot/ClientConnection.cpp @@ -4,6 +4,7 @@ #include #include "GatewayHandler.hpp" +#include "Logger.hpp" ClientConnection::ClientConnection() { // Reset the log channels @@ -58,7 +59,7 @@ void ClientConnection::start(std::string uri) { client::connection_ptr con = c.get_connection(uri, ec); if (ec) { // failed to create connection - c.get_alog().write(websocketpp::log::alevel::app, ec.message()); + Logger::write("Failed to create connection: " + ec.message(), Logger::LogLevel::Severe); return; } @@ -69,7 +70,7 @@ void ClientConnection::start(std::string uri) { // Event handlers void ClientConnection::on_socket_init(websocketpp::connection_hdl) { - c.get_alog().write(websocketpp::log::alevel::app, "Socket intialised."); + Logger::write("Socket initialised", Logger::LogLevel::Debug); } context_ptr ClientConnection::on_tls_init(websocketpp::connection_hdl) { @@ -81,8 +82,8 @@ context_ptr ClientConnection::on_tls_init(websocketpp::connection_hdl) { boost::asio::ssl::context::no_sslv3 | boost::asio::ssl::context::single_dh_use); } - catch (std::exception& e) { - std::cout << "Error in context pointer: " << e.what() << std::endl; + catch (std::exception &e) { + Logger::write("[tls] Error in context pointer: " + std::string(e.what()), Logger::LogLevel::Severe); } return ctx; } @@ -91,23 +92,24 @@ void ClientConnection::on_fail(websocketpp::connection_hdl hdl) { client::connection_ptr con = c.get_con_from_hdl(hdl); // Print as much information as possible - c.get_elog().write(websocketpp::log::elevel::warn, - "Fail handler: \n" + + Logger::write("Fail handler: \n" + std::to_string(con->get_state()) + "\n" + std::to_string(con->get_local_close_code()) + "\n" + con->get_local_close_reason() + "\n" + std::to_string(con->get_remote_close_code()) + "\n" + con->get_remote_close_reason() + "\n" + - std::to_string(con->get_ec().value()) + " - " + con->get_ec().message() + "\n"); + std::to_string(con->get_ec().value()) + " - " + con->get_ec().message() + "\n", + Logger::LogLevel::Severe); } void ClientConnection::on_open(websocketpp::connection_hdl hdl) { + Logger::write("Connection opened", Logger::LogLevel::Debug); } void ClientConnection::on_message(websocketpp::connection_hdl hdl, message_ptr message) { if (message->get_opcode() != websocketpp::frame::opcode::text) { // If the message is not text, just print as hex - std::cout << "<< " << websocketpp::utility::to_hex(message->get_payload()) << std::endl; + Logger::write("Non-text message received: " + websocketpp::utility::to_hex(message->get_payload()), Logger::LogLevel::Warning); return; } @@ -117,5 +119,5 @@ void ClientConnection::on_message(websocketpp::connection_hdl hdl, message_ptr m } void ClientConnection::on_close(websocketpp::connection_hdl) { - std::cout << "Closed." << std::endl; + Logger::write("Connection closed", Logger::LogLevel::Info); } \ No newline at end of file diff --git a/TriviaBot/bot/GatewayHandler.cpp b/TriviaBot/bot/GatewayHandler.cpp index 1916ebc..7fef1cf 100644 --- a/TriviaBot/bot/GatewayHandler.cpp +++ b/TriviaBot/bot/GatewayHandler.cpp @@ -4,6 +4,7 @@ #include "APIHelper.hpp" #include "data_structures/User.hpp" +#include "Logger.hpp" extern std::string bot_token; @@ -27,7 +28,7 @@ void GatewayHandler::handle_data(std::string data, client &c, websocketpp::conne on_hello(decoded, c, hdl); break; case 11: - c.get_alog().write(websocketpp::log::alevel::app, "Heartbeat acknowledged."); + Logger::write("Heartbeat acknowledged", Logger::LogLevel::Debug); break; } } @@ -43,14 +44,14 @@ void GatewayHandler::heartbeat(client *c, websocketpp::connection_hdl hdl, int i c->send(hdl, heartbeat.dump(), websocketpp::frame::opcode::text); - c->get_alog().write(websocketpp::log::alevel::app, "Sent heartbeat. (seq: " + std::to_string(last_seq) + ")"); + Logger::write("Sent heartbeat (seq: " + std::to_string(last_seq) + ")", Logger::LogLevel::Debug); } } void GatewayHandler::on_hello(json decoded, client &c, websocketpp::connection_hdl &hdl) { heartbeat_interval = decoded["d"]["heartbeat_interval"]; - c.get_alog().write(websocketpp::log::alevel::app, "Heartbeat interval: " + std::to_string(heartbeat_interval / 1000.0f) + " seconds"); + Logger::write("Heartbeat interval: " + std::to_string(heartbeat_interval / 1000.0f) + " seconds", Logger::LogLevel::Debug); heartbeat_thread = std::make_unique(boost::bind(&GatewayHandler::heartbeat, this, &c, hdl, heartbeat_interval)); @@ -65,13 +66,13 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio if (event_name == "READY") { user_object.load_from_json(data["user"]); - c.get_alog().write(websocketpp::log::alevel::app, "Sign-on confirmed. (@" + user_object.username + "#" + user_object.discriminator + ")"); + Logger::write("Sign-on confirmed. (@" + user_object.username + "#" + user_object.discriminator + ")", Logger::LogLevel::Info); } else if (event_name == "GUILD_CREATE") { std::string guild_id = data["id"]; guilds[guild_id] = std::make_unique(data); - c.get_alog().write(websocketpp::log::alevel::app, "Loaded guild: " + guilds[guild_id]->name); + Logger::write("Loaded guild: " + guilds[guild_id]->name, Logger::LogLevel::Debug); for (json channel : data["channels"]) { std::string channel_id = channel["id"]; @@ -84,8 +85,10 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio if (v8_instances.count(guild_id) == 0) { v8_instances[guild_id] = std::make_unique(ah); - c.get_alog().write(websocketpp::log::alevel::app, "Created v8 instance for guild " + guild_id); + Logger::write("Created v8 instance for guild " + guild_id, Logger::LogLevel::Debug); } + + Logger::write("Loaded " + std::to_string(guilds.size()) + " guild(s)", Logger::LogLevel::Info); } else if (event_name == "TYPING_START") {} else if (event_name == "MESSAGE_CREATE") { @@ -206,7 +209,7 @@ void GatewayHandler::identify(client &c, websocketpp::connection_hdl &hdl) { }; c.send(hdl, identify.dump(), websocketpp::frame::opcode::text); - c.get_alog().write(websocketpp::log::alevel::app, "Sent identify payload."); + Logger::write("Sent identify payload", Logger::LogLevel::Debug); } void GatewayHandler::delete_game(std::string channel_id) { @@ -217,6 +220,6 @@ void GatewayHandler::delete_game(std::string channel_id) { // remove from map games.erase(it); } else { - std::cerr << "Tried to delete a game that didn't exist."; + Logger::write("Tried to delete a game that didn't exist (channel_id: " + channel_id + ")", Logger::LogLevel::Warning); } } \ No newline at end of file diff --git a/TriviaBot/bot/Logger.cpp b/TriviaBot/bot/Logger.cpp new file mode 100644 index 0000000..e42b5ad --- /dev/null +++ b/TriviaBot/bot/Logger.cpp @@ -0,0 +1,39 @@ +#include "Logger.hpp" + +#include +#include +#include + +namespace Logger { + std::ostream &operator<<(std::ostream &out, const LogLevel log_level) { + switch (log_level) { + case LogLevel::Debug: + return out << "debug"; + case LogLevel::Info: + return out << "info"; + case LogLevel::Warning: + return out << "warning"; + case LogLevel::Severe: + return out << "severe"; + } + return out << ""; + } + + std::ostream &get_ostream(LogLevel log_level) { + switch (log_level) { + case LogLevel::Debug: + case LogLevel::Info: + return std::clog; + case LogLevel::Severe: + case LogLevel::Warning: + return std::cerr; + } + } + + void write(std::string text, LogLevel log_level) { + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + + get_ostream(log_level) << "[" << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << "] [" << log_level << "] " << text << std::endl; + } +} \ No newline at end of file diff --git a/TriviaBot/bot/Logger.hpp b/TriviaBot/bot/Logger.hpp new file mode 100644 index 0000000..b587b81 --- /dev/null +++ b/TriviaBot/bot/Logger.hpp @@ -0,0 +1,14 @@ +#ifndef BOT_LOGGER +#define BOT_LOGGER + +#include + +namespace Logger { + enum class LogLevel { + Debug, Info, Warning, Severe + }; + + void write(std::string text, LogLevel log_level); +} + +#endif diff --git a/TriviaBot/bot/TriviaBot.cpp b/TriviaBot/bot/TriviaBot.cpp index 10d8ceb..d284b93 100644 --- a/TriviaBot/bot/TriviaBot.cpp +++ b/TriviaBot/bot/TriviaBot.cpp @@ -3,6 +3,7 @@ #include #include "ClientConnection.hpp" +#include "Logger.hpp" std::string bot_token; @@ -15,6 +16,8 @@ int main(int argc, char *argv[]) { v8::V8::InitializePlatform(platform); v8::V8::Initialize(); + Logger::write("Initialised V8 and curl", Logger::LogLevel::Debug); + if (argc == 2) { bot_token = argv[1]; } @@ -30,14 +33,14 @@ int main(int argc, char *argv[]) { ClientConnection conn; conn.start(uri); } - catch (const std::exception & e) { - std::cerr << e.what() << std::endl; + catch (const std::exception &e) { + Logger::write(e.what(), Logger::LogLevel::Severe); } catch (websocketpp::lib::error_code e) { - std::cerr << e.message() << std::endl; + Logger::write(e.message(), Logger::LogLevel::Severe); } catch (...) { - std::cerr << "other exception" << std::endl; + Logger::write("Other exception.", Logger::LogLevel::Severe); } v8::V8::Dispose(); @@ -46,5 +49,7 @@ int main(int argc, char *argv[]) { curl_global_cleanup(); + Logger::write("Cleaned up", Logger::LogLevel::Info); + return 0; } \ No newline at end of file diff --git a/TriviaBot/bot/TriviaGame.cpp b/TriviaBot/bot/TriviaGame.cpp index 94a5631..275aa92 100644 --- a/TriviaBot/bot/TriviaGame.cpp +++ b/TriviaBot/bot/TriviaGame.cpp @@ -12,6 +12,7 @@ #include "GatewayHandler.hpp" #include "APIHelper.hpp" #include "data_structures/User.hpp" +#include "Logger.hpp" TriviaGame::TriviaGame(GatewayHandler *gh, std::shared_ptr ah, std::string channel_id, int total_questions, int delay) : interval(delay) { this->gh = gh; @@ -56,7 +57,7 @@ TriviaGame::~TriviaGame() { rc = sqlite3_open("bot/db/trivia.db", &db); if (rc) { - std::cerr << "Cant't open database: " << sqlite3_errmsg(db) << std::endl; + Logger::write("Can't open database: " + *sqlite3_errmsg(db), Logger::LogLevel::Severe); } std::string sql_in_list; @@ -71,7 +72,7 @@ TriviaGame::~TriviaGame() { rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, 0); if (rc != SQLITE_OK) { - std::cerr << "SQL error." << std::endl; + Logger::write("Error creating prepared statement: " + *sqlite3_errmsg(db), Logger::LogLevel::Severe); } // insert arguments @@ -79,7 +80,7 @@ TriviaGame::~TriviaGame() { rc = sqlite3_bind_text(stmt, i + 1, pairs[i].first.c_str(), -1, (sqlite3_destructor_type) -1); if (rc != SQLITE_OK) { - std::cerr << "SQL error." << std::endl; + Logger::write("Error binding prepared statement argument: " + *sqlite3_errmsg(db), Logger::LogLevel::Severe); break; } } @@ -97,7 +98,7 @@ TriviaGame::~TriviaGame() { data[id] = std::pair(total_score, average_time); } else if (rc != SQLITE_DONE) { sqlite3_finalize(stmt); - std::cerr << "SQLite error." << std::endl; + Logger::write("Error fetching results: " + *sqlite3_errmsg(db), Logger::LogLevel::Severe); break; } } @@ -116,7 +117,7 @@ TriviaGame::~TriviaGame() { rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, 0); if (rc != SQLITE_OK) { - std::cerr << "SQL error." << std::endl; + Logger::write("Error creating prepared statement: " + *sqlite3_errmsg(db), Logger::LogLevel::Severe); } int count = 1; @@ -140,7 +141,7 @@ TriviaGame::~TriviaGame() { if (update_sql != "") { rc = sqlite3_prepare_v2(db, update_sql.c_str(), -1, &stmt, 0); if (rc != SQLITE_OK) { - std::cerr << "SQL error." << std::endl; + Logger::write("Error creating prepared statement: " + *sqlite3_errmsg(db), Logger::LogLevel::Severe); } int index = 1; @@ -180,16 +181,15 @@ void TriviaGame::question() { /// open db rc = sqlite3_open("bot/db/trivia.db", &db); if (rc) { - std::cerr << "Cant't open database: " << sqlite3_errmsg(db) << std::endl; + Logger::write("Error opening database: " + *sqlite3_errmsg(db), Logger::LogLevel::Severe); } // prepare statement sqlite3_stmt *stmt; sql = "SELECT * FROM Questions ORDER BY RANDOM() LIMIT 1;"; rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, 0); - if (rc != SQLITE_OK) { - std::cerr << "SQL error." << std::endl; + Logger::write("Error creating prepared statement: " + *sqlite3_errmsg(db), Logger::LogLevel::Severe); } rc = sqlite3_step(stmt); @@ -205,9 +205,9 @@ void TriviaGame::question() { boost::split(current_answers, answer, boost::is_any_of("*")); } - else if (rc != SQLITE_DONE) { + else { sqlite3_finalize(stmt); - std::cerr << "SQLite error." << std::endl; + Logger::write("Error fetching question: " + *sqlite3_errmsg(db), Logger::LogLevel::Severe); } sqlite3_finalize(stmt); diff --git a/TriviaBot/bot/http/HTTPHelper.cpp b/TriviaBot/bot/http/HTTPHelper.cpp index 33b6c0a..5c76703 100644 --- a/TriviaBot/bot/http/HTTPHelper.cpp +++ b/TriviaBot/bot/http/HTTPHelper.cpp @@ -1,5 +1,7 @@ #include "HTTPHelper.hpp" +#include "../Logger.hpp" + extern std::string bot_token; /* @@ -40,10 +42,10 @@ std::string HTTPHelper::post_request(std::string url, std::string content_type, if (res == CURLE_OK) { curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, response_code); } else { + Logger::write("curl error", Logger::LogLevel::Warning); return ""; } - /* always cleanup */ curl_easy_cleanup(curl); curl_slist_free_all(headers); } diff --git a/TriviaBot/bot/js/CommandHelper.cpp b/TriviaBot/bot/js/CommandHelper.cpp index dade323..d641f8b 100644 --- a/TriviaBot/bot/js/CommandHelper.cpp +++ b/TriviaBot/bot/js/CommandHelper.cpp @@ -5,6 +5,8 @@ #include +#include "../Logger.hpp" + CommandHelper::CommandHelper() { sqlite3 *db; int return_code; return_code = sqlite3_open("bot/db/trivia.db", &db); @@ -32,7 +34,7 @@ CommandHelper::CommandHelper() { } } - std::cout << commands.size() << " commands loaded." << std::endl; + Logger::write(std::to_string(commands.size()) + " custom command loaded", Logger::LogLevel::Info); sqlite3_finalize(stmt); sqlite3_close(db); @@ -145,8 +147,9 @@ bool CommandHelper::command_in_db(std::string guild_id, std::string command_name } bool CommandHelper::return_code_ok(int return_code) { + // TODO: NotLikeThis if (return_code != SQLITE_OK) { - std::cerr << "SQLite error. " << std::endl; + Logger::write("SQLite error", Logger::LogLevel::Severe); return false; } return true; diff --git a/TriviaBot/bot/js/V8Instance.cpp b/TriviaBot/bot/js/V8Instance.cpp index 434fd8d..a8fd3f0 100644 --- a/TriviaBot/bot/js/V8Instance.cpp +++ b/TriviaBot/bot/js/V8Instance.cpp @@ -3,6 +3,7 @@ #include "V8Instance.hpp" #include "../APIHelper.hpp" +#include "../Logger.hpp" using namespace v8; @@ -21,7 +22,7 @@ void V8Instance::create() { isolate = Isolate::New(create_params); isolate->Enter(); - std::cout << "Created isolate." << std::endl; + Logger::write("[v8] Created isolate", Logger::LogLevel::Debug); Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); @@ -30,7 +31,7 @@ void V8Instance::create() { Local context = create_context(); context->Enter(); Context::Scope context_scope(context); - std::cout << "Created context and context scope." << std::endl; + Logger::write("[v8] Created context and context scope", Logger::LogLevel::Debug); } v8::Local V8Instance::create_context() { @@ -38,13 +39,13 @@ v8::Local V8Instance::create_context() { // bind print() function Local self = External::New(isolate, (void *) this); global->Set(String::NewFromUtf8(isolate, "print", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, V8Instance::js_print, self)); - std::cout << "Created global, assigned print function." << std::endl; + Logger::write("[v8] Created global obj, linked print function", Logger::LogLevel::Debug); return Context::New(isolate, NULL, global); } void V8Instance::clean_up() { - std::cout << "Cleaning up." << std::endl; + Logger::write("[v8] Cleaning up", Logger::LogLevel::Debug); isolate->Exit(); isolate->Dispose(); delete array_buffer_allocator; @@ -56,33 +57,29 @@ void V8Instance::reload() { } void V8Instance::exec_js(std::string js, std::string channel_id) { - std::cout << "Isolate nullptr? " << (isolate == nullptr) << std::endl; - HandleScope handle_scope(isolate); Local context(isolate->GetCurrentContext()); - std::cout << "Executing js: " << js << std::endl; + Logger::write("[v8] Executing JS: " + js, Logger::LogLevel::Debug); Local source = String::NewFromUtf8(isolate, js.c_str(), NewStringType::kNormal).ToLocalChecked(); - std::cout << "String coverted" << std::endl; // compile - std::cout << "Context empty? " << context.IsEmpty() << std::endl; + Logger::write("[v8] Isolate nullptr? " + std::to_string(isolate == nullptr) + " Context empty? " + std::to_string(context.IsEmpty()), Logger::LogLevel::Debug); TryCatch try_catch(isolate); Local