custom log function; change Game and Node from struct to class

This commit is contained in:
frank 2021-06-24 17:40:30 -04:00
parent 4ece64442f
commit fff9e13562
12 changed files with 126 additions and 66 deletions

View File

@ -46,7 +46,7 @@ struct Mushroom : Sprite
Mushroom(Node*);
void update();
std::string get_class_name() { return "Mushroom"; }
virtual std::string get_class_name() const { return "Mushroom"; }
};
@ -71,6 +71,6 @@ struct Demo : Game
void load_gl_context();
void respond(SDL_Event&);
void update();
std::string get_class_name() { return "Demo"; }
virtual std::string get_class_name() const { return "Demo"; }
};

View File

@ -9,7 +9,7 @@
typedef std::function<void()> callback;
struct Node;
class Node;
struct Animation
{

View File

@ -77,7 +77,7 @@ struct Box : SDL_FRect
bool collide(const Segment&, glm::vec2&) const;
bool collide(const Box&, Box* = nullptr) const;
bool collide(const Box&, Box&) const;
std::string get_class_name() { return "Box"; }
virtual std::string get_class_name() const { return "Box"; }
std::ostream& to_string (std::ostream&) const;
};

View File

@ -75,9 +75,10 @@ void Configuration::set_defaults()
sys_config["animation"] = {
{"all-frames-frameset-name", "all"}
};
sys_config["logging"] = {
sys_config["log"] = {
{"enabled", false},
{"debug", false},
{"debug-to-stdout", false},
{"debug-to-file", false},
{"ouput-directory", "."},
{"info-file-name", "log.txt"},
{"debug-file-name", "debug_log.txt"}

View File

@ -20,7 +20,7 @@ struct Configuration : Node
void merge();
void write();
void write(fs::path path);
std::string get_class_name() { return "Configuration"; }
virtual std::string get_class_name() const { return "Configuration"; }
};

View File

@ -39,49 +39,26 @@ void FramerateIndicator::refresh()
}
}
void log(void* userdata, int category, SDL_LogPriority priority, const char* message)
{
Game* game = static_cast<Game*>(userdata);
std::ostream& out = (priority > SDL_LOG_PRIORITY_DEBUG) ? std::cerr : std::cout;
out << message << std::endl;
if (game->get_configuration()["logging"]["enabled"])
{
fs::path path = game->get_configuration()["logging"]["output-directory"];
if (!fs::exists(path))
{
fs::create_directories(path);
}
std::time_t now = std::time(nullptr);
std::stringstream stamped_message;
stamped_message << std::put_time(std::localtime(&now), "%F %T ") << message;
if (game->get_configuration()["logging"]["debug"])
{
fs::path debug_path = path / game->get_configuration()["logging"]["debug-file-name"];
std::ofstream debug_stream(debug_path, std::ios_base::app);
debug_stream << stamped_message.str() << std::endl;
}
if (priority > SDL_LOG_PRIORITY_DEBUG)
{
fs::path info_path = path / game->get_configuration()["logging"]["info-file-name"];
std::ofstream info_stream(info_path, std::ios_base::app);
info_stream << stamped_message.str() << std::endl;
}
}
}
Game::Game()
{
// use config to determine if debug statements should be printed
if (get_configuration()["logging"]["debug"])
// set the appropriate priority level for the default log category so either info level messages
// and higher are enabled or debug level messages are enabled, depending on the global configuration
SDL_LogPriority default_log_category_priority;
if (get_configuration()["log"]["debug-to-file"] || get_configuration()["log"]["debug-to-stdout"])
{
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
default_log_category_priority = SDL_LOG_PRIORITY_DEBUG;
}
else
{
default_log_category_priority = SDL_LOG_PRIORITY_INFO;
}
SDL_LogSetPriority(DEFAULT_SDL_LOG_CATEGORY, default_log_category_priority);
// set custom log function (prints to stdout/stderr and to file if enabled)
SDL_LogSetOutputFunction(&log, this);
SDL_LogSetOutputFunction(&Game::sdl_log_override, this);
// pretty print config to debug log
std::stringstream config_formatted;
config_formatted << std::setw(4) << get_configuration() << std::endl;
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "%s", config_formatted.str().c_str());
SDL_LogDebug(DEFAULT_SDL_LOG_CATEGORY, "%s", config_formatted.str().c_str());
SDL_SetHint(SDL_HINT_RENDER_DRIVER, get_configuration()["display"]["render driver"].get<std::string>().c_str());
frame_length_history.reserve(5000);
set_framerate(get_configuration()["display"]["framerate"]);
@ -192,6 +169,48 @@ Game::~Game()
get_delegate().unsubscribe(this);
}
/* Overrides SDL's default log function to log a message to stdout/stderr and, if log is enabled in the
* global configuration, to a file. Debug level statements may be suppressed, printed to stdout, or printed to
* both stdout and file, depending on the global configuration.
*/
void Game::sdl_log_override(void* userdata, int category, SDL_LogPriority priority, const char* message)
{
Game* game = static_cast<Game*>(userdata);
std::ostream& out = (priority > SDL_LOG_PRIORITY_WARN) ? std::cerr : std::cout;
// print to stdout/stderr if priority is higher than debug or debug statements are enabled
if (priority > SDL_LOG_PRIORITY_DEBUG || game->get_configuration()["log"]["debug-to-stdout"])
{
out << message << std::endl;
}
// handle writing to log file
if (game->get_configuration()["log"]["enabled"])
{
fs::path path = game->get_configuration()["log"]["output-directory"];
if (!fs::exists(path))
{
fs::create_directories(path);
}
// prepend a timestamp to the message
std::time_t now = std::time(nullptr);
std::stringstream stamped_message;
stamped_message << std::put_time(std::localtime(&now), "%F %T ") << message;
// if debug is enabled, append message to debug log file
if (game->get_configuration()["log"]["debug-to-file"])
{
fs::path debug_path = path / game->get_configuration()["log"]["debug-file-name"];
std::ofstream debug_stream(debug_path, std::ios_base::app);
debug_stream << stamped_message.str() << std::endl;
}
// only append messages to the info log that are higher than debug priority
if (priority > SDL_LOG_PRIORITY_DEBUG)
{
fs::path info_path = path / game->get_configuration()["log"]["info-file-name"];
std::ofstream info_stream(info_path, std::ios_base::app);
info_stream << stamped_message.str() << std::endl;
}
}
}
void Game::print_error(const std::string& message)
{
sfw::print_error(message);
@ -288,6 +307,23 @@ void Game::load_gl_context()
log_display_mode();
}
/* Send an info priority message to SDL's log output function, which is overridden by our own member
* function. Category will default to SDL's custom category.
*/
void Game::log(const std::string& message, const int category) const
{
SDL_LogInfo(category, "%s", message.c_str());
}
/* Send a debug priority message to SDL's log output function, which is overridden by our own member
* function. Category will default to SDL's custom category. Using the default category will ensure
* that debug level statements are handled according to the options in the global configuration.
*/
void Game::debug(const std::string& message, const int category) const
{
SDL_LogDebug(category, "%s", message.c_str());
}
void Game::log_renderer_info(SDL_RendererInfo& info)
{
SDL_Log("renderer name: %s, flags: %i, texture formats: %i, "

View File

@ -42,16 +42,21 @@ struct FramerateIndicator : Sprite
};
void log(void*, int, SDL_LogPriority, const char*);
struct Game : Node
class Game : public Node
{
private:
static void sdl_log_override(void*, int, SDL_LogPriority, const char*);
public:
Game(const Game&) = delete;
Game& operator=(const Game&) = delete;
Game(Game&&) = delete;
Game& operator=(Game&&) = delete;
static const int DEFAULT_SDL_LOG_CATEGORY = SDL_LOG_CATEGORY_CUSTOM;
SDL_Window* window;
SDL_Renderer* renderer = NULL;
SDL_GLContext glcontext = NULL;
@ -78,6 +83,8 @@ struct Game : Node
void print_frame_length_history();
void load_sdl_context();
void load_gl_context();
void log(const std::string&, const int = DEFAULT_SDL_LOG_CATEGORY) const;
void debug(const std::string&, const int = DEFAULT_SDL_LOG_CATEGORY) const;
void log_renderer_info(SDL_RendererInfo&);
bool log_gl_errors(std::string);
void log_display_mode();
@ -98,7 +105,7 @@ struct Game : Node
void set_framerate(int);
void handle_quit_event(SDL_Event&);
void quit();
std::string get_class_name() { return "Game"; }
virtual std::string get_class_name() const { return "Game"; }
template<typename T>
float weight(T amount)

View File

@ -60,7 +60,7 @@ struct Input : Node
void suppress();
void unsuppress();
bool is_suppressed();
std::string get_class_name() { return "Input"; }
virtual std::string get_class_name() const { return "Input"; }
};

View File

@ -11,8 +11,7 @@ Node::Node() : Node(nullptr) {}
Node::Node(Node* parent) : parent(parent)
{
std::cout << "Constructing ";
print_branch();
debug("constructing node " + get_branch_as_string());
}
void Node::set_parent(Node* other)
@ -35,6 +34,11 @@ bool Node::is_active() const
return active;
}
const nlohmann::json& Node::get_configuration() const
{
return get_root()->configuration.config;
}
nlohmann::json& Node::get_configuration()
{
return get_root()->configuration.config;
@ -120,27 +124,34 @@ void Node::unsuppress_input()
get_root()->get_input().unsuppress();
}
void Node::print_branch()
void Node::log(const std::string& message) const
{
Node* current = this;
get_root()->log(message);
}
void Node::debug(const std::string& message) const
{
get_root()->debug(message);
}
const std::string Node::get_branch_as_string() const
{
const Node* current = this;
std::stringstream branch;
while (current != nullptr)
{
std::cout << current->get_class_name() << " @ " << current;
branch << current->get_class_name() << " @ " << current;
if (current->parent != nullptr)
{
std::cout << " -> ";
}
else
{
std::cout << std::endl;
branch << " -> ";
}
current = current->parent;
}
return branch.str();
}
Node::~Node()
{
// std::cout << "Destructing ";
// print_branch();
debug("destroying node " + get_branch_as_string());
get_delegate().unsubscribe(this);
}

View File

@ -10,16 +10,18 @@
#include "filesystem.hpp"
struct Game;
class Game;
struct Delegate;
struct Display;
struct Input;
struct Box;
struct Audio;
struct Node
class Node
{
public:
Node *parent;
SDL_Texture* canvas = nullptr;
bool active = true;
@ -33,6 +35,7 @@ struct Node
void set_canvas(SDL_Texture*);
SDL_Texture* get_canvas();
bool is_active() const;
const nlohmann::json& get_configuration() const;
nlohmann::json& get_configuration();
Delegate& get_delegate();
const Display& get_display() const;
@ -48,8 +51,10 @@ struct Node
void suppress_input();
void suppress_input_temporarily(int = 0);
void unsuppress_input();
void print_branch();
virtual std::string get_class_name() { return "Node"; };
void log(const std::string&) const;
void debug(const std::string&) const;
const std::string get_branch_as_string() const;
virtual std::string get_class_name() const { return "Node"; };
virtual ~Node();
template<typename T = Game>

View File

@ -62,7 +62,7 @@ struct Recorder : Node
void write_mp4();
void write_audio(Uint8*, int);
void update();
std::string get_class_name() { return "Recorder"; }
virtual std::string get_class_name() const { return "Recorder"; }
};

View File

@ -17,7 +17,7 @@
#include "Animation.hpp"
#include "Color.hpp"
struct Game;
class Game;
struct Frameset;
struct Sprite : Node
@ -143,7 +143,7 @@ struct Sprite : Node
void render_subsection(SDL_Renderer*, SDL_Texture*, const Box&, const Box&);
void set_to_leave_memory_allocated();
void set_to_deallocate_memory();
virtual std::string get_class_name() { return "Sprite"; }
virtual std::string get_class_name() const { return "Sprite"; }
~Sprite() { unload(); }
};