https://github.com/zhehaoli1999/DiffFR
Raw File
Tip revision: f7dc063b7f3c0330f345c5d52454c52c1f6f1f26 authored by Li Zhehao on 31 March 2024, 14:19:09 UTC
update readme to fix typo
Tip revision: f7dc063
Logger.h
#ifndef __Logger_h__
#define __Logger_h__

#include <sstream>
#include <iostream>
#include <fstream>
#include <ctime>
#include <iomanip>
#include <vector>
#include <memory>


namespace Utilities
{
	enum LogLevel { DEBUG=0, INFO, WARN, ERR };

	class LogSink
	{
	protected: 
		LogLevel m_minLevel;
	public:
		LogSink(const LogLevel minLevel) : m_minLevel(minLevel) {}
		virtual ~LogSink() {}
		virtual void write(const LogLevel level, const std::string &str) = 0;
	};

	class ConsoleSink : public LogSink
	{
	public:
		ConsoleSink(const LogLevel minLevel) : LogSink(minLevel) {}

		virtual void write(const LogLevel level, const std::string &str)
		{
			if (level < m_minLevel)
				return;

// 			if (level == LogLevel::INFO)
// 				std::cout << "Info: ";
// 			else 
			if (level == LogLevel::WARN)
				std::cout << "Warning: ";
			else if (level == LogLevel::ERR)
				std::cerr << "Error: ";

			std::cout << str << std::endl;
		}
	};

	class FileSink : public LogSink
	{
	protected: 
		std::ofstream m_file;

	public:
		FileSink(const LogLevel minLevel, const std::string &fileName)
			: LogSink(minLevel)
		{
			m_file.open(fileName.c_str(), std::ios::out);
			if (m_file.fail())
				std::cerr << "Failed to open file: " << fileName << "\n";
		}

		virtual ~FileSink()
		{
			m_file.close();
		}

		virtual void write(const LogLevel level, const std::string &str)
		{
			if (level < m_minLevel)
				return;

			// print time
			time_t t = time(0);   // get time now
			struct tm * now = localtime(&t);
			m_file << "[" << (now->tm_year + 1900) << '-' 
					<< std::setfill('0') << std::setw(2)
					<< (now->tm_mon + 1) << '-'
					<< std::setfill('0') << std::setw(2)
					<< now->tm_mday << " "
					<< std::setfill('0') << std::setw(2) 
					<< now->tm_hour << ":" 
					<< std::setfill('0') << std::setw(2) 
					<< now->tm_min << ":" 
					<< std::setfill('0') 
					<< std::setw(2) << now->tm_sec << "] ";

			// print level
			if (level == LogLevel::DEBUG)
				m_file << "Debug:   ";
			else if (level == LogLevel::INFO)
				m_file << "Info:    ";
			else if (level == LogLevel::WARN)
				m_file << "Warning: ";
			else if (level == LogLevel::ERR)
				m_file << "Error:   ";

			m_file << str << std::endl;
			m_file.flush();
		}
	};

	class Logger
	{
	public: 
		Logger() { m_active = true; }
		~Logger() 
		{ 
			m_sinks.clear();  
		}

	protected:
		std::vector<std::unique_ptr<LogSink>> m_sinks;
		bool m_active;

	public:
		// Todo: format

		void addSink(std::unique_ptr<LogSink> sink)
		{
			m_sinks.push_back(std::move(sink));
		}

		void write(const LogLevel level, const std::string &str)
		{
			if (!m_active)
				return;
			for (unsigned int i = 0; i < m_sinks.size(); i++)
				m_sinks[i]->write(level, str);
		}

		void noConsoleWrite(const LogLevel level, const std::string &str)
		{
			if (!m_active)
				return;
			for (unsigned int i = 0; i < m_sinks.size(); i++)
			{
				if (dynamic_cast<ConsoleSink *>(m_sinks[i].get()))
					continue;
				m_sinks[i]->write(level, str);
			}
		}

		void activate(const bool b) { m_active = b; }
	};

	class LogStream
	{
	public:
		LogStream(Logger *logger, const LogLevel level) : m_logger(logger), m_level(level) {}

		template <typename T>
		LogStream& operator<<(T const & value)
		{
			m_buffer << value;
			return *this;
		}

		~LogStream() { m_logger->write(m_level, m_buffer.str()); }

	protected:
		LogLevel m_level;
		Logger *m_logger;
		std::ostringstream m_buffer;
	};

	class NoConsoleLogStream
	{
	public:
		NoConsoleLogStream(Logger *logger, const LogLevel level) : m_logger(logger), m_level(level) {}

		template <typename T>
		NoConsoleLogStream& operator<<(T const & value)
		{
			m_buffer << value;
			return *this;
		}

		~NoConsoleLogStream() { m_logger->noConsoleWrite(m_level, m_buffer.str()); }

	protected:
		LogLevel m_level;
		Logger *m_logger;
		std::ostringstream m_buffer;
	};

	extern Utilities::Logger logger;

	#define LOG_DEBUG Utilities::LogStream(&Utilities::logger, Utilities::LogLevel::DEBUG)
	#define LOG_INFO Utilities::LogStream(&Utilities::logger, Utilities::LogLevel::INFO)
	#define LOG_WARN Utilities::LogStream(&Utilities::logger, Utilities::LogLevel::WARN)
	#define LOG_ERR Utilities::LogStream(&Utilities::logger, Utilities::LogLevel::ERR)
	#define INIT_LOGGING Utilities::Logger Utilities::logger;

	#define NO_CONSOLE_LOG_DEBUG Utilities::NoConsoleLogStream(&Utilities::logger, Utilities::LogLevel::DEBUG)
	#define NO_CONSOLE_LOG_INFO Utilities::NoConsoleLogStream(&Utilities::logger, Utilities::LogLevel::INFO)
	#define NO_CONSOLE_LOG_WARN Utilities::NoConsoleLogStream(&Utilities::logger, Utilities::LogLevel::WARN)
	#define NO_CONSOLE_LOG_ERR Utilities::NoConsoleLogStream(&Utilities::logger, Utilities::LogLevel::ERR)
}


#endif
back to top