// Copyright: 2014, Ableton AG, Berlin, all rights reserved #pragma once #include #include #include namespace ableton { namespace util { // Null object for the Log concept struct NullLog { template friend const NullLog& operator<<(const NullLog& log, const T&) { return log; } friend const NullLog& debug(const NullLog& log) { return log; } friend const NullLog& info(const NullLog& log) { return log; } friend const NullLog& warning(const NullLog& log) { return log; } friend const NullLog& error(const NullLog& log) { return log; } friend NullLog channel(const NullLog&, std::string) { return {}; } }; // std streams-based log struct StdLog { StdLog(std::string channelName = "") : mChannelName(std::move(channelName)) { } // Stream type used by std log to prepend the channel name to log messages struct StdLogStream { StdLogStream(std::ostream& ioStream, const std::string& channelName) : mpIoStream(&ioStream) , mChannelName(channelName) { ioStream << "[" << mChannelName << "] "; } StdLogStream(StdLogStream&& rhs) : mpIoStream(rhs.mpIoStream) , mChannelName(rhs.mChannelName) { rhs.mpIoStream = nullptr; } ~StdLogStream() { if (mpIoStream) { (*mpIoStream) << "\n"; } } template std::ostream& operator<<(const T& rhs) { (*mpIoStream) << rhs; return *mpIoStream; } std::ostream* mpIoStream; const std::string& mChannelName; }; friend StdLogStream debug(const StdLog& log) { return {std::clog, log.mChannelName}; } friend StdLogStream info(const StdLog& log) { return {std::clog, log.mChannelName}; } friend StdLogStream warning(const StdLog& log) { return {std::clog, log.mChannelName}; } friend StdLogStream error(const StdLog& log) { return {std::cerr, log.mChannelName}; } friend StdLog channel(const StdLog& log, const std::string& channelName) { auto compositeName = log.mChannelName.empty() ? channelName : log.mChannelName + "::" + channelName; return {std::move(compositeName)}; } std::string mChannelName; }; // Log adapter that adds timestamps template struct Timestamped { using InnerLog = typename util::Injected::type; Timestamped() = default; Timestamped(util::Injected log) : mLog(std::move(log)) { } util::Injected mLog; friend decltype(debug(std::declval())) debug(const Timestamped& log) { return log.logTimestamp(debug(*log.mLog)); } friend decltype(info(std::declval())) info(const Timestamped& log) { return log.logTimestamp(info(*log.mLog)); } friend decltype(warning(std::declval())) warning(const Timestamped& log) { return log.logTimestamp(warning(*log.mLog)); } friend decltype(error(std::declval())) error(const Timestamped& log) { return log.logTimestamp(error(*log.mLog)); } friend Timestamped channel(const Timestamped& log, const std::string& channelName) { return {channel(*log.mLog, channelName)}; } template Stream logTimestamp(Stream&& streamRef) const { using namespace std::chrono; Stream stream = std::forward(streamRef); stream << "|" << duration_cast(system_clock::now().time_since_epoch()).count() << "ms| "; return stream; } }; } // namespace util } // namespace ableton