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__