Added logger, resolves #4

This commit is contained in:
Jack Bond-Preston 2016-08-04 17:39:48 +01:00
parent 893a6cbbe1
commit a1c50b253d
10 changed files with 120 additions and 49 deletions

View File

@ -1,10 +1,11 @@
#include "http/HTTPHelper.hpp"
#include "APIHelper.hpp"
#include <cstdio>
#include <thread>
#include <chrono>
#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);
}
}

View File

@ -4,6 +4,7 @@
#include <iostream>
#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) {
@ -82,7 +83,7 @@ context_ptr ClientConnection::on_tls_init(websocketpp::connection_hdl) {
boost::asio::ssl::context::single_dh_use);
}
catch (std::exception &e) {
std::cout << "Error in context pointer: " << e.what() << std::endl;
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);
}

View File

@ -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::thread>(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<DiscordObjects::Guild>(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<V8Instance>(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);
}
}

39
TriviaBot/bot/Logger.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "Logger.hpp"
#include <iostream>
#include <iomanip>
#include <ctime>
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;
}
}

14
TriviaBot/bot/Logger.hpp Normal file
View File

@ -0,0 +1,14 @@
#ifndef BOT_LOGGER
#define BOT_LOGGER
#include <string>
namespace Logger {
enum class LogLevel {
Debug, Info, Warning, Severe
};
void write(std::string text, LogLevel log_level);
}
#endif

View File

@ -3,6 +3,7 @@
#include <include/v8.h>
#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];
}
@ -31,13 +34,13 @@ int main(int argc, char *argv[]) {
conn.start(uri);
}
catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
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;
}

View File

@ -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<APIHelper> 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<int, int>(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);

View File

@ -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);
}

View File

@ -5,6 +5,8 @@
#include <sqlite3.h>
#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;

View File

@ -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> 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<v8::Context> V8Instance::create_context() {
@ -38,13 +39,13 @@ v8::Local<v8::Context> V8Instance::create_context() {
// bind print() function
Local<External> 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> context(isolate->GetCurrentContext());
std::cout << "Executing js: " << js << std::endl;
Logger::write("[v8] Executing JS: " + js, Logger::LogLevel::Debug);
Local<String> 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<Script> script;
if (!Script::Compile(context, source).ToLocal(&script)) {
String::Utf8Value error(try_catch.Exception());
std::cerr << "Error: " << *error << std::endl;
Logger::write("[v8] Compilation error: " + std::string((const char *) *error), Logger::LogLevel::Debug);
return;
}
std::cout << "Compiled" << std::endl;
// run
script->Run(context);
std::cout << "Ran" << std::endl;
Logger::write("[v8] Script compiled and run", Logger::LogLevel::Debug);
ah->send_message(channel_id, print_text);
print_text = "";