Log.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file Log.h
  15. * @author Gav Wood <i@gavwood.com>
  16. * @date 2014
  17. *
  18. * The logging subsystem.
  19. */
  20. #pragma once
  21. #include <ctime>
  22. #include <chrono>
  23. #include "vector_ref.h"
  24. #include "Common.h"
  25. #include "CommonIO.h"
  26. #include "CommonData.h"
  27. #include "FixedHash.h"
  28. #include "Terminal.h"
  29. namespace boost { namespace asio { namespace ip { template<class T>class basic_endpoint; class tcp; } } }
  30. namespace dev
  31. {
  32. /// The null output stream. Used when logging is disabled.
  33. class NullOutputStream
  34. {
  35. public:
  36. template <class T> NullOutputStream& operator<<(T const&) { return *this; }
  37. };
  38. /// A simple log-output function that prints log messages to stdout.
  39. void simpleDebugOut(std::string const&, char const*);
  40. /// The logging system's current verbosity.
  41. extern int g_logVerbosity;
  42. /// The current method that the logging system uses to output the log messages. Defaults to simpleDebugOut().
  43. extern std::function<void(std::string const&, char const*)> g_logPost;
  44. class LogOverrideAux
  45. {
  46. protected:
  47. LogOverrideAux(std::type_info const* _ch, bool _value);
  48. ~LogOverrideAux();
  49. private:
  50. std::type_info const* m_ch;
  51. static const int c_null = -1;
  52. int m_old;
  53. };
  54. template <class Channel>
  55. class LogOverride: LogOverrideAux
  56. {
  57. public:
  58. LogOverride(bool _value): LogOverrideAux(&typeid(Channel), _value) {}
  59. };
  60. bool isChannelVisible(std::type_info const* _ch, bool _default);
  61. template <class Channel> bool isChannelVisible() { return isChannelVisible(&typeid(Channel), Channel::verbosity <= g_logVerbosity); }
  62. /// Temporary changes system's verbosity for specific function. Restores the old verbosity when function returns.
  63. /// Not thread-safe, use with caution!
  64. struct VerbosityHolder
  65. {
  66. VerbosityHolder(int _temporaryValue, bool _force = false): oldLogVerbosity(g_logVerbosity) { if (g_logVerbosity >= 0 || _force) g_logVerbosity = _temporaryValue; }
  67. ~VerbosityHolder() { g_logVerbosity = oldLogVerbosity; }
  68. int oldLogVerbosity;
  69. };
  70. #define ETH_THREAD_CONTEXT(name) for (std::pair<dev::ThreadContext, bool> __eth_thread_context(name, true); p.second; p.second = false)
  71. class ThreadContext
  72. {
  73. public:
  74. ThreadContext(std::string const& _info) { push(_info); }
  75. ~ThreadContext() { pop(); }
  76. static void push(std::string const& _n);
  77. static void pop();
  78. static std::string join(std::string const& _prior);
  79. };
  80. /// Set the current thread's log name.
  81. ///
  82. /// It appears that there is not currently any cross-platform way of setting
  83. /// thread names either in Boost or in the C++11 runtime libraries. What is
  84. /// more, the API for 'pthread_setname_np' is not even consistent across
  85. /// platforms which implement it.
  86. ///
  87. /// A proposal to add such functionality on the Boost mailing list, which
  88. /// I assume never happened, but which I should follow-up and ask about.
  89. /// http://boost.2283326.n4.nabble.com/Adding-an-option-to-set-the-name-of-a-boost-thread-td4638283.html
  90. ///
  91. /// man page for 'pthread_setname_np', including this crucial snippet of
  92. /// information ... "These functions are nonstandard GNU extensions."
  93. /// http://man7.org/linux/man-pages/man3/pthread_setname_np.3.html
  94. ///
  95. /// Stack Overflow "Can I set the name of a thread in pthreads / linux?"
  96. /// which includes useful information on the minor API differences between
  97. /// Linux, BSD and OS X.
  98. /// http://stackoverflow.com/questions/2369738/can-i-set-the-name-of-a-thread-in-pthreads-linux/7989973#7989973
  99. ///
  100. /// musl mailng list posting "pthread set name on MIPs" which includes the
  101. /// information that musl doesn't currently implement 'pthread_setname_np'
  102. /// https://marc.info/?l=musl&m=146171729013062&w=1
  103. void setThreadName(std::string const& _n);
  104. /// Set the current thread's log name.
  105. std::string getThreadName();
  106. /// The default logging channels. Each has an associated verbosity and three-letter prefix (name() ).
  107. /// Channels should inherit from LogChannel and define name() and verbosity.
  108. struct LogChannel { static const char* name(); static const int verbosity = 1; static const bool debug = true; };
  109. struct LeftChannel: public LogChannel { static const char* name(); };
  110. struct RightChannel: public LogChannel { static const char* name(); };
  111. struct WarnChannel: public LogChannel { static const char* name(); static const int verbosity = 0; static const bool debug = false; };
  112. struct NoteChannel: public LogChannel { static const char* name(); static const bool debug = false; };
  113. struct DebugChannel: public LogChannel { static const char* name(); static const int verbosity = 0; };
  114. struct TraceChannel: public LogChannel { static const char* name(); static const int verbosity = 4; static const bool debug = true; };
  115. enum class LogTag
  116. {
  117. None,
  118. Url,
  119. Error,
  120. Special
  121. };
  122. class LogOutputStreamBase
  123. {
  124. public:
  125. LogOutputStreamBase(char const* _id, std::type_info const* _info, unsigned _v, bool _autospacing);
  126. void comment(std::string const& _t)
  127. {
  128. switch (m_logTag)
  129. {
  130. case LogTag::Url: m_sstr << EthNavyUnder; break;
  131. case LogTag::Error: m_sstr << EthRedBold; break;
  132. case LogTag::Special: m_sstr << EthWhiteBold; break;
  133. default:;
  134. }
  135. m_sstr << _t << EthReset;
  136. m_logTag = LogTag::None;
  137. }
  138. void append(unsigned long _t) { m_sstr << EthBlue << _t << EthReset; }
  139. void append(long _t) { m_sstr << EthBlue << _t << EthReset; }
  140. void append(unsigned int _t) { m_sstr << EthBlue << _t << EthReset; }
  141. void append(int _t) { m_sstr << EthBlue << _t << EthReset; }
  142. void append(bigint const& _t) { m_sstr << EthNavy << _t << EthReset; }
  143. void append(u256 const& _t) { m_sstr << EthNavy << _t << EthReset; }
  144. void append(u160 const& _t) { m_sstr << EthNavy << _t << EthReset; }
  145. void append(double _t) { m_sstr << EthBlue << _t << EthReset; }
  146. template <unsigned N> void append(FixedHash<N> const& _t) { m_sstr << EthTeal "#" << _t.abridged() << EthReset; }
  147. void append(h160 const& _t) { m_sstr << EthRed "@" << _t.abridged() << EthReset; }
  148. void append(h256 const& _t) { m_sstr << EthCyan "#" << _t.abridged() << EthReset; }
  149. void append(h512 const& _t) { m_sstr << EthTeal "##" << _t.abridged() << EthReset; }
  150. void append(std::string const& _t) { m_sstr << EthGreen "\"" + _t + "\"" EthReset; }
  151. void append(bytes const& _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; }
  152. void append(bytesConstRef _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; }
  153. #if !defined(ETH_EMSCRIPTEN)
  154. void append(boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> const& _t);
  155. #endif
  156. template <class T> void append(std::vector<T> const& _t)
  157. {
  158. m_sstr << EthWhite "[" EthReset;
  159. int n = 0;
  160. for (auto const& i: _t)
  161. {
  162. m_sstr << (n++ ? EthWhite ", " EthReset : "");
  163. append(i);
  164. }
  165. m_sstr << EthWhite "]" EthReset;
  166. }
  167. template <class T> void append(std::set<T> const& _t)
  168. {
  169. m_sstr << EthYellow "{" EthReset;
  170. int n = 0;
  171. for (auto const& i: _t)
  172. {
  173. m_sstr << (n++ ? EthYellow ", " EthReset : "");
  174. append(i);
  175. }
  176. m_sstr << EthYellow "}" EthReset;
  177. }
  178. template <class T, class U> void append(std::map<T, U> const& _t)
  179. {
  180. m_sstr << EthLime "{" EthReset;
  181. int n = 0;
  182. for (auto const& i: _t)
  183. {
  184. m_sstr << (n++ ? EthLime ", " EthReset : "");
  185. append(i.first);
  186. m_sstr << (n++ ? EthLime ": " EthReset : "");
  187. append(i.second);
  188. }
  189. m_sstr << EthLime "}" EthReset;
  190. }
  191. template <class T> void append(std::unordered_set<T> const& _t)
  192. {
  193. m_sstr << EthYellow "{" EthReset;
  194. int n = 0;
  195. for (auto const& i: _t)
  196. {
  197. m_sstr << (n++ ? EthYellow ", " EthReset : "");
  198. append(i);
  199. }
  200. m_sstr << EthYellow "}" EthReset;
  201. }
  202. template <class T, class U> void append(std::unordered_map<T, U> const& _t)
  203. {
  204. m_sstr << EthLime "{" EthReset;
  205. int n = 0;
  206. for (auto const& i: _t)
  207. {
  208. m_sstr << (n++ ? EthLime ", " EthReset : "");
  209. append(i.first);
  210. m_sstr << (n++ ? EthLime ": " EthReset : "");
  211. append(i.second);
  212. }
  213. m_sstr << EthLime "}" EthReset;
  214. }
  215. template <class T, class U> void append(std::pair<T, U> const& _t)
  216. {
  217. m_sstr << EthPurple "(" EthReset;
  218. append(_t.first);
  219. m_sstr << EthPurple ", " EthReset;
  220. append(_t.second);
  221. m_sstr << EthPurple ")" EthReset;
  222. }
  223. template <class T> void append(T const& _t)
  224. {
  225. m_sstr << toString(_t);
  226. }
  227. protected:
  228. bool m_autospacing = false;
  229. unsigned m_verbosity = 0;
  230. std::stringstream m_sstr; ///< The accrued log entry.
  231. LogTag m_logTag = LogTag::None;
  232. };
  233. /// Logging class, iostream-like, that can be shifted to.
  234. template <class Id, bool _AutoSpacing = true>
  235. class LogOutputStream: LogOutputStreamBase
  236. {
  237. public:
  238. /// Construct a new object.
  239. /// If _term is true the the prefix info is terminated with a ']' character; if not it ends only with a '|' character.
  240. LogOutputStream(): LogOutputStreamBase(Id::name(), &typeid(Id), Id::verbosity, _AutoSpacing) {}
  241. /// Destructor. Posts the accrued log entry to the g_logPost function.
  242. ~LogOutputStream() { if (Id::verbosity <= g_logVerbosity) g_logPost(m_sstr.str(), Id::name()); }
  243. LogOutputStream& operator<<(std::string const& _t) { if (Id::verbosity <= g_logVerbosity) { if (_AutoSpacing && m_sstr.str().size() && m_sstr.str().back() != ' ') m_sstr << " "; comment(_t); } return *this; }
  244. LogOutputStream& operator<<(LogTag _t) { m_logTag = _t; return *this; }
  245. /// Shift arbitrary data to the log. Spaces will be added between items as required.
  246. template <class T> LogOutputStream& operator<<(T const& _t) { if (Id::verbosity <= g_logVerbosity) { if (_AutoSpacing && m_sstr.str().size() && m_sstr.str().back() != ' ') m_sstr << " "; append(_t); } return *this; }
  247. };
  248. /// A "hacky" way to execute the next statement on COND.
  249. /// We need such a thing due to the dangling else problem and the need
  250. /// for the logging macros to end with the stream object and not a closing brace '}'
  251. #define DEV_STATEMENT_IF(COND) for (bool i_eth_if_ = (COND); i_eth_if_; i_eth_if_ = false)
  252. /// A "hacky" way to skip the next statement.
  253. /// We need such a thing due to the dangling else problem and the need
  254. /// for the logging macros to end with the stream object and not a closing brace '}'
  255. #define DEV_STATEMENT_SKIP() while (/*CONSTCOND*/ false) /*NOTREACHED*/
  256. // Kill all logs when when NLOG is defined.
  257. #if NLOG
  258. #define clog(X) nlog(X)
  259. #define cslog(X) nslog(X)
  260. #else
  261. #if NDEBUG
  262. #define clog(X) DEV_STATEMENT_IF(!(X::debug)) dev::LogOutputStream<X, true>()
  263. #define cslog(X) DEV_STATEMENT_IF(!(X::debug)) dev::LogOutputStream<X, false>()
  264. #else
  265. #define clog(X) dev::LogOutputStream<X, true>()
  266. #define cslog(X) dev::LogOutputStream<X, false>()
  267. #endif
  268. #endif
  269. // Simple cout-like stream objects for accessing common log channels.
  270. // Dirties the global namespace, but oh so convenient...
  271. #define cdebug clog(dev::DebugChannel)
  272. #define cnote clog(dev::NoteChannel)
  273. #define cwarn clog(dev::WarnChannel)
  274. #define ctrace clog(dev::TraceChannel)
  275. // Null stream-like objects.
  276. #define ndebug DEV_STATEMENT_SKIP() dev::NullOutputStream()
  277. #define nlog(X) DEV_STATEMENT_SKIP() dev::NullOutputStream()
  278. #define nslog(X) DEV_STATEMENT_SKIP() dev::NullOutputStream()
  279. }