diff --git a/CMakeLists.txt b/CMakeLists.txt index 060dd37..9cbd01e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable(FlashMQ rwlockguard.cpp retainedmessage.cpp cirbuf.cpp + logger.cpp ) target_link_libraries(FlashMQ pthread) diff --git a/FlashMQTests/FlashMQTests.pro b/FlashMQTests/FlashMQTests.pro index 1213ae3..281e8fc 100644 --- a/FlashMQTests/FlashMQTests.pro +++ b/FlashMQTests/FlashMQTests.pro @@ -25,6 +25,7 @@ SOURCES += tst_maintests.cpp \ ../threaddata.cpp \ ../types.cpp \ ../utils.cpp \ + ../logger.cpp \ mainappthread.cpp \ twoclienttestcontext.cpp @@ -42,5 +43,6 @@ HEADERS += \ ../threaddata.h \ ../types.h \ ../utils.h \ + ../logger.h \ mainappthread.h \ twoclienttestcontext.h diff --git a/logger.cpp b/logger.cpp new file mode 100644 index 0000000..5a534df --- /dev/null +++ b/logger.cpp @@ -0,0 +1,79 @@ +#include "logger.h" +#include +#include +#include + +Logger *Logger::instance = nullptr; + +Logger::Logger() +{ + +} + +std::string Logger::getLogLevelString(int level) const +{ + switch (level) + { + case LOG_NONE: + return "NONE"; + case LOG_INFO: + return "INFO"; + case LOG_NOTICE: + return "NOTICE"; + case LOG_WARNING: + return "WARNING"; + case LOG_ERR: + return "ERROR"; + case LOG_DEBUG: + return "DEBUG"; + default: + return "UNKNOWN LOG LEVEL"; + } +} + +Logger *Logger::getInstance() +{ + if (instance == nullptr) + instance = new Logger(); + return instance; +} + +void Logger::logf(int level, const char *str, ...) +{ + if (level > curLogLevel) + return; + + std::lock_guard locker(logMutex); + + time_t time = std::time(nullptr); + struct tm tm = *std::localtime(&time); + std::ostringstream oss; + + std::string str_(str); + oss << "[" << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << "] [" << getLogLevelString(level) << "] " << str_; + oss.flush(); + const std::string s = oss.str(); + const char *logfmtstring = s.c_str(); + + va_list valist; + va_start(valist, str); + if (this->file) + { + vfprintf(this->file, logfmtstring, valist); + fprintf(this->file, "\n"); + fflush(this->file); + } + else + { +#ifdef TESTING + vfprintf(stderr, logfmtstring, valist); // the stdout interfers with Qt test XML output, so using stderr. + fprintf(stderr, "\n"); + fflush(stderr); +#else + vfprintf(stdout, logfmtstring, valist); + fprintf(stdout, "\n"); + fflush(stdout); +#endif + } + va_end(valist); +} diff --git a/logger.h b/logger.h new file mode 100644 index 0000000..9d88422 --- /dev/null +++ b/logger.h @@ -0,0 +1,32 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#include +#include +#include + +// Compatible with Mosquitto, for auth plugin compatability. +#define LOG_NONE 0x00 +#define LOG_INFO 0x01 +#define LOG_NOTICE 0x02 +#define LOG_WARNING 0x04 +#define LOG_ERR 0x08 +#define LOG_DEBUG 0x10 + +class Logger +{ + static Logger *instance; + int curLogLevel = LOG_DEBUG; + std::mutex logMutex; + FILE *file = nullptr; + + Logger(); + std::string getLogLevelString(int level) const; + +public: + static Logger *getInstance(); + void logf(int level, const char *str, ...); + +}; + +#endif // LOGGER_H