/ libi2pd / Log.h
Log.h
  1  /*
  2  * Copyright (c) 2013-2024, The PurpleI2P Project
  3  *
  4  * This file is part of Purple i2pd project and licensed under BSD3
  5  *
  6  * See full license text in LICENSE file at top of project tree
  7  */
  8  
  9  #ifndef LOG_H__
 10  #define LOG_H__
 11  
 12  #include <ctime>
 13  #include <string>
 14  #include <iostream>
 15  #include <fstream>
 16  #include <sstream>
 17  #include <chrono>
 18  #include <memory>
 19  #include <thread>
 20  #include <functional>
 21  #include "Queue.h"
 22  
 23  #ifndef _WIN32
 24  #include <syslog.h>
 25  #endif
 26  
 27  enum LogLevel
 28  {
 29  	eLogNone = 0,
 30  	eLogCritical,
 31  	eLogError,
 32  	eLogWarning,
 33  	eLogInfo,
 34  	eLogDebug,
 35  	eNumLogLevels
 36  };
 37  
 38  enum LogType {
 39  	eLogStdout = 0,
 40  	eLogStream,
 41  	eLogFile,
 42  #ifndef _WIN32
 43  	eLogSyslog,
 44  #endif
 45  };
 46  
 47  namespace i2p {
 48  namespace log {
 49  
 50  	struct LogMsg; /* forward declaration */
 51  
 52  	class Log
 53  	{
 54  		private:
 55  
 56  			enum LogType m_Destination;
 57  			enum LogLevel m_MinLevel;
 58  			std::shared_ptr<std::ostream> m_LogStream;
 59  			std::string m_Logfile;
 60  			std::time_t m_LastTimestamp;
 61  			char m_LastDateTime[64];
 62  			i2p::util::Queue<std::shared_ptr<LogMsg> > m_Queue;
 63  			bool m_HasColors;
 64  			std::string m_TimeFormat;
 65  			volatile bool m_IsRunning;
 66  			std::thread * m_Thread;
 67  
 68  		private:
 69  
 70  			/** prevent making copies */
 71  			Log (const Log &);
 72  			const Log& operator=(const Log&);
 73  
 74  			void Run ();
 75  			void Process (std::shared_ptr<LogMsg> msg);
 76  
 77  			/**
 78  			 * @brief Makes formatted string from unix timestamp
 79  			 * @param ts Second since epoch
 80  			 *
 81  			 * This function internally caches the result for last provided value
 82  			 */
 83  			const char * TimeAsString(std::time_t ts);
 84  
 85  		public:
 86  
 87  			Log ();
 88  			~Log ();
 89  
 90  			LogType GetLogType () const { return m_Destination; };
 91  			LogLevel GetLogLevel () const { return m_MinLevel; };
 92  
 93  			void Start ();
 94  			void Stop ();
 95  
 96  			/**
 97  			 * @brief Sets minimal allowed level for log messages
 98  			 * @param level String with wanted minimal msg level
 99  			 */
100  			void SetLogLevel (const std::string& level);
101  
102  			/**
103  			 * @brief Sets log destination to logfile
104  			 * @param path Path to logfile
105  			 */
106  			void SendTo (const std::string &path);
107  
108  			/**
109  			 * @brief Sets log destination to given output stream
110  			 * @param os Output stream
111  			 */
112  			void SendTo (std::shared_ptr<std::ostream> os);
113  
114  			/**
115  			 * @brief Sets format for timestamps in log
116  			 * @param format String with timestamp format
117  			 */
118  			void SetTimeFormat (std::string format) { m_TimeFormat = format; };
119  
120  	#ifndef _WIN32
121  			/**
122  			 * @brief Sets log destination to syslog
123  			 * @param name Wanted program name
124  			 * @param facility Wanted log category
125  			 */
126  			void SendTo (const char *name, int facility);
127  	#endif
128  
129  			/**
130  			 * @brief Format log message and write to output stream/syslog
131  			 * @param msg Pointer to processed message
132  			 */
133  			void Append(std::shared_ptr<i2p::log::LogMsg> &);
134  
135  			/** @brief Reopen log file */
136  			void Reopen();
137  	};
138  
139  	/**
140  	 * @struct LogMsg
141  	 * @brief Log message container
142  	 *
143  	 * We creating it somewhere with LogPrint(),
144  	 * then put in MsgQueue for later processing.
145  	 */
146  	struct LogMsg {
147  		std::time_t timestamp;
148  		std::string text;    /**< message text as single string */
149  		LogLevel level;      /**< message level */
150  		std::thread::id tid; /**< id of thread that generated message */
151  
152  		LogMsg (LogLevel lvl, std::time_t ts, std::string&& txt): timestamp(ts), text(std::move(txt)), level(lvl) {}
153  	};
154  
155  	Log & Logger();
156  
157  	typedef std::function<void (const std::string&)> ThrowFunction;
158  	ThrowFunction GetThrowFunction ();
159  	void SetThrowFunction (ThrowFunction f);
160  } // log
161  } // i2p
162  
163  inline bool CheckLogLevel (LogLevel level) noexcept
164  {
165  	return level <= i2p::log::Logger().GetLogLevel ();
166  }	
167  
168  /** internal usage only -- folding args array to single string */
169  template<typename TValue>
170  void LogPrint (std::stringstream& s, TValue&& arg) noexcept
171  {
172  	s << std::forward<TValue>(arg);
173  }
174  
175  /**
176   * @brief Create log message and send it to queue
177   * @param level Message level (eLogError, eLogInfo, ...)
178   * @param args Array of message parts
179   */
180  template<typename... TArgs>
181  void LogPrint (LogLevel level, TArgs&&... args) noexcept
182  {
183  	if (!CheckLogLevel (level)) return; 
184  
185  	// fold message to single string
186  	std::stringstream ss;
187  	(LogPrint (ss, std::forward<TArgs>(args)), ...);
188  	auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), std::move(ss).str());
189  	msg->tid = std::this_thread::get_id();
190  	i2p::log::Logger().Append(msg);
191  }
192  
193  /**
194   * @brief Throw fatal error message with the list of arguments
195   * @param args Array of message parts
196   */
197  template<typename... TArgs>
198  void ThrowFatal (TArgs&&... args) noexcept
199  {
200  	auto f = i2p::log::GetThrowFunction ();
201  	if (!f) return;
202  	// fold message to single string
203  	std::stringstream ss("");
204  	(LogPrint (ss, std::forward<TArgs>(args)), ...);
205  	f (ss.str ());
206  }
207  
208  #endif // LOG_H__