4#include <unordered_map>
37 using Sink = std::function<void(
const std::string& channel,
const LogEntry& e)>;
48 void log(
const std::string& channel,
const std::string& line)
54 void log(
const std::string& channel,
Level lvl,
const std::string& line)
64 std::vector<LogEntry>
getChannel(
const std::string& channel)
66 std::lock_guard<std::mutex> lk(
m_);
70 return {it->second.begin(), it->second.end()};
75 std::lock_guard<std::mutex> lk(
m_);
76 std::vector<std::string> names;
79 names.push_back(kv.first);
85 std::lock_guard<std::mutex> lk(
m_);
91 std::lock_guard<std::mutex> lk(
m_);
98 std::lock_guard<std::mutex> lk(
m_);
100 sinks_.emplace_back(
id, s);
105 std::lock_guard<std::mutex> lk(
m_);
108 { return p.first == id; }),
113 std::lock_guard<std::mutex> lk(
m_);
120 std::lock_guard<std::mutex> lk(
m_);
129 std::lock_guard<std::mutex> lk(
m_);
137 using namespace std::chrono;
138 auto tp = time_point<system_clock, milliseconds>(milliseconds(ms));
139 auto t = system_clock::to_time_t(tp);
140 auto ms_part = (int)(ms % 1000);
143 localtime_s(&bt, &t);
145 localtime_r(&t, &bt);
148 std::snprintf(buf,
sizeof(buf),
"%02d:%02d:%02d.%03d", bt.tm_hour, bt.tm_min, bt.tm_sec, ms_part);
149 return std::string(buf);
159 explicit LineToLoggerBuf(std::string channel, std::optional<Level> forced = std::nullopt) :
165 if (ch == traits_type::eof())
167 char c =
static_cast<char>(ch);
173 std::streamsize
xsputn(
const char* s, std::streamsize count)
override
175 std::streamsize w = 0;
176 for (; w < count; ++w)
189 if (
buf_.back() ==
'\n')
203 if (!
buf_.empty() &&
buf_.back() ==
'\n')
221 OstreamRedirect(std::ostream& os,
const std::string& channel, std::optional<Level> forced = std::nullopt) :
264 using namespace std::chrono;
265 return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
271 auto has = [&](
const char* needle)
273 auto it = std::search(
275 needle, needle + std::strlen(needle),
277 { return std::tolower((unsigned char)a) == std::tolower((unsigned char)b); });
278 return it != s.end();
280 if (has(
"[error]") || has(
" error") || has(
"failed") || has(
"exception"))
282 if (has(
"[warn]") || has(
" warning"))
294 std::lock_guard<std::mutex> lk(
m_);
296 q.emplace_back(std::move(e));
300 auto& back = q.back();
301 for (
auto& [
id, s] :
sinks_)
306 mutable std::mutex
m_;
308 std::unordered_map<std::string, std::deque<LogEntry>>
channels_;
310 std::vector<std::pair<int, Sink>>
sinks_;
std::streamsize xsputn(const char *s, std::streamsize count) override
std::optional< Level > forcedLevel_
int overflow(int ch) override
LineToLoggerBuf(std::string channel, std::optional< Level > forced=std::nullopt)
OstreamRedirect & operator=(OstreamRedirect &&)=delete
std::streambuf * original_
OstreamRedirect & operator=(const OstreamRedirect &)=delete
OstreamRedirect(const OstreamRedirect &)=delete
OstreamRedirect(std::ostream &os, const std::string &channel, std::optional< Level > forced=std::nullopt)
OstreamRedirect(OstreamRedirect &&)=delete
std::unique_ptr< OstreamRedirect > cerrRedirect_
void log(const std::string &channel, Level lvl, const std::string &line)
std::vector< std::pair< int, Sink > > sinks_
std::vector< LogEntry > getChannel(const std::string &channel)
std::function< void(const std::string &channel, const LogEntry &e)> Sink
std::unique_ptr< OstreamRedirect > coutRedirect_
void commit_(const std::string &channel, LogEntry e)
int addSink(const Sink &s)
void uninstallStdCapture()
static std::string formatTs(uint64_t ms)
void setChannelCapacity(size_t cap)
std::unordered_map< std::string, std::deque< LogEntry > > channels_
std::vector< std::string > channels() const
void log(const std::string &channel, const std::string &line)
static Level autoDetect_(const std::string &s)
static Logger & instance()
void clearChannel(const std::string &channel)