summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/Exceptions.cpp45
-rw-r--r--src/core/Exceptions.hpp170
-rw-r--r--src/core/Logger.cpp160
-rw-r--r--src/core/Logger.hpp384
4 files changed, 686 insertions, 73 deletions
diff --git a/src/core/Exceptions.cpp b/src/core/Exceptions.cpp
new file mode 100644
index 0000000..92d9293
--- /dev/null
+++ b/src/core/Exceptions.cpp
@@ -0,0 +1,45 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program 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.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <sstream>
+
+#include "Exceptions.hpp"
+
+namespace ousia {
+
+/* Class LoggableException */
+
+std::string LoggableException::formatMessage(const std::string &msg,
+ const std::string &file, int line,
+ int column, bool fatal)
+{
+ std::stringstream ss;
+ if (!file.empty()) {
+ ss << "while processing \"" << file << "\" ";
+ }
+ if (line >= 0) {
+ ss << "at line: " << line << " ";
+ if (column >= 0) {
+ ss << "col: " << column << " ";
+ }
+ }
+ ss << "message: " << msg;
+ return ss.str();
+}
+}
+
diff --git a/src/core/Exceptions.hpp b/src/core/Exceptions.hpp
new file mode 100644
index 0000000..f1bb95a
--- /dev/null
+++ b/src/core/Exceptions.hpp
@@ -0,0 +1,170 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program 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.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file Exceptions.hpp
+ *
+ * Describes basic exception classes which are used throughout Ousía.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_EXCEPTIONS_HPP_
+#define _OUSIA_EXCEPTIONS_HPP_
+
+namespace ousia {
+
+/**
+ * Base exception class all other Ousía exceptions should derive from.
+ */
+class OusiaException : public std::exception {
+private:
+ /**
+ * Error message which will be printed by the runtime environment if the
+ * exception is not caught and handled in the code.
+ */
+ const std::string formatedMessage;
+
+public:
+ /**
+ * Constructor of the OusiaException class.
+ *
+ * @param formatedMessage is a formated message that should be printed by
+ * the runtime environment if the exception is not caught.
+ */
+ OusiaException(std::string formatedMessage)
+ : formatedMessage(std::move(formatedMessage))
+ {
+ }
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~OusiaException() {}
+
+ /**
+ * Implementation of the std::exception what function and used to retrieve
+ * the error message that should be printed by the runtime environment.
+ *
+ * @return a reference to the formated message string given in the
+ * constructor.
+ */
+ const char *what() const noexcept override
+ {
+ return formatedMessage.c_str();
+ }
+};
+
+/**
+ * Exception class which can be directly passed to a Logger instance and thus
+ * makes it simple to handle non-recoverable errors in the code.
+ */
+class LoggableException : public OusiaException {
+private:
+ /**
+ * Function used internally to build the formated message that should be
+ * reported to the runtime environment.
+ */
+ static std::string formatMessage(const std::string &msg,
+ const std::string &file, int line,
+ int column, bool fatal);
+
+public:
+ /**
+ * Message describing the error that occured.
+ */
+ const std::string msg;
+
+ /**
+ * Name of the file in which the error occured. May be empty.
+ */
+ const std::string file;
+
+ /**
+ * Line at which the exception occured. Negative values are ignored.
+ */
+ const int line;
+
+ /**
+ * Column at which the exception occured. Negative values are ignored.
+ */
+ const int column;
+
+ /**
+ * If set to true, the exception should not be handled as recoverable error
+ * but as "fatal" error.
+ */
+ const bool fatal;
+
+ /**
+ * Constructor of the LoggableException class.
+ *
+ * @param msg contains the error message.
+ * @param file provides the context the message refers to. May be empty.
+ * @param line is the line in the above file the message refers to.
+ * @param column is the column in the above file the message refers to.
+ * @param fatal shoudl be set to true if the error is non-recoverable.
+ */
+ LoggableException(std::string msg, std::string file, int line = -1,
+ int column = -1, bool fatal = true)
+ : OusiaException(formatMessage(msg, file, line, column, fatal)),
+ msg(std::move(msg)),
+ file(std::move(file)),
+ line(line),
+ column(column),
+ fatal(fatal)
+ {
+ }
+
+ /**
+ * Constructor of the LoggableException class with empty file.
+ *
+ * @param msg contains the error message.
+ * @param line is the line in the above file the message refers to.
+ * @param column is the column in the above file the message refers to.
+ * @param fatal shoudl be set to true if the error is non-recoverable.
+ */
+ LoggableException(std::string msg, int line = -1, int column = -1,
+ bool fatal = true)
+ : OusiaException(formatMessage(msg, "", line, column, fatal)),
+ msg(std::move(msg)),
+ line(line),
+ column(column),
+ fatal(fatal)
+ {
+ }
+
+ /**
+ * Constructor of the LoggableException class with empty file.
+ *
+ * @param msg contains the error message.
+ * @param fatal should be set to true if the error is non-recoverable.
+ */
+ LoggableException(std::string msg, bool fatal)
+ : OusiaException(formatMessage(msg, "", -1, -1, fatal)),
+ msg(std::move(msg)),
+ line(-1),
+ column(-1),
+ fatal(fatal)
+ {
+ }
+};
+}
+
+#endif /* _OUSIA_EXCEPTIONS_HPP_ */
+
diff --git a/src/core/Logger.cpp b/src/core/Logger.cpp
index 2317e70..1a3b6c6 100644
--- a/src/core/Logger.cpp
+++ b/src/core/Logger.cpp
@@ -16,54 +16,146 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <iostream>
+#include <sstream>
+
+#include "Logger.hpp"
+
namespace ousia {
-static const int BLACK = 30;
-static const int RED = 31;
-static const int GREEN = 32;
-static const int YELLOW = 33;
-static const int BLUE = 34;
-static const int MAGENTA = 35;
-static const int CYAN = 36;
-static const int WHITE = 37;
-
-void StreamLogger::logMessage(const LogMessage &msg) {
- os << '[';
+/* Class Logger */
+
+void Logger::log(Severity severity, const std::string &msg,
+ const std::string &file, int line, int column)
+{
+ // Copy the current severity level
+ if (static_cast<int>(severity) > static_cast<int>(maxEncounteredSeverity)) {
+ maxEncounteredSeverity = severity;
+ }
+
+ // Call the actual log message function if the severity is larger or equal
+ // to the minimum severity
+ if (static_cast<int>(severity) >= static_cast<int>(minSeverity)) {
+ process(Message{severity, msg, file, line, column});
+ }
+}
+
+unsigned int Logger::pushFilename(const std::string &name)
+{
+ filenameStack.push(name);
+ return filenameStack.size();
+}
+
+unsigned int Logger::popFilename()
+{
+ filenameStack.pop();
+ return filenameStack.size();
+}
+
+void Logger::unwindFilenameStack(unsigned int pos)
+{
+ while (filenameStack.size() > pos && !filenameStack.empty()) {
+ filenameStack.pop();
+ }
+}
+
+/* Class TerminalLogger */
+
+/**
+ * Small class used internally for formated terminal output using ANSI/VT100
+ * escape codes on supported terminals.
+ *
+ * TODO: Deactivate if using windows or use the corresponding API function.
+ */
+class Terminal {
+private:
+ /**
+ * If set to false, no control codes are generated.
+ */
+ bool active;
+
+public:
+ static const int BLACK = 30;
+ static const int RED = 31;
+ static const int GREEN = 32;
+ static const int YELLOW = 33;
+ static const int BLUE = 34;
+ static const int MAGENTA = 35;
+ static const int CYAN = 36;
+ static const int WHITE = 37;
+
+ Terminal(bool active) : active(active) {}
+
+ std::string color(int color, bool bright = true) const
+ {
+ if (!active) {
+ return std::string{};
+ }
+ std::stringstream ss;
+ ss << "\x1b[";
+ if (bright) {
+ ss << "1;";
+ }
+ ss << color << "m";
+ return ss.str();
+ }
+
+ std::string reset() const
+ {
+ if (!active) {
+ return std::string{};
+ }
+ return "\x1b[0m";
+ }
+};
+
+void TerminalLogger::process(const Message &msg)
+{
+ Terminal t(useColor);
+
+ // Print the file name
+ if (msg.hasFile()) {
+ os << t.color(Terminal::WHITE, true) << msg.file << t.reset();
+ }
+
+ // Print line and column number
+ if (msg.hasLine()) {
+ if (msg.hasFile()) {
+ os << ':';
+ }
+ os << t.color(Terminal::WHITE, true) << msg.line
+ << t.reset();
+ if (msg.hasColumn()) {
+ os << ':' << msg.column;
+ }
+ }
+
+ // Print the optional seperator
+ if (msg.hasFile() || msg.hasLine()) {
+ os << ": ";
+ }
+
+ // Print the severity
switch (msg.severity) {
case Severity::DEBUG:
- os << "debug" << os;
break;
- case Severity::INFO:
- os << "info" << os;
+ case Severity::NOTE:
+ os << t.color(Terminal::CYAN, true) << "note: ";
break;
case Severity::WARNING:
- os << "warning" << os;
+ os << t.color(Terminal::MAGENTA, true) << "warning: ";
break;
case Severity::ERROR:
- os << "error" << os;
+ os << t.color(Terminal::RED, true) << "error: ";
break;
case Severity::FATAL_ERROR:
- is << "fatal error" << os;
+ os << t.color(Terminal::RED, true) << "error: ";
break;
}
- os << ']';
-
- // Print the file name
- if (!msg.file.empty()) {
- os << msg.file;
-
- // Print the line and column
- if (msg.line >= 0) {
- os << ':' << msg.line;
- if (msg.column >= 0) {
- os << ':' << msg.column;
- }
- }
- }
+ os << t.reset();
// Print the actual message
- os << ' ' << msg.msg;
+ os << msg.msg << std::endl;
+}
}
-
-};
diff --git a/src/core/Logger.hpp b/src/core/Logger.hpp
index 8f0abfb..260d010 100644
--- a/src/core/Logger.hpp
+++ b/src/core/Logger.hpp
@@ -16,111 +16,417 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * @file Logger.hpp
+ *
+ * Contains classes for logging messages in Ousía. Provides a generic Logger
+ * class, and TerminalLogger, an extension of Logger which logs do an output
+ * stream.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
#ifndef _OUSIA_LOGGER_HPP_
#define _OUSIA_LOGGER_HPP_
#include <ostream>
+#include <stack>
#include <string>
#include <vector>
+#include "Exceptions.hpp"
+
namespace ousia {
+/**
+ * Enum containing the severities used for logging errors and debug messages.
+ */
enum class Severity : int {
+ /**
+ * Indicates that this message was only printed for debugging. Note that
+ * in release builds messages with this severity are discarded.
+ */
DEBUG = 0,
- INFO = 1,
+
+ /**
+ * A message which might provide additional information to the user.
+ */
+ NOTE = 1,
+
+ /**
+ * A message which warns of possible mistakes by the user which might not be
+ * actual errors but may lead to unintended behaviour.
+ */
WARNING = 2,
+
+ /**
+ * An error occurred while processing, however program execution continues,
+ * trying to deal with the error situation (graceful degradation). However,
+ * messages with this severity may be followed up by fatal errors.
+ */
ERROR = 3,
+
+ /**
+ * A fatal error occurred. Program execution cannot continue.
+ */
FATAL_ERROR = 4
};
-struct LogMessage {
- Severity severity;
- std::string msg;
- std::string file;
- int line;
- int column;
-
- LogMessage(Severity severity, std::string msg, std::string file, int line,
- int column)
- : severity(severity),
- msg(std::move(msg)),
- file(std::move(file)),
- line(line),
- column(column){};
-};
+#ifdef NDEBUG
+static constexpr Severity DEFAULT_MIN_SEVERITY = Severity::NOTE;
+#else
+static constexpr Severity DEFAULT_MIN_SEVERITY = Severity::DEBUG;
+#endif
+/**
+ * The Logger class is the base class the individual logging systems should
+ * derive from. It provides a simple interface for logging errors, warnings and
+ * notes and filters these according to the set minimum severity. Additionally
+ * a stack of file names is maintained in order to allow simple descent into
+ * included files. Note however, that this base Logger class simply discards the
+ * incomming log messages. Use one of the derived classes to actually handle the
+ * log messages.
+ */
class Logger {
+public:
+ /**
+ * The message struct represents a single log message and all information
+ * attached to it.
+ */
+ struct Message {
+ /**
+ * Severity of the log message.
+ */
+ Severity severity;
+
+ /**
+ * Actual log message.
+ */
+ std::string msg;
+
+ /**
+ * Refers to the file which provides the context for this error message.
+ * May be empty.
+ */
+ std::string file;
+
+ /**
+ * Line in the above file the error message refers to. Ignored if
+ * smaller than zero.
+ */
+ int line;
+
+ /**
+ * Column in the above file the error message refers to. Ignored if
+ * smaller than zero.
+ */
+ int column;
+
+ /**
+ * Constructor of the Message struct.
+ *
+ * @param severity describes the message severity.
+ * @param msg contains the actual message.
+ * @param file provides the context the message refers to. May be empty.
+ * @param line is the line in the above file the message refers to.
+ * @param column is the column in the above file the message refers to.
+ */
+ Message(Severity severity, std::string msg, std::string file, int line,
+ int column)
+ : severity(severity),
+ msg(std::move(msg)),
+ file(std::move(file)),
+ line(line),
+ column(column){};
+
+ /**
+ * Returns true if the file string is set.
+ *
+ * @return true if the file string is set.
+ */
+ bool hasFile() const { return !file.empty(); }
+
+ /**
+ * Returns true if the line is set.
+ *
+ * @return true if the line number is a non-negative integer.
+ */
+ bool hasLine() const { return line >= 0; }
+
+ /**
+ * Returns true if column and line are set (since a column has no
+ * significance without a line number).
+ *
+ * @return true if line number and column number are non-negative
+ * integers.
+ */
+ bool hasColumn() const { return hasLine() && column >= 0; }
+ };
+
private:
- Severity maxLogSeverity = Severity::DEBUG;
- std::string curFile;
+ /**
+ * Minimum severity a log message should have before it is discarded.
+ */
+ Severity minSeverity;
+
+ /**
+ * Maximum encountered log message severity.
+ */
+ Severity maxEncounteredSeverity;
+
+ /**
+ * Stack containing the current file names that have been processed.
+ */
+ std::stack<std::string> filenameStack;
protected:
- virtual void logMessage(const LogMessage &msg){};
+ /**
+ * Function to be overriden by child classes to actually display or store
+ * the messages. The default implementation just discards all incomming
+ * messages.
+ *
+ * @param msg is an instance of the Message struct containing the data that
+ * should be logged.
+ */
+ virtual void process(const Message &msg){};
public:
- Logger(){};
+ /**
+ * Constructor of the Logger class.
+ *
+ * @param minSeverity is the minimum severity a log message should have.
+ * Messages below this severity are discarded.
+ */
+ Logger(Severity minSeverity = DEFAULT_MIN_SEVERITY)
+ : minSeverity(minSeverity), maxEncounteredSeverity(Severity::DEBUG)
+ {
+ }
Logger(const Logger &) = delete;
- virtual ~Logger();
+ /**
+ * Virtual destructor.
+ */
+ virtual ~Logger(){};
+ /**
+ * Logs the given message. Most generic log function.
+ *
+ * @param severity is the severity of the log message.
+ * @param msg is the actual log message.
+ * @param file is the name of the file the message refers to. May be empty.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
void log(Severity severity, const std::string &msg, const std::string &file,
- int line = -1, int column = -1)
- {
- // Copy the current severity level
- if (static_cast<int>(severity) > static_cast<int>(maxSeverity)) {
- maxSeverity = severity;
- }
-
- // Call the actual log message function
- logMessage(LogMessage{severity, msg, file, line, column});
- }
+ int line = -1, int column = -1);
+ /**
+ * Logs the given message. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param severity is the severity of the log message.
+ * @param msg is the actual log message.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
void log(Severity severity, const std::string &msg, int line = -1,
int column = -1)
{
- log(severity, msg, curFile, line, column);
+ log(severity, msg, currentFilename(), line, column);
+ }
+
+ /**
+ * Logs the given loggable exception.
+ *
+ * @param ex is the exception that should be logged.
+ */
+ void log(const LoggableException &ex)
+ {
+ log(ex.fatal ? Severity::FATAL_ERROR : Severity::ERROR, ex.msg,
+ ex.file.empty() ? currentFilename() : ex.file, ex.line, ex.column);
}
+ /**
+ * Logs a debug message. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
void debug(const std::string &msg, int line = -1, int column = -1)
{
log(Severity::DEBUG, msg, line, column);
}
- void info(const std::string &msg, int line = -1, int column = -1)
+ /**
+ * Logs a note. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
+ void note(const std::string &msg, int line = -1, int column = -1)
{
- log(Severity::INFO, msg, line, column);
+ log(Severity::NOTE, msg, line, column);
}
+ /**
+ * Logs a warning. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
void warning(const std::string &msg, int line = -1, int column = -1)
{
log(Severity::WARNING, msg, line, column);
}
+ /**
+ * Logs an error message. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
void error(const std::string &msg, int line = -1, int column = -1)
{
log(Severity::ERROR, msg, line, column);
}
+ /**
+ * Logs a fatal error. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
void fatalError(const std::string &msg, int line = -1, int column = -1)
{
log(Severity::FATAL_ERROR, msg, line, column);
}
- Severity getMaxSeverity() { return maxSeverity; }
+ /**
+ * Pushes a new file name onto the internal filename stack.
+ *
+ * @param name is the name of the file that should be added to the filename
+ * stack.
+ * @return the size of the filename stack. This number can be passed to the
+ * "unwindFilenameStack" method in order to return the stack to state it was
+ * in after this function has been called.
+ */
+ unsigned int pushFilename(const std::string &name);
+
+ /**
+ * Pops the filename from the internal filename stack.
+ *
+ * @return the current size of the filename stack.
+ */
+ unsigned int popFilename();
+
+ /**
+ * Pops elements from the filename stack while it has more elements than
+ * the given number and the stack is non-empty.
+ *
+ * @param pos is the position the filename stack should be unwound to. Use
+ * a number returned by pushFilename.
+ */
+ void unwindFilenameStack(unsigned int pos);
+
+ /**
+ * Returns the topmost filename from the internal filename stack.
+ *
+ * @return the topmost filename from the filename stack or an empty string
+ * if the filename stack is empty.
+ */
+ std::string currentFilename()
+ {
+ return filenameStack.empty() ? std::string{} : filenameStack.top();
+ }
+
+ /**
+ * Returns the maximum severity that was encountered by the Logger but at
+ * least Severity::DEBUG.
+ *
+ * @return the severity of the most severe log message but at least
+ * Severity::DEBUG.
+ */
+ Severity getMaxEncounteredSeverity() { return maxEncounteredSeverity; }
+
+ /**
+ * Returns the minimum severity. Messages with a smaller severity are
+ * discarded.
+ *
+ * @return the minimum severity.
+ */
+ Severity getMinSeverity() { return minSeverity; }
+
+ /**
+ * Sets the minimum severity. Messages with a smaller severity will be
+ * discarded. Only new messages will be filtered according to the new value.
+ *
+ * @param severity is the minimum severity for new log messages.
+ */
+ void setMinSeverity(Severity severity) { minSeverity = severity; }
};
-class StreamLogger {
+/**
+ * Class extending the Logger class and printing the log messages to the given
+ * stream.
+ */
+class TerminalLogger : public Logger {
private:
+ /**
+ * Reference to the target output stream.
+ */
std::ostream &os;
+
+ /**
+ * If true, the TerminalLogger will use colors to make the log messages
+ * prettier.
+ */
bool useColor;
protected:
- void logMessage(const LogMessage &msg) override;
+ /**
+ * Implements the process function and logs the messages to the output.
+ */
+ void process(const Message &msg) override;
public:
- StreamLogger(std::ostream &os, bool useColor = false)
- : os(os), useColor(useColor)
+ /**
+ * Constructor of the TerminalLogger class.
+ *
+ * @param os is the output stream the log messages should be logged to.
+ * Should be set to std::cerr in most cases.
+ * @param useColor if true, the TerminalLogger class will do its best to
+ * use ANSI/VT100 control sequences for colored log messages.
+ * @param minSeverity is the minimum severity below which log messages are
+ * discarded.
+ */
+ TerminalLogger(std::ostream &os, bool useColor = false,
+ Severity minSeverity = DEFAULT_MIN_SEVERITY)
+ : Logger(minSeverity), os(os), useColor(useColor)
{
}
};