From 02494d4691f4892839be1d3dd7b03c4d7e9b0f88 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 21 Mar 2019 07:15:38 +0800 Subject: [PATCH] Add prefixes, postfixes, and colors to the logger --- src/debug/ansi-escape-codes.cpp | 66 ++++++++++++++++++++++++++++++ src/debug/ansi-escape-codes.hpp | 72 +++++++++++++++++++++++++++++++++ src/debug/logger.cpp | 68 ++++++++++++++++++++++++++++++- src/debug/logger.hpp | 21 ++++++++++ src/game.cpp | 58 +++++++++++++++++++++----- 5 files changed, 272 insertions(+), 13 deletions(-) create mode 100644 src/debug/ansi-escape-codes.cpp create mode 100644 src/debug/ansi-escape-codes.hpp diff --git a/src/debug/ansi-escape-codes.cpp b/src/debug/ansi-escape-codes.cpp new file mode 100644 index 0000000..fcb5c99 --- /dev/null +++ b/src/debug/ansi-escape-codes.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017-2019 Christopher J. Howard + * + * This file is part of Antkeeper Source Code. + * + * Antkeeper Source Code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper Source Code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper Source Code. If not, see . + */ + +#include "ansi-escape-codes.hpp" + +const char* ANSI_CODE_RESET = "\u001b[0m"; + +const char* ANSI_CODE_BLACK = "\u001b[30m"; +const char* ANSI_CODE_RED = "\u001b[31m"; +const char* ANSI_CODE_GREEN = "\u001b[32m"; +const char* ANSI_CODE_YELLOW = "\u001b[33m"; +const char* ANSI_CODE_BLUE = "\u001b[34m"; +const char* ANSI_CODE_MAGENTA = "\u001b[35m"; +const char* ANSI_CODE_CYAN = "\u001b[36m"; +const char* ANSI_CODE_WHITE = "\u001b[37m"; + +const char* ANSI_CODE_BRIGHT_BLACK = "\u001b[30;1m"; +const char* ANSI_CODE_BRIGHT_RED = "\u001b[31;1m"; +const char* ANSI_CODE_BRIGHT_GREEN = "\u001b[32;1m"; +const char* ANSI_CODE_BRIGHT_YELLOW = "\u001b[33;1m"; +const char* ANSI_CODE_BRIGHT_BLUE = "\u001b[34;1m"; +const char* ANSI_CODE_BRIGHT_MAGENTA = "\u001b[35;1m"; +const char* ANSI_CODE_BRIGHT_CYAN = "\u001b[36;1m"; +const char* ANSI_CODE_BRIGHT_WHITE = "\u001b[37;1m"; + +const char* ANSI_CODE_BACKGROUND_BLACK = "\u001b[40m"; +const char* ANSI_CODE_BACKGROUND_RED = "\u001b[41m"; +const char* ANSI_CODE_BACKGROUND_GREEN = "\u001b[42m"; +const char* ANSI_CODE_BACKGROUND_YELLOW = "\u001b[43m"; +const char* ANSI_CODE_BACKGROUND_BLUE = "\u001b[44m"; +const char* ANSI_CODE_BACKGROUND_MAGENTA = "\u001b[45m"; +const char* ANSI_CODE_BACKGROUND_CYAN = "\u001b[46m"; +const char* ANSI_CODE_BACKGROUND_WHITE = "\u001b[47m"; + +const char* ANSI_CODE_BACKGROUND_BRIGHT_BLACK = "\u001b[40;1m"; +const char* ANSI_CODE_BACKGROUND_BRIGHT_RED = "\u001b[41;1m"; +const char* ANSI_CODE_BACKGROUND_BRIGHT_GREEN = "\u001b[42;1m"; +const char* ANSI_CODE_BACKGROUND_BRIGHT_YELLOW = "\u001b[43;1m"; +const char* ANSI_CODE_BACKGROUND_BRIGHT_BLUE = "\u001b[44;1m"; +const char* ANSI_CODE_BACKGROUND_BRIGHT_MAGENTA = "\u001b[45;1m"; +const char* ANSI_CODE_BACKGROUND_BRIGHT_CYAN = "\u001b[46;1m"; +const char* ANSI_CODE_BACKGROUND_BRIGHT_WHITE = "\u001b[47;1m"; + +const char* ANSI_CODE_BOLD = "\u001b[1m"; +const char* ANSI_CODE_UNDERLINE = "\u001b[4m"; +const char* ANSI_CODE_REVERSED = "\u001b[7m"; + + + + diff --git a/src/debug/ansi-escape-codes.hpp b/src/debug/ansi-escape-codes.hpp new file mode 100644 index 0000000..ae92768 --- /dev/null +++ b/src/debug/ansi-escape-codes.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017-2019 Christopher J. Howard + * + * This file is part of Antkeeper Source Code. + * + * Antkeeper Source Code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper Source Code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper Source Code. If not, see . + */ + +#ifndef ANSI_ESCAPE_CODES_HPP +#define ANSI_ESCAPE_CODES_HPP + +// Reset code +extern const char* ANSI_CODE_RESET; + +// Standard colors +extern const char* ANSI_CODE_BLACK; +extern const char* ANSI_CODE_RED; +extern const char* ANSI_CODE_GREEN; +extern const char* ANSI_CODE_YELLOW; +extern const char* ANSI_CODE_BLUE; +extern const char* ANSI_CODE_MAGENTA; +extern const char* ANSI_CODE_CYAN; +extern const char* ANSI_CODE_WHITE; + +// Bright colors +extern const char* ANSI_CODE_BRIGHT_BLACK; +extern const char* ANSI_CODE_BRIGHT_RED; +extern const char* ANSI_CODE_BRIGHT_GREEN; +extern const char* ANSI_CODE_BRIGHT_YELLOW; +extern const char* ANSI_CODE_BRIGHT_BLUE; +extern const char* ANSI_CODE_BRIGHT_MAGENTA; +extern const char* ANSI_CODE_BRIGHT_CYAN; +extern const char* ANSI_CODE_BRIGHT_WHITE; + +// Standard background colors +extern const char* ANSI_CODE_BACKGROUND_BLACK; +extern const char* ANSI_CODE_BACKGROUND_RED; +extern const char* ANSI_CODE_BACKGROUND_GREEN; +extern const char* ANSI_CODE_BACKGROUND_YELLOW; +extern const char* ANSI_CODE_BACKGROUND_BLUE; +extern const char* ANSI_CODE_BACKGROUND_MAGENTA; +extern const char* ANSI_CODE_BACKGROUND_CYAN; +extern const char* ANSI_CODE_BACKGROUND_WHITE; + +// Bright background colors +extern const char* ANSI_CODE_BACKGROUND_BRIGHT_BLACK; +extern const char* ANSI_CODE_BACKGROUND_BRIGHT_RED; +extern const char* ANSI_CODE_BACKGROUND_BRIGHT_GREEN; +extern const char* ANSI_CODE_BACKGROUND_BRIGHT_YELLOW; +extern const char* ANSI_CODE_BACKGROUND_BRIGHT_BLUE; +extern const char* ANSI_CODE_BACKGROUND_BRIGHT_MAGENTA; +extern const char* ANSI_CODE_BACKGROUND_BRIGHT_CYAN; +extern const char* ANSI_CODE_BACKGROUND_BRIGHT_WHITE; + +// Decorations +extern const char* ANSI_CODE_BOLD; +extern const char* ANSI_CODE_UNDERLINE; +extern const char* ANSI_CODE_REVERSED; + +#endif // ANSI_ESCAPE_CODES_HPP + diff --git a/src/debug/logger.cpp b/src/debug/logger.cpp index b0817ef..0498c7e 100644 --- a/src/debug/logger.cpp +++ b/src/debug/logger.cpp @@ -18,10 +18,19 @@ */ #include "logger.hpp" +#include "ansi-escape-codes.hpp" #include Logger::Logger(): - os(&std::cout) + os(&std::cout), + logPrefix(std::string()), + logPostfix("\n"), + warningPrefix(ANSI_CODE_YELLOW + std::string("Warning: ")), + warningPostfix(ANSI_CODE_RESET), + errorPrefix(ANSI_CODE_RED + std::string("Error: ")), + errorPostfix(ANSI_CODE_RESET), + successPrefix(ANSI_CODE_GREEN + std::string("Success: ")), + successPostfix(ANSI_CODE_RESET) {} Logger::~Logger() @@ -36,8 +45,63 @@ void Logger::log(const std::string& text) { if (os) { - (*os) << text; + (*os) << (logPrefix + text + logPostfix); os->flush(); } } +void Logger::warning(const std::string& text) +{ + log(warningPrefix + text + warningPostfix); +} + +void Logger::error(const std::string& text) +{ + log(errorPrefix + text + errorPostfix); +} + +void Logger::success(const std::string& text) +{ + log(successPrefix + text + successPostfix); +} + +void Logger::setLogPrefix(const std::string& prefix) +{ + logPrefix = prefix; +} + +void Logger::setLogPostfix(const std::string& postfix) +{ + logPostfix = postfix; +} + +void Logger::setWarningPrefix(const std::string& prefix) +{ + warningPrefix = prefix; +} + +void Logger::setWarningPostfix(const std::string& postfix) +{ + warningPostfix = postfix; +} + +void Logger::setErrorPrefix(const std::string& prefix) +{ + errorPrefix = prefix; +} + +void Logger::setErrorPostfix(const std::string& postfix) +{ + errorPostfix = postfix; +} + +void Logger::setSuccessPrefix(const std::string& prefix) +{ + successPrefix = prefix; +} + +void Logger::setSuccessPostfix(const std::string& postfix) +{ + successPostfix = postfix; +} + diff --git a/src/debug/logger.hpp b/src/debug/logger.hpp index 3529568..d343e3e 100644 --- a/src/debug/logger.hpp +++ b/src/debug/logger.hpp @@ -40,8 +40,29 @@ public: */ void log(const std::string& text); + void warning(const std::string& text); + void error(const std::string& text); + void success(const std::string& text); + + void setLogPrefix(const std::string& prefix); + void setLogPostfix(const std::string& postfix); + void setWarningPrefix(const std::string& prefix); + void setWarningPostfix(const std::string& postfix); + void setErrorPrefix(const std::string& prefix); + void setErrorPostfix(const std::string& postfix); + void setSuccessPrefix(const std::string& prefix); + void setSuccessPostfix(const std::string& postfix); + private: std::ostream* os; + std::string logPrefix; + std::string logPostfix; + std::string warningPrefix; + std::string warningPostfix; + std::string errorPrefix; + std::string errorPostfix; + std::string successPrefix; + std::string successPostfix; }; #endif // LOGGER_HPP diff --git a/src/game.cpp b/src/game.cpp index 527bce2..95ff21e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -66,6 +66,7 @@ #include "debug/command-interpreter.hpp" #include "debug/logger.hpp" +#include "debug/ansi-escape-codes.hpp" template <> bool Game::readSetting(const std::string& name, std::string* value) const @@ -506,7 +507,7 @@ void Game::setup() } catch (const std::exception& e) { - logger->log("Failed to load one or more models: \"" + std::string(e.what()) + "\"\n"); + logger->error("Failed to load one or more models: \"" + std::string(e.what()) + "\"\n"); close(EXIT_FAILURE); } @@ -746,10 +747,45 @@ void Game::handleEvent(const ScheduledFunctionEvent& event) void Game::setupDebugging() { // Setup logging - logger = new Logger(); - std::string logFilename = configPath + "log.txt"; - logFileStream.open(logFilename.c_str()); - logger->redirect(&logFileStream); + { + logger = new Logger(); + + // Style log format + std::string logPrefix = std::string(); + std::string logPostfix = "\n"; + std::string warningPrefix = "Warning: "; + std::string warningPostfix = std::string(); + std::string errorPrefix = "Error: "; + std::string errorPostfix = std::string(); + std::string successPrefix = std::string(); + std::string successPostfix = std::string(); + + // Enable colored messages on debug builds + #if defined(DEBUG) + warningPrefix = std::string(ANSI_CODE_BOLD) + std::string(ANSI_CODE_YELLOW) + std::string("Warning: ") + std::string(ANSI_CODE_RESET) + std::string(ANSI_CODE_YELLOW); + warningPostfix.append(ANSI_CODE_RESET); + errorPrefix = std::string(ANSI_CODE_BOLD) + std::string(ANSI_CODE_RED) + std::string("Error: ") + std::string(ANSI_CODE_RESET) + std::string(ANSI_CODE_RED); + errorPostfix.append(ANSI_CODE_RESET); + successPrefix.insert(0, ANSI_CODE_GREEN); + successPostfix.append(ANSI_CODE_RESET); + #endif + + logger->setLogPrefix(logPrefix); + logger->setLogPostfix(logPostfix); + logger->setWarningPrefix(warningPrefix); + logger->setWarningPostfix(warningPostfix); + logger->setErrorPrefix(errorPrefix); + logger->setErrorPostfix(errorPostfix); + logger->setSuccessPrefix(successPrefix); + logger->setSuccessPostfix(successPostfix); + + // Redirect logger output to log file on release builds + #if !defined(DEBUG) + std::string logFilename = configPath + "log.txt"; + logFileStream.open(logFilename.c_str()); + logger->redirect(&logFileStream); + #endif + } // Create CLI cli = new CommandInterpreter(); @@ -2034,7 +2070,7 @@ void Game::loadControlProfile(const std::string& profileName) auto it = controlNameMap.find(controlName); if (it == controlNameMap.end()) { - logger->log("Game::loadControlProfile(): Unknown control name \"" + controlName + "\"\n"); + logger->warning("Game::loadControlProfile(): Unknown control name \"" + controlName + "\"\n"); continue; } @@ -2078,7 +2114,7 @@ void Game::loadControlProfile(const std::string& profileName) } else { - logger->log("Game::loadControlProfile(): Unknown mouse motion axis \"" + axisName + "\"\n"); + logger->warning("Game::loadControlProfile(): Unknown mouse motion axis \"" + axisName + "\"\n"); continue; } @@ -2102,7 +2138,7 @@ void Game::loadControlProfile(const std::string& profileName) } else { - logger->log("Game::loadControlProfile(): Unknown mouse wheel axis \"" + axisName + "\"\n"); + logger->warning("Game::loadControlProfile(): Unknown mouse wheel axis \"" + axisName + "\"\n"); continue; } @@ -2124,7 +2160,7 @@ void Game::loadControlProfile(const std::string& profileName) } else { - logger->log("Game::loadControlProfile(): Unknown mouse event type \"" + eventType + "\"\n"); + logger->warning("Game::loadControlProfile(): Unknown mouse event type \"" + eventType + "\"\n"); continue; } } @@ -2182,13 +2218,13 @@ void Game::loadControlProfile(const std::string& profileName) } else { - logger->log("Game::loadControlProfile(): Unknown gamepad event type \"" + eventType + "\"\n"); + logger->warning("Game::loadControlProfile(): Unknown gamepad event type \"" + eventType + "\"\n"); continue; } } else { - logger->log("Game::loadControlProfile(): Unknown input device type \"" + deviceType + "\"\n"); + logger->warning("Game::loadControlProfile(): Unknown input device type \"" + deviceType + "\"\n"); continue; } }