Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 113 additions & 3 deletions libs/logger/include/Logger.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,122 @@
#pragma once

#include <filesystem>
#include <fstream>
#include <memory>
#include <optional>
#include <string>
#include <string_view>

#define COLOR_RESET "\033[0m"
#define COLOR_FATAL "\033[38;5;208m"
#define COLOR_ERROR "\033[38;5;160m"
#define COLOR_WARNING "\033[38;5;226m"
#define COLOR_INFO "\033[38;5;13m"
#define COLOR_DEBUG "\033[38;5;21m"
#define COLOR_GRAY "\033[38;5;232m"

namespace Logger
{

void Log(const std::string& message);
/**
* @brief Enum describing the severity of the log.
*/
enum class LogType
{
Fatal,
Error,
Warning,
Info,
Debug,
};

/**
* @brief Enum describing how much to log.
*
* @note Debug: Logs all log types.
* Normal: Logs everything except debug.
* Sparse: Only logs Error, Fatal and warnings.
* None: self explanatory.
*/
enum class LogLevel
{
None,
Sparse,
Normal,
Debug,
};

/**
* @brief Singleton logger for a unified output.
*
* @note Debug output will be logged onto the stdout, other logs will be sent to the syslog.
*/
class LogInterface
{
const bool _enableLoggingStdout;
LogLevel _logLevel;

/**
* @brief Hidden default constructor.
*/
LogInterface(const char* processName, LogLevel logLevel, bool enableLoggingStdout);

/**
* @brief Deleted constructor and operator.
*/
LogInterface(const LogInterface&) = delete;
std::unique_ptr<LogInterface>& operator=(const LogInterface&) = delete;

/**
* @brief Returns true or false based on the given log leven and how the Interface is
* initialzed.
*/
bool CanLogLogWithSetLogLevel(LogType logType);

/**
* @brief Returns a string literal containing the color meant for the given LogType.
*/
constexpr const char* GetLogColor(LogType LogType);

public:
/**
* @brief Destructor.
*/
~LogInterface();

/**
* @return The singleton instance.
*/
static std::unique_ptr<LogInterface>& GetInstance();

/**
* @brief Initializes the instance, logging without initializing is not possible.
*
* @param processName The name of the process.
*
* @param logLevel The level at which output will be shown,
* see the LogLevel enum for more details.
*
* @param enableLoggingStdout When enabled, will log the non-debug messages to the
* stdout as well as the syslog.
*/
static void Initialize(const char* processName, LogLevel logLevel, bool enableLoggingStdout);

/**
* @brief Function used for logging a message in the format for the LogType.
*/
void Log(const char* logMessage, const LogType logType);
};

}
} /* namespace Logger */

#define LOG_DEBUG(logMessage) Logger::Log(logMessage);
#define LOG_ERROR(logMessage) \
Logger::LogInterface::GetInstance()->Log(logMessage, Logger::LogType::Error);
#define LOG_FATAL(logMessage) \
Logger::LogInterface::GetInstance()->Log(logMessage, Logger::LogType::Fatal);
#define LOG_WARNING(logMessage) \
Logger::LogInterface::GetInstance()->Log(logMessage, Logger::LogType::Warning);
#define LOG_INFO(logMessage) \
Logger::LogInterface::GetInstance()->Log(logMessage, Logger::LogType::Info);
#define LOG_DEBUG(logMessage) \
Logger::LogInterface::GetInstance()->Log(logMessage, Logger::LogType::Debug);
104 changes: 102 additions & 2 deletions libs/logger/src/Logger.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,110 @@
#include <Logger.hpp>
#include <iostream>
#include <syslog.h>

namespace Logger
{
void Log(const std::string& message)
LogInterface::LogInterface(const char* processName, LogLevel logLevel, bool enableLoggingStdout)
: _logLevel(logLevel), _enableLoggingStdout(enableLoggingStdout)
{
std::cout << message << std::endl;
openlog(processName, LOG_NOWAIT, LOG_NOWAIT);
}

LogInterface::~LogInterface()
{
try {
closelog();
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
}
}

std::unique_ptr<LogInterface>& LogInterface::GetInstance()
{
static std::unique_ptr<LogInterface> logger;
return logger;
}

void LogInterface::Initialize(const char* processName, LogLevel logLevel, bool enableLoggingStdout)
{
auto& logger = GetInstance();

if (logger != nullptr) {
throw std::runtime_error("Logger is already initialized.");
}

logger =
std::unique_ptr<LogInterface>(new LogInterface(processName, logLevel, enableLoggingStdout));
}

bool LogInterface::CanLogLogWithSetLogLevel(LogType logType)
{
switch (_logLevel) {
case LogLevel::None:
return false;
case LogLevel::Sparse:
return (logType != LogType::Debug && logType != LogType::Info);
case LogLevel::Normal:
return (logType != LogType::Debug);
case LogLevel::Debug:
return true;
default:
return false;
}
}

constexpr const char* LogInterface::GetLogColor(LogType LogType)
{
switch (LogType) {
case LogType::Fatal:
return COLOR_FATAL;
case LogType::Error:
return COLOR_ERROR;
case LogType::Warning:
return COLOR_WARNING;
case LogType::Info:
return COLOR_INFO;
case LogType::Debug:
return COLOR_DEBUG;
default:
return "";
}
}

void LogInterface::Log(const char* logMessage, const LogType logType)
{
if (!CanLogLogWithSetLogLevel(logType)) {
return;
}

if (_enableLoggingStdout || logType == LogType::Debug) {
std::cout << GetLogColor(logType) << logMessage << COLOR_RESET << "\n";
}

try {
switch (logType) {
case LogType::Fatal:
syslog(LOG_DAEMON | LOG_ERR, "%s", logMessage);
break;
case LogType::Error:
syslog(LOG_DAEMON | LOG_ERR, "%s", logMessage);
break;
case LogType::Warning:
syslog(LOG_DAEMON | LOG_WARNING, "%s", logMessage);
break;
case LogType::Info:
syslog(LOG_DAEMON | LOG_INFO, "%s", logMessage);
break;
case LogType::Debug:
syslog(LOG_DAEMON | LOG_DEBUG, "%s", logMessage);
break;
default:
break;
}
} catch (const std::exception& e) {
std::cerr << GetLogColor(LogType::Error) << "Error using syslog: " << e.what()
<< COLOR_RESET "\n";
}
}

} // namespace Logger
9 changes: 6 additions & 3 deletions taskmasterd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ add_executable(${EXECUTABLE_NAME})
file(GLOB_RECURSE SOURCES "src/*.cpp")

# Add compile options
set(COMPILE_OPTIONS -Wall -Wextra -Werror -pedantic -O3 -march=native)
add_compile_options(${COMPILE_OPTIONS})
set(COMPILE_OPTIONS -Wall -Wextra -Werror -pedantic -O3 -march=native -g -DPROGRAM_NAME="${EXECUTABLE_NAME}")
target_compile_options(${EXECUTABLE_NAME} PRIVATE ${COMPILE_OPTIONS})

# Enable fsanitize:
# target_link_options(${EXECUTABLE_NAME} PRIVATE -fsanitize=address)

# Link to the needed libs
target_link_libraries(${EXECUTABLE_NAME} PRIVATE logger)

# add executable sources
target_sources(${EXECUTABLE_NAME} PRIVATE ${SOURCES} main.cpp)
target_sources(${EXECUTABLE_NAME} PRIVATE ${SOURCES})

# include header directory
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..)
Expand Down
19 changes: 13 additions & 6 deletions taskmasterd/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
#include <logger/include/Logger.hpp>
#include <taskmasterd/include/example.hpp>
#include <iostream>

#ifndef PROGRAM_NAME
#define PROGRAM_NAME "taskmasterd"
#endif

int main(int argc, char** argv)
{
testFunc();
(void) argc;
(void) argv;
Logger::LogInterface::Initialize(PROGRAM_NAME, Logger::LogLevel::Debug, true);

if (argc > 2) {
LOG_DEBUG("argc > 2")
return 1;
}
LOG_DEBUG("Debug log")
LOG_ERROR("Error log")
LOG_FATAL("Fatal log")
LOG_WARNING("Warning log")
LOG_INFO("Info log")

LOG_DEBUG("argc <= 2")
return 0;
}