177 lines
3.5 KiB
C++
177 lines
3.5 KiB
C++
// Copyright: 2014, Ableton AG, Berlin, all rights reserved
|
|
|
|
#pragma once
|
|
|
|
#include <ableton/util/Injected.hpp>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
namespace ableton
|
|
{
|
|
namespace util
|
|
{
|
|
|
|
// Null object for the Log concept
|
|
struct NullLog
|
|
{
|
|
template <typename T>
|
|
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 <typename T>
|
|
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 <typename Log>
|
|
struct Timestamped
|
|
{
|
|
using InnerLog = typename util::Injected<Log>::type;
|
|
|
|
Timestamped() = default;
|
|
|
|
Timestamped(util::Injected<Log> log)
|
|
: mLog(std::move(log))
|
|
{
|
|
}
|
|
|
|
util::Injected<Log> mLog;
|
|
|
|
friend decltype(debug(std::declval<InnerLog>())) debug(const Timestamped& log)
|
|
{
|
|
return log.logTimestamp(debug(*log.mLog));
|
|
}
|
|
|
|
friend decltype(info(std::declval<InnerLog>())) info(const Timestamped& log)
|
|
{
|
|
return log.logTimestamp(info(*log.mLog));
|
|
}
|
|
|
|
friend decltype(warning(std::declval<InnerLog>())) warning(const Timestamped& log)
|
|
{
|
|
return log.logTimestamp(warning(*log.mLog));
|
|
}
|
|
|
|
friend decltype(error(std::declval<InnerLog>())) 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 <typename Stream>
|
|
Stream logTimestamp(Stream&& streamRef) const
|
|
{
|
|
using namespace std::chrono;
|
|
Stream stream = std::forward<Stream>(streamRef);
|
|
stream << "|"
|
|
<< duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count()
|
|
<< "ms| ";
|
|
return stream;
|
|
}
|
|
};
|
|
|
|
} // namespace util
|
|
} // namespace ableton
|