123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- /*
- This file is part of cpp-ethereum.
- cpp-ethereum is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- cpp-ethereum is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
- */
- /** @file Log.h
- * @author Gav Wood <i@gavwood.com>
- * @date 2014
- *
- * The logging subsystem.
- */
- #pragma once
- #include <ctime>
- #include <chrono>
- #include "vector_ref.h"
- #include "Common.h"
- #include "CommonIO.h"
- #include "CommonData.h"
- #include "FixedHash.h"
- #include "Terminal.h"
- namespace boost { namespace asio { namespace ip { template<class T>class basic_endpoint; class tcp; } } }
- namespace dev
- {
- /// The null output stream. Used when logging is disabled.
- class NullOutputStream
- {
- public:
- template <class T> NullOutputStream& operator<<(T const&) { return *this; }
- };
- /// A simple log-output function that prints log messages to stdout.
- void simpleDebugOut(std::string const&, char const*);
- /// The logging system's current verbosity.
- extern int g_logVerbosity;
- /// The current method that the logging system uses to output the log messages. Defaults to simpleDebugOut().
- extern std::function<void(std::string const&, char const*)> g_logPost;
- class LogOverrideAux
- {
- protected:
- LogOverrideAux(std::type_info const* _ch, bool _value);
- ~LogOverrideAux();
- private:
- std::type_info const* m_ch;
- static const int c_null = -1;
- int m_old;
- };
- template <class Channel>
- class LogOverride: LogOverrideAux
- {
- public:
- LogOverride(bool _value): LogOverrideAux(&typeid(Channel), _value) {}
- };
- bool isChannelVisible(std::type_info const* _ch, bool _default);
- template <class Channel> bool isChannelVisible() { return isChannelVisible(&typeid(Channel), Channel::verbosity <= g_logVerbosity); }
- /// Temporary changes system's verbosity for specific function. Restores the old verbosity when function returns.
- /// Not thread-safe, use with caution!
- struct VerbosityHolder
- {
- VerbosityHolder(int _temporaryValue, bool _force = false): oldLogVerbosity(g_logVerbosity) { if (g_logVerbosity >= 0 || _force) g_logVerbosity = _temporaryValue; }
- ~VerbosityHolder() { g_logVerbosity = oldLogVerbosity; }
- int oldLogVerbosity;
- };
- #define ETH_THREAD_CONTEXT(name) for (std::pair<dev::ThreadContext, bool> __eth_thread_context(name, true); p.second; p.second = false)
- class ThreadContext
- {
- public:
- ThreadContext(std::string const& _info) { push(_info); }
- ~ThreadContext() { pop(); }
- static void push(std::string const& _n);
- static void pop();
- static std::string join(std::string const& _prior);
- };
- /// Set the current thread's log name.
- ///
- /// It appears that there is not currently any cross-platform way of setting
- /// thread names either in Boost or in the C++11 runtime libraries. What is
- /// more, the API for 'pthread_setname_np' is not even consistent across
- /// platforms which implement it.
- ///
- /// A proposal to add such functionality on the Boost mailing list, which
- /// I assume never happened, but which I should follow-up and ask about.
- /// http://boost.2283326.n4.nabble.com/Adding-an-option-to-set-the-name-of-a-boost-thread-td4638283.html
- ///
- /// man page for 'pthread_setname_np', including this crucial snippet of
- /// information ... "These functions are nonstandard GNU extensions."
- /// http://man7.org/linux/man-pages/man3/pthread_setname_np.3.html
- ///
- /// Stack Overflow "Can I set the name of a thread in pthreads / linux?"
- /// which includes useful information on the minor API differences between
- /// Linux, BSD and OS X.
- /// http://stackoverflow.com/questions/2369738/can-i-set-the-name-of-a-thread-in-pthreads-linux/7989973#7989973
- ///
- /// musl mailng list posting "pthread set name on MIPs" which includes the
- /// information that musl doesn't currently implement 'pthread_setname_np'
- /// https://marc.info/?l=musl&m=146171729013062&w=1
- void setThreadName(std::string const& _n);
- /// Set the current thread's log name.
- std::string getThreadName();
- /// The default logging channels. Each has an associated verbosity and three-letter prefix (name() ).
- /// Channels should inherit from LogChannel and define name() and verbosity.
- struct LogChannel { static const char* name(); static const int verbosity = 1; static const bool debug = true; };
- struct LeftChannel: public LogChannel { static const char* name(); };
- struct RightChannel: public LogChannel { static const char* name(); };
- struct WarnChannel: public LogChannel { static const char* name(); static const int verbosity = 0; static const bool debug = false; };
- struct NoteChannel: public LogChannel { static const char* name(); static const bool debug = false; };
- struct DebugChannel: public LogChannel { static const char* name(); static const int verbosity = 0; };
- struct TraceChannel: public LogChannel { static const char* name(); static const int verbosity = 4; static const bool debug = true; };
- enum class LogTag
- {
- None,
- Url,
- Error,
- Special
- };
- class LogOutputStreamBase
- {
- public:
- LogOutputStreamBase(char const* _id, std::type_info const* _info, unsigned _v, bool _autospacing);
- void comment(std::string const& _t)
- {
- switch (m_logTag)
- {
- case LogTag::Url: m_sstr << EthNavyUnder; break;
- case LogTag::Error: m_sstr << EthRedBold; break;
- case LogTag::Special: m_sstr << EthWhiteBold; break;
- default:;
- }
- m_sstr << _t << EthReset;
- m_logTag = LogTag::None;
- }
- void append(unsigned long _t) { m_sstr << EthBlue << _t << EthReset; }
- void append(long _t) { m_sstr << EthBlue << _t << EthReset; }
- void append(unsigned int _t) { m_sstr << EthBlue << _t << EthReset; }
- void append(int _t) { m_sstr << EthBlue << _t << EthReset; }
- void append(bigint const& _t) { m_sstr << EthNavy << _t << EthReset; }
- void append(u256 const& _t) { m_sstr << EthNavy << _t << EthReset; }
- void append(u160 const& _t) { m_sstr << EthNavy << _t << EthReset; }
- void append(double _t) { m_sstr << EthBlue << _t << EthReset; }
- template <unsigned N> void append(FixedHash<N> const& _t) { m_sstr << EthTeal "#" << _t.abridged() << EthReset; }
- void append(h160 const& _t) { m_sstr << EthRed "@" << _t.abridged() << EthReset; }
- void append(h256 const& _t) { m_sstr << EthCyan "#" << _t.abridged() << EthReset; }
- void append(h512 const& _t) { m_sstr << EthTeal "##" << _t.abridged() << EthReset; }
- void append(std::string const& _t) { m_sstr << EthGreen "\"" + _t + "\"" EthReset; }
- void append(bytes const& _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; }
- void append(bytesConstRef _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; }
- #if !defined(ETH_EMSCRIPTEN)
- void append(boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> const& _t);
- #endif
- template <class T> void append(std::vector<T> const& _t)
- {
- m_sstr << EthWhite "[" EthReset;
- int n = 0;
- for (auto const& i: _t)
- {
- m_sstr << (n++ ? EthWhite ", " EthReset : "");
- append(i);
- }
- m_sstr << EthWhite "]" EthReset;
- }
- template <class T> void append(std::set<T> const& _t)
- {
- m_sstr << EthYellow "{" EthReset;
- int n = 0;
- for (auto const& i: _t)
- {
- m_sstr << (n++ ? EthYellow ", " EthReset : "");
- append(i);
- }
- m_sstr << EthYellow "}" EthReset;
- }
- template <class T, class U> void append(std::map<T, U> const& _t)
- {
- m_sstr << EthLime "{" EthReset;
- int n = 0;
- for (auto const& i: _t)
- {
- m_sstr << (n++ ? EthLime ", " EthReset : "");
- append(i.first);
- m_sstr << (n++ ? EthLime ": " EthReset : "");
- append(i.second);
- }
- m_sstr << EthLime "}" EthReset;
- }
- template <class T> void append(std::unordered_set<T> const& _t)
- {
- m_sstr << EthYellow "{" EthReset;
- int n = 0;
- for (auto const& i: _t)
- {
- m_sstr << (n++ ? EthYellow ", " EthReset : "");
- append(i);
- }
- m_sstr << EthYellow "}" EthReset;
- }
- template <class T, class U> void append(std::unordered_map<T, U> const& _t)
- {
- m_sstr << EthLime "{" EthReset;
- int n = 0;
- for (auto const& i: _t)
- {
- m_sstr << (n++ ? EthLime ", " EthReset : "");
- append(i.first);
- m_sstr << (n++ ? EthLime ": " EthReset : "");
- append(i.second);
- }
- m_sstr << EthLime "}" EthReset;
- }
- template <class T, class U> void append(std::pair<T, U> const& _t)
- {
- m_sstr << EthPurple "(" EthReset;
- append(_t.first);
- m_sstr << EthPurple ", " EthReset;
- append(_t.second);
- m_sstr << EthPurple ")" EthReset;
- }
- template <class T> void append(T const& _t)
- {
- m_sstr << toString(_t);
- }
- protected:
- bool m_autospacing = false;
- unsigned m_verbosity = 0;
- std::stringstream m_sstr; ///< The accrued log entry.
- LogTag m_logTag = LogTag::None;
- };
- /// Logging class, iostream-like, that can be shifted to.
- template <class Id, bool _AutoSpacing = true>
- class LogOutputStream: LogOutputStreamBase
- {
- public:
- /// Construct a new object.
- /// If _term is true the the prefix info is terminated with a ']' character; if not it ends only with a '|' character.
- LogOutputStream(): LogOutputStreamBase(Id::name(), &typeid(Id), Id::verbosity, _AutoSpacing) {}
- /// Destructor. Posts the accrued log entry to the g_logPost function.
- ~LogOutputStream() { if (Id::verbosity <= g_logVerbosity) g_logPost(m_sstr.str(), Id::name()); }
- 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; }
- LogOutputStream& operator<<(LogTag _t) { m_logTag = _t; return *this; }
- /// Shift arbitrary data to the log. Spaces will be added between items as required.
- 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; }
- };
- /// A "hacky" way to execute the next statement on COND.
- /// We need such a thing due to the dangling else problem and the need
- /// for the logging macros to end with the stream object and not a closing brace '}'
- #define DEV_STATEMENT_IF(COND) for (bool i_eth_if_ = (COND); i_eth_if_; i_eth_if_ = false)
- /// A "hacky" way to skip the next statement.
- /// We need such a thing due to the dangling else problem and the need
- /// for the logging macros to end with the stream object and not a closing brace '}'
- #define DEV_STATEMENT_SKIP() while (/*CONSTCOND*/ false) /*NOTREACHED*/
- // Kill all logs when when NLOG is defined.
- #if NLOG
- #define clog(X) nlog(X)
- #define cslog(X) nslog(X)
- #else
- #if NDEBUG
- #define clog(X) DEV_STATEMENT_IF(!(X::debug)) dev::LogOutputStream<X, true>()
- #define cslog(X) DEV_STATEMENT_IF(!(X::debug)) dev::LogOutputStream<X, false>()
- #else
- #define clog(X) dev::LogOutputStream<X, true>()
- #define cslog(X) dev::LogOutputStream<X, false>()
- #endif
- #endif
- // Simple cout-like stream objects for accessing common log channels.
- // Dirties the global namespace, but oh so convenient...
- #define cdebug clog(dev::DebugChannel)
- #define cnote clog(dev::NoteChannel)
- #define cwarn clog(dev::WarnChannel)
- #define ctrace clog(dev::TraceChannel)
- // Null stream-like objects.
- #define ndebug DEV_STATEMENT_SKIP() dev::NullOutputStream()
- #define nlog(X) DEV_STATEMENT_SKIP() dev::NullOutputStream()
- #define nslog(X) DEV_STATEMENT_SKIP() dev::NullOutputStream()
- }
|