diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index bfe9e31..ef37f43 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -36,6 +36,8 @@ #include "RepeaterProtocolHandlerFactory.h" #include "XLXHostsFileDownloader.h" #include "Log.h" +#include "LogFileTarget.h" +#include "LogConsoleTarget.h" int main(int argc, char *argv[]) { @@ -100,7 +102,8 @@ bool CDStarGatewayApp::createThread() TLog log; config.getLog(log); - CLog::initialize(log.logDir + "dstargateway.log", LS_INFO, true); + CLog::addTarget(new CLogConsoleTarget(LS_INFO)); + CLog::addTarget(new CLogFileTarget(LS_INFO, log.logDir, true)); Tpaths paths; config.getPaths(paths); diff --git a/Log.cpp b/Log.cpp index c0404fb..c89ac81 100644 --- a/Log.cpp +++ b/Log.cpp @@ -18,18 +18,40 @@ */ #include +#include +#include #include "Log.h" +#include "LogConsoleTarget.h" -LOG_SEVERITY CLog::m_level = LS_INFO; -std::string CLog::m_file = ""; -bool CLog::m_logToConsole = true; +LOG_SEVERITY CLog::m_level(LS_DEBUG); +bool CLog::m_addedTargets(false); +std::recursive_mutex CLog::m_targetsMutex; +std::vector CLog::m_targets = { new CLogConsoleTarget(LS_DEBUG) }; -void CLog::initialize(const std::string& logfile, LOG_SEVERITY logLevel, bool logToConsole) +void CLog::addTarget(CLogTarget* target) { - m_file = logfile; - m_level = logLevel; - m_logToConsole = logToConsole; + assert(target != nullptr); + + std::lock_guard lockTargets(m_targetsMutex); + + if(!m_addedTargets) { + // It is the first time we add an external target, clear the default one(s) + m_addedTargets = true; + finalise(); + } + + m_targets.push_back(target); +} + +void CLog::finalise() +{ + std::lock_guard lockTargets(m_targetsMutex); + for(auto target : m_targets) { + delete target; + } + + m_targets.clear(); } void CLog::getTimeStamp(std::string & s) @@ -39,4 +61,4 @@ void CLog::getTimeStamp(std::string & s) char buf[64]; std::strftime(buf, 42, "%Y-%m-%d %T", now_tm); s = std::string(buf); -} \ No newline at end of file +} diff --git a/Log.h b/Log.h index 0e99426..c74eb1f 100644 --- a/Log.h +++ b/Log.h @@ -20,64 +20,26 @@ #pragma once #include -#include -#include -#include -#include +#include #include +#include +#include #include "StringUtils.h" - -enum LOG_SEVERITY { - LS_TRACE = 1, - LS_DEBUG, - LS_INFO, - LS_WARNING, - LS_ERROR, - LS_FATAL -}; +#include "LogTarget.h" class CLog { private: static LOG_SEVERITY m_level; - static std::string m_file; - static bool m_logToConsole; + static std::vector m_targets; + static bool m_addedTargets; + static std::recursive_mutex m_targetsMutex; static void getTimeStamp(std::string & s); -public: - - static void initialize(const std::string& logfile, LOG_SEVERITY logLevel, bool logToConsole); - - template static void logDebug(const std::string & f, Args... args) - { - log(LS_DEBUG, f, args...); - } - - template static void logInfo(const std::string & f, Args... args) - { - log(LS_INFO, f, args...); - } - - template static void logWarning(const std::string & f, Args... args) - { - log(LS_WARNING, f, args...); - } - - template static void logError(const std::string & f, Args... args) - { - log(LS_ERROR, f, args...); - } - - template static void logFatal(const std::string & f, Args... args) - { - log(LS_FATAL, f, args...); - } - - template static void log(LOG_SEVERITY severity, const std::string & f, Args... args) + template static void formatLogMessage(std::string& output, LOG_SEVERITY severity, const std::string & f, Args... args) { - if(severity >= CLog::m_level || CLog::m_file.empty()) { std::string severityStr; switch (severity) { @@ -110,14 +72,48 @@ public: std::stringstream s; s << "[" << timeUtc << "] [" << severityStr << "] " << message << std::endl; - if(CLog::m_logToConsole || CLog::m_file.empty()) - std::cout << s.str(); + output = s.str(); + } + +public: + + static void addTarget(CLogTarget * target); + static void finalise(); + + template static void logDebug(const std::string & f, Args... args) + { + log(LS_DEBUG, f, args...); + } + + template static void logInfo(const std::string & f, Args... args) + { + log(LS_INFO, f, args...); + } + + template static void logWarning(const std::string & f, Args... args) + { + log(LS_WARNING, f, args...); + } + + template static void logError(const std::string & f, Args... args) + { + log(LS_ERROR, f, args...); + } + + template static void logFatal(const std::string & f, Args... args) + { + log(LS_FATAL, f, args...); + } + + template static void log(LOG_SEVERITY severity, const std::string & f, Args... args) + { + std::lock_guard lockTarget(m_targetsMutex); - std::ofstream file; - file.open(CLog::m_file, std::ios::app); - if(file.is_open()) { - file << s.str(); - file.close(); + std::string msg; + for(auto target : m_targets) { + if(target->getLevel() >= CLog::m_level) { + if(msg.empty()) formatLogMessage(msg, severity, f, args...); + target->printLog(msg); } } } diff --git a/LogConsoleTarget.cpp b/LogConsoleTarget.cpp new file mode 100644 index 0000000..78cdabc --- /dev/null +++ b/LogConsoleTarget.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include + +#include "LogConsoleTarget.h" + +CLogConsoleTarget::CLogConsoleTarget(LOG_SEVERITY logLevel) : +CLogTarget(logLevel) +{ + +} + +void CLogConsoleTarget::printLogInt(const std::string& msg) +{ + std::cout << msg; +} \ No newline at end of file diff --git a/LogConsoleTarget.h b/LogConsoleTarget.h new file mode 100644 index 0000000..7ef2da8 --- /dev/null +++ b/LogConsoleTarget.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#pragma once + +#include "LogTarget.h" + +class CLogConsoleTarget : public CLogTarget +{ +public: + CLogConsoleTarget(LOG_SEVERITY logLevel); + +protected: + virtual void printLogInt(const std::string& msg); +}; \ No newline at end of file diff --git a/LogFileTarget.cpp b/LogFileTarget.cpp new file mode 100644 index 0000000..a44dd35 --- /dev/null +++ b/LogFileTarget.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include + +#include "LogFileTarget.h" + +CLogFileTarget::CLogFileTarget(LOG_SEVERITY logLevel, const std::string & dir, bool rotate) : +CLogTarget(logLevel), +m_dir(dir), +m_rotate(rotate) +{ + +} + +void CLogFileTarget::printLogInt(const std::string& msg) +{ + // construct filename + std::string fileName(m_dir); + if(fileName[fileName.length() - 1U] != '/') fileName.push_back('/'); + fileName.append("dstargateway"); + + if(m_rotate) { + std::time_t now = std::time(0); + std::tm* now_tm = std::gmtime(&now); + char buf[64]; + std::strftime(buf, 42, "-%Y-%m-%d", now_tm); + fileName.append(std::string(buf)); + } + fileName.append(".log"); + + std::ofstream file; + file.open(fileName, std::ios::app); + if(file.is_open()) { + file << msg; + file.close(); + } +} \ No newline at end of file diff --git a/LogFileTarget.h b/LogFileTarget.h new file mode 100644 index 0000000..2a8ad1d --- /dev/null +++ b/LogFileTarget.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#pragma once + +#include + +#include "LogTarget.h" + +class CLogFileTarget : public CLogTarget +{ +public: + CLogFileTarget(LOG_SEVERITY logLevel, const std::string& directory, bool rotate); + +protected: + virtual void printLogInt(const std::string& msg); + +private: + std::string m_dir; + bool m_rotate; +}; \ No newline at end of file diff --git a/LogTarget.cpp b/LogTarget.cpp new file mode 100644 index 0000000..ea60270 --- /dev/null +++ b/LogTarget.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "LogTarget.h" + +CLogTarget::CLogTarget(LOG_SEVERITY logLevel) : +m_logLevel(logLevel) +{ + +} + +CLogTarget::~CLogTarget() +{ + +} + +void CLogTarget::printLog(const std::string& msg) +{ + printLogInt(msg); +} \ No newline at end of file diff --git a/LogTarget.h b/LogTarget.h new file mode 100644 index 0000000..427c707 --- /dev/null +++ b/LogTarget.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#pragma once + +#include + +enum LOG_SEVERITY { + LS_TRACE = 1, + LS_DEBUG, + LS_INFO, + LS_WARNING, + LS_ERROR, + LS_FATAL +}; + +class CLogTarget +{ +public: + CLogTarget(LOG_SEVERITY logLevel); + virtual ~CLogTarget(); + void printLog(const std::string& msg); + LOG_SEVERITY getLevel() { return m_logLevel; } + +protected: + virtual void printLogInt(const std::string& msg) = 0; + +private: + LOG_SEVERITY m_logLevel; +}; \ No newline at end of file