C++11 library providing functionality common to all adapters.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
12 KiB

7 months ago
7 months ago
  1. // This file is under GNU General Public License 3.0
  2. // see LICENSE.txt
  3. #ifndef LIBPEPADAPTER_PEPLOG_HH
  4. #define LIBPEPADAPTER_PEPLOG_HH
  5. // getpid
  6. // Linux - unistd.h
  7. // macOS - unistd.h
  8. // Android - unistd.h
  9. // Win - process.h
  10. #ifdef WIN32
  11. #include <process.h>
  12. // TODO: once this works, move this to pEpEngine platform_windows.h and file a PR
  13. #ifndef getpid
  14. #define getpid() _getpid()
  15. #endif
  16. #else
  17. #include <unistd.h>
  18. #endif
  19. #include <sstream>
  20. #include <thread>
  21. #include "std_utils.hh"
  22. // pEpLog
  23. // ======
  24. // a "to be kept ultra small and simple" logging unit.
  25. // featuring:
  26. // * Logging macros that completely eliminate any logging calls in release-builds (NDEBUG)
  27. // * thread safe (no interleave when logging from diff threads) TODO: pEpLogger: REALLY?
  28. // * OS dependent backend switches:
  29. // * android: __android_log_print
  30. // * all other OS: cerr
  31. // * Logging without any class/object (pEpLog / pEpLogRaw macros)
  32. // * runtime switchable (on/off) only on a global level
  33. // * Class backed Logging macros (pEpLogClass / pEpLogClassRaw)
  34. // * * runtime switchable (on/off) on a class and object level
  35. //
  36. // There are already too many features and you might want even more and more.
  37. // But the feature-policy of this logging unit is very restrictive, and there is a
  38. // primary design goal to keep it very simple, maintainable and portable.
  39. //
  40. // pEpLog - logformat "thread - __FILE__::__FUNTION__ - <message>"
  41. // To be used in a non-class/object context
  42. #ifdef NDEBUG
  43. #define pEpLog(msg) \
  44. do { \
  45. } while (0)
  46. #else
  47. #define pEpLog(msg) \
  48. do { \
  49. if (pEp::Adapter::pEpLog::get_enabled()) { \
  50. std::stringstream msg_; \
  51. msg_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; \
  52. msg_ << " - " << __FILE__ << "::" << __FUNCTION__; \
  53. msg_ << " - " << msg; \
  54. pEp::Adapter::pEpLog::log(msg_.str()); \
  55. } \
  56. } while (0)
  57. #endif // NDEBUG
  58. // pEpLogH1 - logformat "Thread - __FILE__::__FUNTION__ - <=============== message ==============>"
  59. #ifdef NDEBUG
  60. #define pEpLogH1(msg) \
  61. do { \
  62. } while (0)
  63. #else
  64. #define pEpLogH1(msg) \
  65. do { \
  66. if (pEp::Adapter::pEpLog::get_enabled()) { \
  67. std::stringstream msg_; \
  68. msg_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; \
  69. msg_ << " - " << __FILE__ << "::" << __FUNCTION__; \
  70. msg_ << " - " << pEp::Adapter::pEpLog::decorateH1(msg); \
  71. pEp::Adapter::pEpLog::log(msg_.str()); \
  72. } \
  73. } while (0)
  74. #endif // NDEBUG
  75. // pEpLogH1 - logformat "Thread - __FILE__::__FUNTION__ - <--------------- message -------------->"
  76. #ifdef NDEBUG
  77. #define pEpLogH2(msg) \
  78. do { \
  79. } while (0)
  80. #else
  81. #define pEpLogH2(msg) \
  82. do { \
  83. if (pEp::Adapter::pEpLog::get_enabled()) { \
  84. std::stringstream msg_; \
  85. msg_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; \
  86. msg_ << " - " << __FILE__ << "::" << __FUNCTION__; \
  87. msg_ << " - " << pEp::Adapter::pEpLog::decorateH2(msg); \
  88. pEp::Adapter::pEpLog::log(msg_.str()); \
  89. } \
  90. } while (0)
  91. #endif // NDEBUG
  92. // RAW == without prefix of thread, file, function
  93. // pEpLogRaw - logformat "<message>"
  94. #ifdef NDEBUG
  95. #define pEpLogRaw(msg) \
  96. do { \
  97. } while (0)
  98. #else
  99. #define pEpLogRaw(msg) \
  100. do { \
  101. if (pEp::Adapter::pEpLog::get_enabled()) { \
  102. pEp::Adapter::pEpLog::log(msg_.str()); \
  103. } \
  104. } while (0)
  105. #endif // NDEBUG
  106. // pEpLogRawH1 - logformat "<--------------- message -------------->"
  107. #ifdef NDEBUG
  108. #define pEpLogRawH1(msg) \
  109. do { \
  110. } while (0)
  111. #else
  112. #define pEpLogRawH1(msg) \
  113. do { \
  114. if (pEp::Adapter::pEpLog::get_enabled()) { \
  115. pEp::Adapter::pEpLog::logH1(msg_.str()); \
  116. } \
  117. } while (0)
  118. #endif // NDEBUG
  119. // pEpLogRawH2 - logformat <=============== message ==============>"
  120. #ifdef NDEBUG
  121. #define pEpLogRawH2(msg) \
  122. do { \
  123. } while (0)
  124. #else
  125. #define pEpLogRawH2(msg) \
  126. do { \
  127. if (pEp::Adapter::pEpLog::get_enabled()) { \
  128. pEp::Adapter::pEpLog::logH2(msg_.str()); \
  129. } \
  130. } while (0)
  131. #endif // NDEBUG
  132. namespace pEp {
  133. namespace Adapter {
  134. namespace pEpLog {
  135. // Logging functions to control pEpLog() macro
  136. void set_enabled(const bool& is_enabled);
  137. bool get_enabled();
  138. void log(const std::string& msg, Utils::Color col = Utils::Color::WHITE);
  139. void logH1(const std::string& msg, Utils::Color col = Utils::Color::WHITE);
  140. void logH2(const std::string& msg, Utils::Color col = Utils::Color::WHITE);
  141. void logH3(const std::string& msg, Utils::Color col = Utils::Color::WHITE);
  142. std::string decorate_three_lines(const std::string& msg, char decoration = '-');
  143. std::string decorate_centered(const std::string& msg, char decoration = '-');
  144. } // namespace pEpLog
  145. } // namespace Adapter
  146. } // namespace pEp
  147. // --------------------------------------------------------------------------------------------------
  148. // pEpLogClass is to be used in a class
  149. // pEpLogger can only print the "thread - file::class::function - <message>" format using this macro
  150. // WARNING: Some magic is needed
  151. // Usage:
  152. // create your logger obj in your class as a public member (usually)
  153. // Adapter::pEpLog::pEpLogger logger{"<CLASSNAME>", enabled: true|false};
  154. // then, create an alias for your logger called "m4gic_logger_n4me" as a private member
  155. // Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger;
  156. // Thats all.
  157. // Now in your implementation, to log a message you just write:
  158. // pEpLogClass("my great logging message");
  159. #ifdef NDEBUG
  160. #define pEpLogClass(msg) \
  161. do { \
  162. } while (0)
  163. #else
  164. #define pEpLogClass(msg) \
  165. do { \
  166. std::stringstream msg_; \
  167. msg_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; \
  168. msg_ << " - " << this->m4gic_logger_n4me.get_classname(); \
  169. msg_ << "[" << this->m4gic_logger_n4me.get_instancename() << "]"; \
  170. msg_ << "::" << __FUNCTION__; \
  171. msg_ << " - " << (msg); \
  172. this->m4gic_logger_n4me.logRaw(msg_.str()); \
  173. } while (0)
  174. #endif // NDEBUG
  175. // pEpLogClassRaw is the same as pEpLogClass, but does not print anything except the supplied msg
  176. // This can also be achieved without this macro, just use the log method of pEpLogger
  177. // You also need to set up the logger in your class as for pEpLogClass
  178. // The only advantage of this macro is that is compiled away to nothing with NDEBUG
  179. #ifdef NDEBUG
  180. #define pEpLogClassRaw(msg) \
  181. do { \
  182. } while (0)
  183. #else
  184. #define pEpLogClassRaw(msg) \
  185. do { \
  186. this->m4gic_logger_n4me.logRaw(msg); \
  187. } while (0)
  188. #endif // NDEBUG
  189. namespace pEp {
  190. namespace Adapter {
  191. namespace pEpLog {
  192. class pEpLogger {
  193. public:
  194. pEpLogger() = delete;
  195. pEpLogger(const std::string& classname, const bool& enabled);
  196. // Print a logging message in the format "thread - classname[instancename] - <msg>"
  197. void log(const std::string& msg, Utils::Color col = Utils::Color::WHITE) const;
  198. // Prints just "<msg>"
  199. void logRaw(const std::string& msg, Utils::Color col = Utils::Color::WHITE) const;
  200. void set_enabled(const bool& enabled);
  201. bool get_enabled() const;
  202. std::string get_classname() const;
  203. // If never set, the default instancename is a unique number
  204. void set_instancename(const std::string& name);
  205. std::string get_instancename() const;
  206. private:
  207. static int auto_instance_nr;
  208. bool is_enabled;
  209. std::string classname;
  210. std::string instancename;
  211. };
  212. } // namespace pEpLog
  213. } // namespace Adapter
  214. } // namespace pEp
  215. #endif // LIBPEPADAPTER_PEPLOG_HH