feat/update_config #10

Merged
tqcq merged 26 commits from feat/update_config into master 2024-10-14 10:15:01 +08:00
15 changed files with 958 additions and 729 deletions
Showing only changes of commit fa04f9c23a - Show all commits

View File

@ -2128,8 +2128,8 @@ nsel_DISABLE_MSVC_WARNINGS(26409)
: make_unexpected(detail::invoke(std::forward<F>(f), std::move(error()))); : make_unexpected(detail::invoke(std::forward<F>(f), std::move(error())));
} }
#endif #endif
#endif// nsel_P2505R >= 3 #endif// nsel_P2505R >= 3 \
// unwrap() // unwrap()
// template <class U, class E> // template <class U, class E>
// constexpr expected<U,E> expected<expected<U,E>,E>::unwrap() const&; // constexpr expected<U,E> expected<expected<U,E>,E>::unwrap() const&;

View File

@ -174,9 +174,8 @@ private:
{"1s", 1} {"1s", 1}
}; };
for (auto &&item : m) {} for (auto &&item : m) {}
return result;
} }
return result;
}
void LinkToParent(Slice rel_path, ExposedVarGroup *parent) void LinkToParent(Slice rel_path, ExposedVarGroup *parent)
{ {

View File

@ -16,7 +16,7 @@ GetProviers()
static std::vector<PrefixAppender *> providers; static std::vector<PrefixAppender *> providers;
return &providers; return &providers;
} }
} // namespace }// namespace
namespace details { namespace details {
std::string std::string
@ -24,10 +24,12 @@ DescribeFormatArguments(const std::vector<std::string> &args)
{ {
return fmt::format("{}", fmt::join(args.begin(), args.end(), ", ")); return fmt::format("{}", fmt::join(args.begin(), args.end(), ", "));
} }
} // namespace details }// namespace details
void InstallPrefixProvider(PrefixAppender *writer) { void
GetProviers()->push_back(writer); InstallPrefixProvider(PrefixAppender *writer)
{
GetProviers()->push_back(writer);
} }
void void
@ -39,9 +41,9 @@ WritePrefixTo(std::string *to)
if (to->size() != was) { to->push_back(' '); } if (to->size() != was) { to->push_back(' '); }
} }
} }
} // namespace logging }// namespace logging
} // namespace internal }// namespace internal
} // namespace tile }// namespace tile
namespace tile { namespace tile {
static std::mutex g_sink_mutex; static std::mutex g_sink_mutex;
@ -53,226 +55,273 @@ std::mutex g_log_mutex;
class OStreamWrapper : public std::streambuf { class OStreamWrapper : public std::streambuf {
public: public:
OStreamWrapper(std::ostream &ostream) : ostream_(ostream) {} OStreamWrapper(std::ostream &ostream) : ostream_(ostream) {}
int_type overflow(int_type c) override { return c; } int_type overflow(int_type c) override { return c; }
private: private:
std::ostream &ostream_; std::ostream &ostream_;
}; };
bool VLogIsOn(int n) { return true; } bool
VLogIsOn(int n)
{
return true;
}
class LogMessage::Impl { class LogMessage::Impl {
public: public:
Impl(const char *file, int line) Impl(const char *file, int line) : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0)
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
Init(file, line, TILE_INFO, &LogMessage::Impl::SendToLog);
}
Impl(const char *file, int line, LogSeverity severity)
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
Init(file, line, severity, &LogMessage::Impl::SendToLog);
}
Impl(const char *file, int line, LogSeverity severity, LogSink *sink,
bool also_send_to_log)
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
Init(file, line, severity,
also_send_to_log ? &LogMessage::Impl::SendToSinkAndLog
: &LogMessage::Impl::SendToSink);
sink_ = sink;
}
~Impl() { Flush(); }
std::ostream &stream() { return stream_; }
void Flush() {
if (has_been_flushed_) {
return;
}
num_chars_to_log_ = stream_.pcount();
const bool append_newline = message_text_[num_chars_to_log_ - 1] != '\n';
char original_final_char = '\0';
if (append_newline) {
original_final_char = message_text_[num_chars_to_log_];
message_text_[num_chars_to_log_++] = '\n';
}
message_text_[num_chars_to_log_] = '\0';
{ {
std::lock_guard<std::mutex> _{g_log_mutex}; Init(file, line, TILE_INFO, &LogMessage::Impl::SendToLog);
(this->*(send_method_))();
++g_num_messages[severity_];
WaitForSinks();
if (sink_) {
sink_->Flush();
}
} }
if (append_newline) { Impl(const char *file, int line, LogSeverity severity) : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0)
message_text_[num_chars_to_log_ - 1] = original_final_char; {
Init(file, line, severity, &LogMessage::Impl::SendToLog);
} }
if (preserved_errno_ != 0) { Impl(const char *file, int line, LogSeverity severity, LogSink *sink, bool also_send_to_log)
errno = preserved_errno_; : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0)
{
Init(file, line, severity,
also_send_to_log ? &LogMessage::Impl::SendToSinkAndLog : &LogMessage::Impl::SendToSink);
sink_ = sink;
} }
has_been_flushed_ = true;
if (severity_ == TILE_FATAL) { ~Impl() { Flush(); }
assert(false);
std::ostream &stream() { return stream_; }
void Flush()
{
if (has_been_flushed_) { return; }
num_chars_to_log_ = stream_.pcount();
const bool append_newline = message_text_[num_chars_to_log_ - 1] != '\n';
char original_final_char = '\0';
if (append_newline) {
original_final_char = message_text_[num_chars_to_log_];
message_text_[num_chars_to_log_++] = '\n';
}
message_text_[num_chars_to_log_] = '\0';
{
std::lock_guard<std::mutex> _{g_log_mutex};
(this->*(send_method_))();
++g_num_messages[severity_];
WaitForSinks();
if (sink_) { sink_->Flush(); }
}
if (append_newline) { message_text_[num_chars_to_log_ - 1] = original_final_char; }
if (preserved_errno_ != 0) { errno = preserved_errno_; }
has_been_flushed_ = true;
if (severity_ == TILE_FATAL) { assert(false); }
} }
}
LogSeverity severity() const noexcept { return severity_; } LogSeverity severity() const noexcept { return severity_; }
int line() const noexcept { return line_; }
const char *fullname() const noexcept { return file_; } int line() const noexcept { return line_; }
const char *basename() const noexcept { return file_; }
const LogMessageTime &time() const noexcept { return time_; } const char *fullname() const noexcept { return file_; }
int preserved_errno() const { return preserved_errno_; }
const char *basename() const noexcept { return file_; }
const LogMessageTime &time() const noexcept { return time_; }
int preserved_errno() const { return preserved_errno_; }
private: private:
void Init(const char *file, int line, LogSeverity severity, void Init(const char *file, int line, LogSeverity severity, void (LogMessage::Impl::*send_method)())
void (LogMessage::Impl::*send_method)()) { {
has_been_flushed_ = false; has_been_flushed_ = false;
file_ = file; file_ = file;
line_ = line; line_ = line;
severity_ = severity; severity_ = severity;
send_method_ = send_method; send_method_ = send_method;
sink_ = nullptr; sink_ = nullptr;
const auto now = std::chrono::system_clock::now(); const auto now = std::chrono::system_clock::now();
time_ = LogMessageTime(now); time_ = LogMessageTime(now);
thread_id_ = std::this_thread::get_id(); thread_id_ = std::this_thread::get_id();
preserved_errno_ = errno; preserved_errno_ = errno;
} }
void SendToSink() { void SendToSink()
if (sink_) { {
sink_->Send(severity_, fullname(), basename(), line(), time(), if (sink_) {
message_text_ + num_prefix_chars_, sink_->Send(severity_, fullname(), basename(), line(), time(), message_text_ + num_prefix_chars_,
num_chars_to_log_ - num_prefix_chars_); num_chars_to_log_ - num_prefix_chars_ - 1);
}
} }
}
void SendToLog() { void SendToLog()
if (g_sink_count.load(std::memory_order_relaxed) == 0) { {
ColoredWriteToStdout(severity_, message_text_ + num_prefix_chars_, if (g_sink_count.load(std::memory_order_relaxed) == 0) {
num_chars_to_log_ - num_chars_to_log_); ColoredWriteToStdout(severity_, message_text_ + num_prefix_chars_, num_chars_to_log_ - num_chars_to_log_);
}
LogToSinks(severity_, fullname(), basename(), line(), time(), message_text_ + num_prefix_chars_,
num_chars_to_log_ - num_prefix_chars_ - 1);
}
void SendToSinkAndLog()
{
SendToSink();
SendToLog();
} }
LogToSinks(severity_, fullname(), basename(), line(), time(),
message_text_ + num_prefix_chars_,
num_chars_to_log_ - num_prefix_chars_);
}
void SendToSinkAndLog() {
SendToSink();
SendToLog();
}
private: private:
char message_text_[LogMessage::kMaxLogMessageLen + 1]; char message_text_[LogMessage::kMaxLogMessageLen + 1];
LogMessage::LogStream stream_; LogMessage::LogStream stream_;
bool has_been_flushed_; bool has_been_flushed_;
const char *file_; const char *file_;
int line_; int line_;
LogSeverity severity_; LogSeverity severity_;
void (LogMessage::Impl::*send_method_)(); void (LogMessage::Impl::*send_method_)();
LogSink *sink_; LogSink *sink_;
LogMessageTime time_; LogMessageTime time_;
std::thread::id thread_id_; std::thread::id thread_id_;
int preserved_errno_; int preserved_errno_;
size_t num_prefix_chars_; size_t num_prefix_chars_;
size_t num_chars_to_log_; size_t num_chars_to_log_;
}; };
LogMessage::LogMessage(const char *file, int line) LogMessage::LogMessage(const char *file, int line) : impl_(new Impl(file, line)) {}
: impl_(new Impl(file, line)) {}
LogMessage::LogMessage(const char *file, int line, LogSeverity severity) LogMessage::LogMessage(const char *file, int line, LogSeverity severity) : impl_(new Impl(file, line, severity)) {}
: impl_(new Impl(file, line, severity)) {}
LogMessage::LogMessage(const char *file, int line, LogSeverity severity, LogMessage::LogMessage(const char *file, int line, LogSeverity severity, LogSink *sink, bool also_send_to_log)
LogSink *sink, bool also_send_to_log) : impl_(new Impl(file, line, severity, sink, also_send_to_log))
: impl_(new Impl(file, line, severity, sink, also_send_to_log)) {} {}
LogMessage::~LogMessage() {} LogMessage::~LogMessage() {}
std::ostream &LogMessage::stream() { return impl_->stream(); } std::ostream &
void LogMessage::Flush() { impl_->Flush(); } LogMessage::stream()
{
LogSeverity LogMessage::severity() const noexcept { return impl_->severity(); } return impl_->stream();
int LogMessage::line() const noexcept { return impl_->line(); }
const char *LogMessage::fullname() const noexcept { return impl_->fullname(); }
const char *LogMessage::basename() const noexcept { return impl_->basename(); }
const LogMessageTime &LogMessage::time() const noexcept {
return impl_->time();
} }
int LogMessage::preserved_errno() const { return impl_->preserved_errno(); }
LogMessageFatal::LogMessageFatal(const char *file, int line) void
: LogMessage(file, line, TILE_FATAL) {} LogMessage::Flush()
{
impl_->Flush();
}
LogSeverity
LogMessage::severity() const noexcept
{
return impl_->severity();
}
int
LogMessage::line() const noexcept
{
return impl_->line();
}
const char *
LogMessage::fullname() const noexcept
{
return impl_->fullname();
}
const char *
LogMessage::basename() const noexcept
{
return impl_->basename();
}
const LogMessageTime &
LogMessage::time() const noexcept
{
return impl_->time();
}
int
LogMessage::preserved_errno() const
{
return impl_->preserved_errno();
}
LogMessageFatal::LogMessageFatal(const char *file, int line) : LogMessage(file, line, TILE_FATAL) {}
LogMessageFatal::~LogMessageFatal() {} LogMessageFatal::~LogMessageFatal() {}
std::ostream &LogMessageFatal::stream() { return LogMessage::stream(); } std::ostream &
LogMessageFatal::stream()
{
return LogMessage::stream();
}
LogMessageTime::LogMessageTime() : time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {} LogMessageTime::LogMessageTime() : time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {}
LogMessageTime::LogMessageTime(std::tm t) : use_localtime_(true) { LogMessageTime::LogMessageTime(std::tm t) : use_localtime_(true)
std::time_t timestamp = std::mktime(&t); {
init(t, timestamp, 0); std::time_t timestamp = std::mktime(&t);
init(t, timestamp, 0);
} }
LogMessageTime::LogMessageTime(std::time_t timestamp, WallTime now) LogMessageTime::LogMessageTime(std::time_t timestamp, WallTime now) : use_localtime_(false)
: use_localtime_(false) { {
std::tm t; std::tm t;
if (use_localtime_) { if (use_localtime_) {
localtime_r(&timestamp, &t); localtime_r(&timestamp, &t);
} else { } else {
gmtime_r(&timestamp, &t); gmtime_r(&timestamp, &t);
} }
init(t, timestamp, now); init(t, timestamp, now);
}
LogMessageTime::LogMessageTime(std::chrono::system_clock::time_point tp)
: use_localtime_(false) {
std::time_t timestamp = std::chrono::system_clock::to_time_t(tp);
std::tm t;
if (use_localtime_) {
localtime_r(&timestamp, &t);
} else {
gmtime_r(&timestamp, &t);
}
init(t, timestamp, 0);
usecs_ = std::chrono::duration_cast<std::chrono::microseconds>(
tp.time_since_epoch())
.count() %
1000000;
} }
void LogMessageTime::init(const std::tm &t, std::time_t timestamp, LogMessageTime::LogMessageTime(std::chrono::system_clock::time_point tp) : use_localtime_(false)
WallTime now) { {
time_struct_ = t; std::time_t timestamp = std::chrono::system_clock::to_time_t(tp);
timestamp_ = timestamp; std::tm t;
if (now < timestamp) { if (use_localtime_) {
usecs_ = 0; localtime_r(&timestamp, &t);
} else { } else {
usecs_ = static_cast<std::int32_t>((now - timestamp) * 1000000) % 1000000; gmtime_r(&timestamp, &t);
} }
init(t, timestamp, 0);
usecs_ = std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch()).count() % 1000000;
}
void
LogMessageTime::init(const std::tm &t, std::time_t timestamp, WallTime now)
{
time_struct_ = t;
timestamp_ = timestamp;
if (now < timestamp) {
usecs_ = 0;
} else {
usecs_ = static_cast<std::int32_t>((now - timestamp) * 1000000) % 1000000;
}
CalcGmtOffset(); CalcGmtOffset();
} }
void LogMessageTime::CalcGmtOffset() { void
std::tm gmt_struct; LogMessageTime::CalcGmtOffset()
int isDst = 0; {
if (true) { std::tm gmt_struct;
localtime_r(&timestamp_, &gmt_struct); int isDst = 0;
isDst = gmt_struct.tm_isdst; if (true) {
gmt_struct = time_struct_; localtime_r(&timestamp_, &gmt_struct);
} else { isDst = gmt_struct.tm_isdst;
isDst = time_struct_.tm_isdst; gmt_struct = time_struct_;
gmtime_r(&timestamp_, &gmt_struct); } else {
} isDst = time_struct_.tm_isdst;
gmtime_r(&timestamp_, &gmt_struct);
}
time_t gmt_sec = mktime(&gmt_struct); time_t gmt_sec = mktime(&gmt_struct);
const long hour_secs = 3600; const long hour_secs = 3600;
@ -282,14 +331,15 @@ void LogMessageTime::CalcGmtOffset() {
} }
LogSink::~LogSink() {} LogSink::~LogSink() {}
bool LogSink::ShouldLog(LogSeverity severity) { return true; }
void LogSink::Send(LogSeverity severity, const char *full_filename, bool
const char *base_filename, int line, LogSink::ShouldLog(LogSeverity severity)
const LogMessageTime &logmsgtime, const char *message, {
size_t message_len) { return true;
}
void void
LogSink::send(LogSeverity severity, LogSink::Send(LogSeverity severity,
const char *full_filename, const char *full_filename,
const char *base_filename, const char *base_filename,
int line, int line,
@ -300,104 +350,130 @@ LogSink::send(LogSeverity severity,
// do nothing // do nothing
} }
void LogSink::Flush() {}
std::string LogSink::ToString(LogSeverity severity, const char *file, void
const char *base_filename, int line, LogSink::Flush()
const LogMessageTime &logmsgtime, {}
const char *message, size_t message_len) {
std::stringstream ss;
char date_time[64];
sprintf(date_time, "%4d-%02d-%02dT%02d:%02d:%02d.%06d",
logmsgtime.year() + 1900, logmsgtime.month(), logmsgtime.day(),
logmsgtime.hour(), logmsgtime.min(), logmsgtime.sec(),
logmsgtime.usec());
ss << date_time; std::string
LogSink::ToString(LogSeverity severity,
const char *file,
const char *base_filename,
int line,
const LogMessageTime &logmsgtime,
const char *message,
size_t message_len)
{
std::stringstream ss;
char date_time[64];
sprintf(date_time, "%4d-%02d-%02dT%02d:%02d:%02d.%06d", logmsgtime.year() + 1900, logmsgtime.month(),
logmsgtime.day(), logmsgtime.hour(), logmsgtime.min(), logmsgtime.sec(), logmsgtime.usec());
if (logmsgtime.gmtoff() != 0) {
auto hour = logmsgtime.gmtoff() / 3600;
auto min = std::abs(logmsgtime.gmtoff() % 3600) / 60;
sprintf(date_time, "%+03ld:%02ld", hour, min);
ss << date_time; ss << date_time;
} else if (!logmsgtime.use_localtime()) {
ss << "Z";
}
ss << " " << GetLogSeverityName(severity)[0] << " ";
ss << base_filename << ":" << line << " ";
// return google::LogSink::ToString(severity, file, line, logmsgtime.tm(), if (logmsgtime.gmtoff() != 0) {
// message, message_len); auto hour = logmsgtime.gmtoff() / 3600;
auto min = std::abs(logmsgtime.gmtoff() % 3600) / 60;
ss.write(message, message_len); sprintf(date_time, "%+03ld:%02ld", hour, min);
return ss.str(); ss << date_time;
} } else if (!logmsgtime.use_localtime()) {
ss << "Z";
static void ColoredWriteToStderrOrStdout(FILE *output, LogSeverity severity,
const char *message, size_t len) {
fwrite(message, len, 1, output);
fflush(output);
}
void ColoredWriteToStdout(LogSeverity severity, const char *message,
size_t len) {
FILE *output = stdout;
if (severity >= TILE_FATAL) {
output = stderr;
}
ColoredWriteToStderrOrStdout(output, severity, message, len);
}
void ColoredWriteToStderr(LogSeverity severity, const char *message,
size_t len) {
ColoredWriteToStderrOrStdout(stderr, severity, message, len);
}
void AddLogSink(LogSink::Ptr dest) {
std::lock_guard<std::mutex> _(g_sink_mutex);
g_sinks.insert(dest);
g_sink_count.fetch_add(1);
}
void RemoveLogSink(LogSink::Ptr dest) {
std::lock_guard<std::mutex> _(g_sink_mutex);
g_sinks.erase(dest);
g_sink_count.fetch_sub(1);
}
void SetStderrLogging(LogSeverity min_severity) {}
void LogToStderr() {}
void LogToSinks(LogSeverity severity, const char *full_filename,
const char *base_filename, int line, const LogMessageTime &time,
const char *message, size_t message_len) {
std::lock_guard<std::mutex> _(g_sink_mutex);
for (auto &&sink : g_sinks) {
if (sink->ShouldLog(severity)) {
sink->Send(severity, full_filename, base_filename, line, time, message,
message_len);
} }
} ss << " " << GetLogSeverityName(severity)[0] << " ";
} ss << base_filename << ":" << line << " ";
void WaitForSinks() {
std::lock_guard<std::mutex> _(g_sink_mutex); // return google::LogSink::ToString(severity, file, line, logmsgtime.tm(),
for (auto &&sink : g_sinks) { // message, message_len);
sink->Flush();
} ss.write(message, message_len);
return ss.str();
} }
const char *GetLogSeverityName(LogSeverity severity) { static void
const static std::map<LogSeverity, const char *> severity_names = { ColoredWriteToStderrOrStdout(FILE *output, LogSeverity severity, const char *message, size_t len)
{TILE_INFO, "INFO"}, {
{TILE_WARNING, "WARNING"}, fwrite(message, len, 1, output);
{TILE_ERROR, "ERROR"}, fflush(output);
{TILE_FATAL, "FATAL"},
};
auto iter = severity_names.find(severity);
if (iter != severity_names.end()) {
return iter->second;
} else {
return "UNKNOWN";
}
} }
} // namespace tile void
ColoredWriteToStdout(LogSeverity severity, const char *message, size_t len)
{
FILE *output = stdout;
if (severity >= TILE_FATAL) { output = stderr; }
ColoredWriteToStderrOrStdout(output, severity, message, len);
}
void
ColoredWriteToStderr(LogSeverity severity, const char *message, size_t len)
{
ColoredWriteToStderrOrStdout(stderr, severity, message, len);
}
void
AddLogSink(LogSink::Ptr dest)
{
std::lock_guard<std::mutex> _(g_sink_mutex);
g_sinks.insert(dest);
g_sink_count.fetch_add(1);
}
void
RemoveLogSink(LogSink::Ptr dest)
{
std::lock_guard<std::mutex> _(g_sink_mutex);
g_sinks.erase(dest);
g_sink_count.fetch_sub(1);
}
void
SetStderrLogging(LogSeverity min_severity)
{}
void
LogToStderr()
{}
void
LogToSinks(LogSeverity severity,
const char *full_filename,
const char *base_filename,
int line,
const LogMessageTime &time,
const char *message,
size_t message_len)
{
std::lock_guard<std::mutex> _(g_sink_mutex);
for (auto &&sink : g_sinks) {
if (sink->ShouldLog(severity)) {
sink->Send(severity, full_filename, base_filename, line, time, message, message_len);
}
}
}
void
WaitForSinks()
{
std::lock_guard<std::mutex> _(g_sink_mutex);
for (auto &&sink : g_sinks) { sink->Flush(); }
}
const char *
GetLogSeverityName(LogSeverity severity)
{
const static std::map<LogSeverity, const char *> severity_names = {
{TILE_INFO, "INFO" },
{TILE_WARNING, "WARNING"},
{TILE_ERROR, "ERROR" },
{TILE_FATAL, "FATAL" },
};
auto iter = severity_names.find(severity);
if (iter != severity_names.end()) {
return iter->second;
} else {
return "UNKNOWN";
}
}
}// namespace tile

View File

@ -21,84 +21,93 @@ namespace tile {
// typedef int LogSeverity; // typedef int LogSeverity;
// const int TILE_INFO = 0, TILE_WARNING = 1, TILE_ERROR = 2, TILE_FATAL = 3; // const int TILE_INFO = 0, TILE_WARNING = 1, TILE_ERROR = 2, TILE_FATAL = 3;
enum LogSeverity { enum LogSeverity {
TILE_INFO = 0, TILE_INFO = 0,
TILE_WARNING = 1, TILE_WARNING = 1,
TILE_ERROR = 2, TILE_ERROR = 2,
TILE_FATAL = 3, TILE_FATAL = 3,
TILE_MAX_LOG_SEVERITY = TILE_FATAL TILE_MAX_LOG_SEVERITY = TILE_FATAL
}; };
bool VLogIsOn(int n); bool VLogIsOn(int n);
class LogStreamBuf : public std::streambuf { class LogStreamBuf : public std::streambuf {
public: public:
LogStreamBuf(char *buf, int len) { setp(buf, buf + len - 2); } LogStreamBuf(char *buf, int len) { setp(buf, buf + len - 2); }
int_type overflow(int_type ch) { return ch; } int_type overflow(int_type ch) { return ch; }
size_t pcount() const { return static_cast<size_t>(pptr() - pbase()); }
char *pbase() const { return std::streambuf::pbase(); } size_t pcount() const { return static_cast<size_t>(pptr() - pbase()); }
char *pbase() const { return std::streambuf::pbase(); }
}; };
class LogSink; class LogSink;
class LogMessageTime; class LogMessageTime;
class LogMessage { class LogMessage {
public: public:
class LogStream : public std::ostream { class LogStream : public std::ostream {
public: public:
LogStream(char *buf, int len, int64_t ctr) LogStream(char *buf, int len, int64_t ctr) : std::ostream(nullptr), streambuf_(buf, len), ctr_(ctr), self_(this)
: std::ostream(nullptr), streambuf_(buf, len), ctr_(ctr), self_(this) { {
rdbuf(&streambuf_); rdbuf(&streambuf_);
} }
LogStream(LogStream &other) noexcept LogStream(LogStream &other) noexcept
: std::ostream(nullptr), streambuf_(std::move(other.streambuf_)), : std::ostream(nullptr),
ctr_(internal::Exchange(other.ctr_, 0)), self_(this) { streambuf_(std::move(other.streambuf_)),
rdbuf(&streambuf_); ctr_(internal::Exchange(other.ctr_, 0)),
} self_(this)
{
rdbuf(&streambuf_);
}
LogStream &operator=(LogStream &&other) noexcept { LogStream &operator=(LogStream &&other) noexcept
streambuf_ = std::move(other.streambuf_); {
ctr_ = internal::Exchange(other.ctr_, 0); streambuf_ = std::move(other.streambuf_);
self_ = this; ctr_ = internal::Exchange(other.ctr_, 0);
rdbuf(&streambuf_); self_ = this;
return *this; rdbuf(&streambuf_);
} return *this;
}
int64_t ctr() const { return ctr_; } int64_t ctr() const { return ctr_; }
void set_ctr(int64_t ctr) { ctr_ = ctr; }
LogStream *self() { return self_; } void set_ctr(int64_t ctr) { ctr_ = ctr; }
size_t pcount() const { return streambuf_.pcount(); } LogStream *self() { return self_; }
char *pbase() const { return streambuf_.pbase(); }
char *str() const { return pbase(); }
LogStream(const LogStream &) = delete; size_t pcount() const { return streambuf_.pcount(); }
LogStream &operator=(const LogStream &) = delete;
private: char *pbase() const { return streambuf_.pbase(); }
LogStreamBuf streambuf_;
int64_t ctr_; char *str() const { return pbase(); }
LogStream *self_;
}; LogStream(const LogStream &) = delete;
LogStream &operator=(const LogStream &) = delete;
private:
LogStreamBuf streambuf_;
int64_t ctr_;
LogStream *self_;
};
public: public:
static const size_t kMaxLogMessageLen = 30000; static const size_t kMaxLogMessageLen = 30000;
LogMessage(const char *file, int line); LogMessage(const char *file, int line);
LogMessage(const char *file, int line, LogSeverity severity); LogMessage(const char *file, int line, LogSeverity severity);
LogMessage(const char *file, int line, LogSeverity severity, LogSink *sink, LogMessage(const char *file, int line, LogSeverity severity, LogSink *sink, bool also_send_to_log = true);
bool also_send_to_log = true);
~LogMessage(); ~LogMessage();
std::ostream &stream(); std::ostream &stream();
void Flush(); void Flush();
LogSeverity severity() const noexcept; LogSeverity severity() const noexcept;
int line() const noexcept; int line() const noexcept;
const char *fullname() const noexcept; const char *fullname() const noexcept;
const char *basename() const noexcept; const char *basename() const noexcept;
const LogMessageTime &time() const noexcept; const LogMessageTime &time() const noexcept;
int preserved_errno() const; int preserved_errno() const;
private: private:
class Impl; class Impl;
@ -107,9 +116,9 @@ private:
class LogMessageFatal : public LogMessage { class LogMessageFatal : public LogMessage {
public: public:
LogMessageFatal(const char *file, int line); LogMessageFatal(const char *file, int line);
~LogMessageFatal(); ~LogMessageFatal();
std::ostream &stream(); std::ostream &stream();
}; };
class LogMessageVoidify { class LogMessageVoidify {
@ -550,66 +559,88 @@ FormatLog(const char *file, int line, Ts &&...args) noexcept
namespace tile { namespace tile {
typedef double WallTime; typedef double WallTime;
struct LogMessageTime {
LogMessageTime();
LogMessageTime(std::tm t);
LogMessageTime(std::time_t timestamp, WallTime now);
LogMessageTime(std::chrono::system_clock::time_point tp);
const time_t &timestamp() const { return timestamp_; } struct LogMessageTime {
const int &sec() const { return time_struct_.tm_sec; } LogMessageTime();
const int32_t &usec() const { return usecs_; } LogMessageTime(std::tm t);
const int &(min)() const { return time_struct_.tm_min; } LogMessageTime(std::time_t timestamp, WallTime now);
const int &hour() const { return time_struct_.tm_hour; } LogMessageTime(std::chrono::system_clock::time_point tp);
const int &day() const { return time_struct_.tm_mday; }
const int &month() const { return time_struct_.tm_mon; } const time_t &timestamp() const { return timestamp_; }
const int &year() const { return time_struct_.tm_year; }
const int &dayOfWeek() const { return time_struct_.tm_wday; } const int &sec() const { return time_struct_.tm_sec; }
const int &dayInYear() const { return time_struct_.tm_yday; }
const int &dst() const { return time_struct_.tm_isdst; } const int32_t &usec() const { return usecs_; }
const long int &gmtoff() const { return gmtoffset_; }
const std::tm &tm() const { return time_struct_; } const int &(min) () const { return time_struct_.tm_min; }
const bool use_localtime() const { return use_localtime_; }
const int &hour() const { return time_struct_.tm_hour; }
const int &day() const { return time_struct_.tm_mday; }
const int &month() const { return time_struct_.tm_mon; }
const int &year() const { return time_struct_.tm_year; }
const int &dayOfWeek() const { return time_struct_.tm_wday; }
const int &dayInYear() const { return time_struct_.tm_yday; }
const int &dst() const { return time_struct_.tm_isdst; }
const long int &gmtoff() const { return gmtoffset_; }
const std::tm &tm() const { return time_struct_; }
const bool use_localtime() const { return use_localtime_; }
private: private:
void init(const std::tm &t, std::time_t timestamp, WallTime now); void init(const std::tm &t, std::time_t timestamp, WallTime now);
std::tm time_struct_; // Time of creation of LogMessage std::tm time_struct_;// Time of creation of LogMessage
time_t timestamp_; // Time of creation of LogMessage in seconds time_t timestamp_; // Time of creation of LogMessage in seconds
int32_t usecs_; // Time of creation of LogMessage - microseconds part int32_t usecs_; // Time of creation of LogMessage - microseconds part
long int gmtoffset_; long int gmtoffset_;
bool use_localtime_; bool use_localtime_;
void CalcGmtOffset(); void CalcGmtOffset();
}; };
class LogSink { class LogSink {
public: public:
using Ptr = std::shared_ptr<LogSink>; using Ptr = std::shared_ptr<LogSink>;
virtual ~LogSink(); virtual ~LogSink();
virtual bool ShouldLog(LogSeverity severity); virtual bool ShouldLog(LogSeverity severity);
virtual void Send(LogSeverity severity, const char *full_filename, virtual void Send(LogSeverity severity,
const char *base_filename, int line, const char *full_filename,
const LogMessageTime &logmsgtime, const char *message, const char *base_filename,
size_t message_len); int line,
virtual void Flush(); const LogMessageTime &logmsgtime,
std::string ToString(LogSeverity severity, const char *file, const char *message,
const char *base_file, int line, size_t message_len);
const LogMessageTime &logmsgtime, const char *message, virtual void Flush();
size_t message_len); std::string ToString(LogSeverity severity,
const char *file,
const char *base_file,
int line,
const LogMessageTime &logmsgtime,
const char *message,
size_t message_len);
}; };
void ColoredWriteToStdout(LogSeverity severity, const char *message, void ColoredWriteToStdout(LogSeverity severity, const char *message, size_t len);
size_t len); void ColoredWriteToStderr(LogSeverity severity, const char *message, size_t len);
void ColoredWriteToStderr(LogSeverity severity, const char *message,
size_t len);
void AddLogSink(LogSink::Ptr dest); void AddLogSink(LogSink::Ptr dest);
void RemoveLogSink(LogSink::Ptr dest); void RemoveLogSink(LogSink::Ptr dest);
void SetStderrLogging(LogSeverity min_severity); void SetStderrLogging(LogSeverity min_severity);
void LogToStderr(); void LogToStderr();
void LogToSinks(LogSeverity severity, const char *full_filename, void LogToSinks(LogSeverity severity,
const char *base_filename, int line, const LogMessageTime &time, const char *full_filename,
const char *message, size_t message_len); const char *base_filename,
int line,
const LogMessageTime &time,
const char *message,
size_t message_len);
void WaitForSinks(); void WaitForSinks();
const char *GetLogSeverityName(LogSeverity severity); const char *GetLogSeverityName(LogSeverity severity);

View File

@ -6,182 +6,244 @@
#include <mutex> #include <mutex>
namespace tile { namespace tile {
bool VLogIsOn(int n) { return true; } bool
VLogIsOn(int n)
{
return true;
}
class LogMessage::Impl { class LogMessage::Impl {
public: public:
Impl(const char *file, int line, int severity) : lm_(file, line, severity) {} Impl(const char *file, int line, int severity) : lm_(file, line, severity) {}
std::ostream &stream() { return lm_.stream(); }
std::ostream &stream() { return lm_.stream(); }
private: private:
google::LogMessage lm_; google::LogMessage lm_;
}; };
class LogMessageFatal::Impl { class LogMessageFatal::Impl {
public: public:
Impl(const char *file, int line) : lm_(file, line) {} Impl(const char *file, int line) : lm_(file, line) {}
std::ostream &stream() { return lm_.stream(); }
std::ostream &stream() { return lm_.stream(); }
private: private:
google::LogMessageFatal lm_; google::LogMessageFatal lm_;
}; };
LogMessage::LogMessage(const char *file, int line, int severity) LogMessage::LogMessage(const char *file, int line, int severity) : impl_(new Impl(file, line, severity)) {}
: impl_(new Impl(file, line, severity)) {}
LogMessage::~LogMessage() = default; LogMessage::~LogMessage() = default;
std::ostream &LogMessage::stream() { return impl_->stream(); }
LogMessageFatal::LogMessageFatal(const char *file, int line) std::ostream &
: impl_(new Impl(file, line)) {} LogMessage::stream()
{
return impl_->stream();
}
LogMessageFatal::LogMessageFatal(const char *file, int line) : impl_(new Impl(file, line)) {}
LogMessageFatal::~LogMessageFatal() = default; LogMessageFatal::~LogMessageFatal() = default;
std::ostream &LogMessageFatal::stream() { return impl_->stream(); }
} // namespace tile std::ostream &
LogMessageFatal::stream()
{
return impl_->stream();
}
}// namespace tile
namespace tile { namespace tile {
namespace internal { namespace internal {
namespace logging { namespace logging {
namespace { namespace {
std::vector<PrefixAppender *> *GetProviers() { std::vector<PrefixAppender *> *
static std::vector<PrefixAppender *> providers; GetProviers()
return &providers; {
static std::vector<PrefixAppender *> providers;
return &providers;
} }
} // namespace }// namespace
namespace details { namespace details {
std::string DescribeFormatArguments(const std::vector<std::string> &args) { std::string
return fmt::format("{}", fmt::join(args.begin(), args.end(), ", ")); DescribeFormatArguments(const std::vector<std::string> &args)
{
return fmt::format("{}", fmt::join(args.begin(), args.end(), ", "));
} }
} // namespace details }// namespace details
void InstallPrefixProvider(PrefixAppender *writer) {
GetProviers()->push_back(writer); void
InstallPrefixProvider(PrefixAppender *writer)
{
GetProviers()->push_back(writer);
} }
void WritePrefixTo(std::string *to) {
for (auto &&appender : *GetProviers()) { void
auto was = to->size(); WritePrefixTo(std::string *to)
appender(to); {
if (to->size() != was) { for (auto &&appender : *GetProviers()) {
to->push_back(' '); auto was = to->size();
appender(to);
if (to->size() != was) { to->push_back(' '); }
} }
}
} }
} // namespace logging }// namespace logging
} // namespace internal }// namespace internal
} // namespace tile }// namespace tile
namespace tile { namespace tile {
LogMessageTime::LogMessageTime() LogMessageTime::LogMessageTime() : time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {}
: time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {}
LogMessageTime::LogMessageTime(std::tm t) { LogMessageTime::LogMessageTime(std::tm t)
std::time_t timestamp = std::mktime(&t); {
init(t, timestamp, 0); std::time_t timestamp = std::mktime(&t);
init(t, timestamp, 0);
} }
LogMessageTime::LogMessageTime(std::time_t timestamp, WallTime now) { LogMessageTime::LogMessageTime(std::time_t timestamp, WallTime now)
std::tm t; {
if (FLAGS_log_utc_time) std::tm t;
gmtime_r(&timestamp, &t); if (FLAGS_log_utc_time)
else gmtime_r(&timestamp, &t);
localtime_r(&timestamp, &t); else
init(t, timestamp, now); localtime_r(&timestamp, &t);
init(t, timestamp, now);
} }
void LogMessageTime::init(const std::tm &t, std::time_t timestamp, void
WallTime now) { LogMessageTime::init(const std::tm &t, std::time_t timestamp, WallTime now)
time_struct_ = t; {
timestamp_ = timestamp; time_struct_ = t;
usecs_ = static_cast<std::int32_t>((now - timestamp) * 1000000); timestamp_ = timestamp;
usecs_ = static_cast<std::int32_t>((now - timestamp) * 1000000);
CalcGmtOffset(); CalcGmtOffset();
} }
void LogMessageTime::CalcGmtOffset() { void
std::tm gmt_struct; LogMessageTime::CalcGmtOffset()
int isDst = 0; {
if (FLAGS_log_utc_time) { std::tm gmt_struct;
localtime_r(&timestamp_, &gmt_struct); int isDst = 0;
isDst = gmt_struct.tm_isdst; if (FLAGS_log_utc_time) {
gmt_struct = time_struct_; localtime_r(&timestamp_, &gmt_struct);
} else { isDst = gmt_struct.tm_isdst;
isDst = time_struct_.tm_isdst; gmt_struct = time_struct_;
gmtime_r(&timestamp_, &gmt_struct); } else {
} isDst = time_struct_.tm_isdst;
gmtime_r(&timestamp_, &gmt_struct);
}
time_t gmt_sec = mktime(&gmt_struct); time_t gmt_sec = mktime(&gmt_struct);
const long hour_secs = 3600; const long hour_secs = 3600;
// If the Daylight Saving Time(isDst) is active subtract an hour from the // If the Daylight Saving Time(isDst) is active subtract an hour from the
// current timestamp. // current timestamp.
gmtoffset_ = gmtoffset_ = static_cast<long int>(timestamp_ - gmt_sec + (isDst ? hour_secs : 0));
static_cast<long int>(timestamp_ - gmt_sec + (isDst ? hour_secs : 0));
} }
LogSink::~LogSink() {} LogSink::~LogSink() {}
void LogSink::send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line,
const LogMessageTime &logmsgtime, const char *message,
size_t message_len) {
// do nothing void
LogSink::send(LogSeverity severity,
const char *full_filename,
const char *base_filename,
int line,
const LogMessageTime &logmsgtime,
const char *message,
size_t message_len)
{
// do nothing
} }
void LogSink::WaitTillSent() {}
std::string LogSink::ToString(LogSeverity severity, const char *file, int line, void
const LogMessageTime &logmsgtime, LogSink::WaitTillSent()
const char *message, size_t message_len) { {}
return google::LogSink::ToString(severity, file, line, logmsgtime.tm(),
message, message_len); std::string
LogSink::ToString(LogSeverity severity,
const char *file,
int line,
const LogMessageTime &logmsgtime,
const char *message,
size_t message_len)
{
return google::LogSink::ToString(severity, file, line, logmsgtime.tm(), message, message_len);
} }
class LogSinkWrapper : public google::LogSink { class LogSinkWrapper : public google::LogSink {
public: public:
LogSinkWrapper(tile::LogSink *dest) : dest_(dest) {} LogSinkWrapper(tile::LogSink *dest) : dest_(dest) {}
~LogSinkWrapper() override {}
void send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line,
const google::LogMessageTime &logmsgtime, const char *message,
size_t message_len) override {
dest_->send(severity, full_filename, base_filename, line, logmsgtime.tm(),
message, message_len);
}
void WaitTillSent() override { dest_->WaitTillSent(); } ~LogSinkWrapper() override {}
void send(LogSeverity severity,
const char *full_filename,
const char *base_filename,
int line,
const google::LogMessageTime &logmsgtime,
const char *message,
size_t message_len) override
{
dest_->send(severity, full_filename, base_filename, line, logmsgtime.tm(), message, message_len);
}
void WaitTillSent() override { dest_->WaitTillSent(); }
private: private:
tile::LogSink *dest_; tile::LogSink *dest_;
}; };
struct LogSinkPair { struct LogSinkPair {
struct LogSinWrapper *wrapper; struct LogSinWrapper *wrapper;
LogSink *sink; LogSink *sink;
}; };
static std::map<LogSink *, LogSinkWrapper *> sink_registry; static std::map<LogSink *, LogSinkWrapper *> sink_registry;
static std::mutex sink_registry_mutex; static std::mutex sink_registry_mutex;
void AddLogSink(LogSink *dest) { void
std::lock_guard<std::mutex> lock(sink_registry_mutex); AddLogSink(LogSink *dest)
if (sink_registry.find(dest) != sink_registry.end()) { {
return; std::lock_guard<std::mutex> lock(sink_registry_mutex);
} if (sink_registry.find(dest) != sink_registry.end()) { return; }
auto wrapper = new LogSinkWrapper(dest); auto wrapper = new LogSinkWrapper(dest);
sink_registry[dest] = wrapper; sink_registry[dest] = wrapper;
google::AddLogSink(wrapper); google::AddLogSink(wrapper);
} }
void RemoveLogSink(LogSink *dest) { void
std::lock_guard<std::mutex> lock(sink_registry_mutex); RemoveLogSink(LogSink *dest)
auto iter = sink_registry.find(dest); {
if (iter != sink_registry.end()) { std::lock_guard<std::mutex> lock(sink_registry_mutex);
google::RemoveLogSink(iter->second); auto iter = sink_registry.find(dest);
sink_registry.erase(iter); if (iter != sink_registry.end()) {
delete iter->second; google::RemoveLogSink(iter->second);
} sink_registry.erase(iter);
delete iter->second;
}
} }
void SetStderrLogging(LogSeverity min_severity) {
google::SetStderrLogging(min_severity); void
SetStderrLogging(LogSeverity min_severity)
{
google::SetStderrLogging(min_severity);
} }
void LogToStderr() { google::LogToStderr(); }
const char *GetLogSeverityName(LogSeverity severity) { void
return google::GetLogSeverityName(severity); LogToStderr()
{
google::LogToStderr();
} }
} // namespace tile
const char *
GetLogSeverityName(LogSeverity severity)
{
return google::GetLogSeverityName(severity);
}
}// namespace tile

View File

@ -9,17 +9,31 @@
#include <thread> #include <thread>
struct AwesomeLogSink : public tile::LogSink { struct AwesomeLogSink : public tile::LogSink {
virtual void Send(tile::LogSeverity severity, const char *full_filename, static std::shared_ptr<AwesomeLogSink> Create() { return std::make_shared<AwesomeLogSink>(); }
const char *base_filename, int line,
const tile::LogMessageTime &logmsgtime, const char *message, virtual void Send(tile::LogSeverity severity,
size_t message_len) override { const char *full_filename,
msgs.emplace_back(std::string(message, message_len)); const char *base_filename,
} int line,
std::vector<std::string> msgs; const tile::LogMessageTime &logmsgtime,
const char *message,
size_t message_len) override
{
msgs.emplace_back(std::string(message, message_len));
}
std::vector<std::string> msgs;
}; };
std::string my_prefix, my_prefix2; std::string my_prefix, my_prefix2;
void
ResetLogPrefix()
{
my_prefix.clear();
my_prefix2.clear();
}
void void
WriteLoggingPrefix(std::string *s) WriteLoggingPrefix(std::string *s)
{ {
@ -32,26 +46,26 @@ WriteLoggingPrefix2(std::string *s)
*s += my_prefix2; *s += my_prefix2;
} }
TEST(Logging, Prefix) { TEST(Logging, Prefix)
auto sink = std::make_shared<AwesomeLogSink>(); {
tile::AddLogSink(sink); auto sink = std::make_shared<AwesomeLogSink>();
tile::ScopedDeferred defered([&] { tile::RemoveLogSink(sink); }); tile::AddLogSink(sink);
tile::ScopedDeferred defered([&] { tile::RemoveLogSink(sink); });
TILE_LOG_INFO("something"); TILE_LOG_INFO("something");
my_prefix = "[prefix]"; my_prefix = "[prefix]";
TILE_LOG_INFO("something"); TILE_LOG_INFO("something");
my_prefix = "[prefix1]"; my_prefix = "[prefix1]";
TILE_LOG_INFO("something"); TILE_LOG_INFO("something");
my_prefix2 = "[prefix2]"; my_prefix2 = "[prefix2]";
TILE_LOG_INFO("something"); TILE_LOG_INFO("something");
ASSERT_THAT(sink->msgs, ASSERT_THAT(sink->msgs,
::testing::ElementsAre("something", "[prefix] something", ::testing::ElementsAre(
"[prefix1] something", "something", "[prefix] something", "[prefix1] something", "[prefix1] [prefix2] something"));
"[prefix1] [prefix2] something"));
} }
TEST(Logging, CHECK) TEST(Logging, CHECK)
@ -65,39 +79,21 @@ TEST(Logging, CHECK)
ASSERT_DEATH(([] { TILE_CHECK_NE(1, 1, "CHECK_NE"); }()), "CHECK_NE"); ASSERT_DEATH(([] { TILE_CHECK_NE(1, 1, "CHECK_NE"); }()), "CHECK_NE");
} }
TEST(Logging, Prefix)
{
AwesomeLogSink sink;
tile::AddLogSink(&sink);
tile::ScopedDeferred defered([&] { tile::RemoveLogSink(&sink); });
auto sink = std::make_shared<AwesomeLogSink>();
tile::AddLogSink(sink);
tile::ScopedDeferred defered([&] { tile::RemoveLogSink(sink); });
for (int i = 0; i < 30; i++) {
TILE_LOG_INFO_EVERY_SECOND("something");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
ASSERT_THAT(sink->msgs,
::testing::ElementsAre("something", "something", "something"));
}
TEST(Logging, DontPanicOnFormatFailure) { TILE_LOG_INFO("Don't panic!{}{}", 1); } TEST(Logging, DontPanicOnFormatFailure) { TILE_LOG_INFO("Don't panic!{}{}", 1); }
TEST(Logging, EverySecond) TEST(Logging, EverySecond)
{ {
ResetLogPrefix(); ResetLogPrefix();
AwesomeLogSink sink; auto sink = AwesomeLogSink::Create();
tile::AddLogSink(&sink); tile::AddLogSink(sink);
tile::ScopedDeferred defered([&] { tile::RemoveLogSink(&sink); }); tile::ScopedDeferred defered([&] { tile::RemoveLogSink(sink); });
for (int i = 0; i < 30; i++) { for (int i = 0; i < 30; i++) {
TILE_LOG_INFO_EVERY_SECOND("something"); TILE_LOG_INFO_EVERY_SECOND("something");
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} }
ASSERT_THAT(sink.msgs, ::testing::ElementsAre("something", "something", "something")); ASSERT_THAT(sink->msgs, ::testing::ElementsAre("something", "something", "something"));
} }
TEST(Logging, Enum) TEST(Logging, Enum)

View File

@ -1,24 +1,47 @@
#include "tile/base/logging/basic_file_sink.h" #include "tile/base/logging/basic_file_sink.h"
namespace tile { namespace tile {
BasicFileSink::Ptr BasicFileSink::Create(const std::string &filepath) { BasicFileSink::Ptr
auto sink = std::shared_ptr<BasicFileSink>(new BasicFileSink()); BasicFileSink::Create(const std::string &filepath)
sink->set_filepath(filepath); {
return sink; auto sink = std::shared_ptr<BasicFileSink>(new BasicFileSink());
sink->set_filepath(filepath);
return sink;
} }
BasicFileSink::BasicFileSink() {} BasicFileSink::BasicFileSink() {}
BasicFileSink::~BasicFileSink() {} BasicFileSink::~BasicFileSink() {}
void BasicFileSink::Send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line, void
const LogMessageTime &logmsgtime, const char *message, BasicFileSink::Send(LogSeverity severity,
size_t message_len) { const char *full_filename,
TILE_CHECK(!filepath_.empty(), "filepath is empty"); const char *base_filename,
ofs_ << std::string(message, message_len) << std::endl; int line,
const LogMessageTime &logmsgtime,
const char *message,
size_t message_len)
{
TILE_CHECK(!filepath_.empty(), "filepath is empty");
ofs_ << std::string(message, message_len) << std::endl;
} }
std::string BasicFileSink::filepath() const { return filepath_; }
void BasicFileSink::set_filepath(const std::string &filepath) { std::string
filepath_ = filepath; BasicFileSink::filepath() const
ofs_.open(filepath, std::ios::out | std::ios::app); {
return filepath_;
} }
void BasicFileSink::Flush() { ofs_.flush(); }
} // namespace tile void
BasicFileSink::set_filepath(const std::string &filepath)
{
filepath_ = filepath;
ofs_.open(filepath, std::ios::out | std::ios::app);
}
void
BasicFileSink::Flush()
{
ofs_.flush();
}
}// namespace tile

View File

@ -10,27 +10,30 @@
namespace tile { namespace tile {
class BasicFileSink : public LogSink { class BasicFileSink : public LogSink {
public: public:
using Ptr = std::shared_ptr<BasicFileSink>; using Ptr = std::shared_ptr<BasicFileSink>;
static Ptr Create(const std::string &filepath); static Ptr Create(const std::string &filepath);
~BasicFileSink() override; ~BasicFileSink() override;
void Send(LogSeverity severity, const char *full_filename, void Send(LogSeverity severity,
const char *base_filename, int line, const char *full_filename,
const LogMessageTime &logmsgtime, const char *message, const char *base_filename,
size_t message_len) override; int line,
void Flush() override; const LogMessageTime &logmsgtime,
const char *message,
size_t message_len) override;
void Flush() override;
std::string filepath() const; std::string filepath() const;
void set_filepath(const std::string &filepath); void set_filepath(const std::string &filepath);
protected: protected:
BasicFileSink(); BasicFileSink();
private: private:
std::string filepath_; std::string filepath_;
std::ofstream ofs_; std::ofstream ofs_;
}; };
} // namespace tile }// namespace tile
#endif // TILE_BASE_LOGGING_BASIC_FILE_SINK_H #endif// TILE_BASE_LOGGING_BASIC_FILE_SINK_H

View File

@ -1,32 +1,39 @@
#include "tile/base/logging/console_sink.h" #include "tile/base/logging/console_sink.h"
#include <stdio.h> #include <stdio.h>
namespace tile { namespace tile {
ConsoleSink::Ptr ConsoleSink::Create() { ConsoleSink::Ptr
return std::shared_ptr<ConsoleSink>(new ConsoleSink()); ConsoleSink::Create()
{
return std::shared_ptr<ConsoleSink>(new ConsoleSink());
} }
ConsoleSink::~ConsoleSink() {} ConsoleSink::~ConsoleSink() {}
void ConsoleSink::Send(LogSeverity severity, const char *full_filename, void
const char *base_filename, int line, ConsoleSink::Send(LogSeverity severity,
const LogMessageTime &logmsgtime, const char *message, const char *full_filename,
size_t message_len) { const char *base_filename,
auto msg = ToString(severity, full_filename, base_filename, line, logmsgtime, int line,
message, message_len); const LogMessageTime &logmsgtime,
while (!msg.empty() && msg.back() == '\n') { const char *message,
msg.pop_back(); size_t message_len)
} {
if (severity >= TILE_FATAL) { auto msg = ToString(severity, full_filename, base_filename, line, logmsgtime, message, message_len);
fprintf(stderr, "%s\n", msg.c_str()); while (!msg.empty() && msg.back() == '\n') { msg.pop_back(); }
} else { if (severity >= TILE_FATAL) {
fprintf(stdout, "%s\n", msg.c_str()); fprintf(stderr, "%s\n", msg.c_str());
} } else {
fprintf(stdout, "%s\n", msg.c_str());
}
} }
void ConsoleSink::Flush() {} void
ConsoleSink::Flush()
{}
ConsoleSink::ConsoleSink() {} ConsoleSink::ConsoleSink() {}
} // namespace tile }// namespace tile

View File

@ -4,22 +4,26 @@
#pragma once #pragma once
#include "tile/base/internal/logging.h" #include "tile/base/internal/logging.h"
namespace tile { namespace tile {
class ConsoleSink : public LogSink { class ConsoleSink : public LogSink {
public: public:
using Ptr = std::shared_ptr<ConsoleSink>; using Ptr = std::shared_ptr<ConsoleSink>;
static Ptr Create(); static Ptr Create();
~ConsoleSink() override; ~ConsoleSink() override;
void Send(LogSeverity severity, const char *full_filename, void Send(LogSeverity severity,
const char *base_filename, int line, const char *full_filename,
const LogMessageTime &logmsgtime, const char *message, const char *base_filename,
size_t message_len) override; int line,
void Flush() override; const LogMessageTime &logmsgtime,
const char *message,
size_t message_len) override;
void Flush() override;
protected: protected:
ConsoleSink(); ConsoleSink();
}; };
} // namespace tile }// namespace tile
#endif // TILE_BASE_LOGGING_CONSOLE_SINK_H #endif// TILE_BASE_LOGGING_CONSOLE_SINK_H

View File

@ -2,62 +2,78 @@
#include <cassert> #include <cassert>
namespace tile { namespace tile {
std::shared_ptr<SplitterSink> SplitterSink::Create() { std::shared_ptr<SplitterSink>
return std::shared_ptr<SplitterSink>(new SplitterSink()); SplitterSink::Create()
{
return std::shared_ptr<SplitterSink>(new SplitterSink());
} }
std::shared_ptr<SplitterSink> SplitterSink::Create( std::shared_ptr<SplitterSink>
std::initializer_list<std::shared_ptr<LogSink>> init_list) { SplitterSink::Create(std::initializer_list<std::shared_ptr<LogSink>> init_list)
auto sink = Create(); {
for (auto &s : init_list) { auto sink = Create();
sink->AddSink(s); for (auto &s : init_list) { sink->AddSink(s); }
} return sink;
return sink;
} }
SplitterSink::SplitterSink() {} SplitterSink::SplitterSink() {}
SplitterSink::~SplitterSink() {} SplitterSink::~SplitterSink() {}
void SplitterSink::Send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line, void
const LogMessageTime &logmsgtime, const char *message, SplitterSink::Send(LogSeverity severity,
size_t message_len) { const char *full_filename,
assert(!doing_ && "SplitterSink::send() should not be called recursively"); const char *base_filename,
std::lock_guard<std::mutex> _(sinks_mutex_); int line,
doing_ = true; const LogMessageTime &logmsgtime,
for (auto &sink : sinks_) { const char *message,
sink->Send(severity, full_filename, base_filename, line, logmsgtime, size_t message_len)
message, message_len); {
} assert(!doing_ && "SplitterSink::send() should not be called recursively");
doing_ = false; std::lock_guard<std::mutex> _(sinks_mutex_);
doing_ = true;
for (auto &sink : sinks_) {
sink->Send(severity, full_filename, base_filename, line, logmsgtime, message, message_len);
}
doing_ = false;
} }
void SplitterSink::Flush() { void
assert(!doing_ && "SplitterSink::send() should not be called recursively"); SplitterSink::Flush()
std::lock_guard<std::mutex> _(sinks_mutex_); {
doing_ = true; assert(!doing_ && "SplitterSink::send() should not be called recursively");
for (auto &sink : sinks_) { std::lock_guard<std::mutex> _(sinks_mutex_);
sink->Flush(); doing_ = true;
} for (auto &sink : sinks_) { sink->Flush(); }
doing_ = false; doing_ = false;
} }
void SplitterSink::AddSink(std::shared_ptr<LogSink> sink) { void
std::lock_guard<std::mutex> _(sinks_mutex_); SplitterSink::AddSink(std::shared_ptr<LogSink> sink)
sinks_.insert(sink); {
std::lock_guard<std::mutex> _(sinks_mutex_);
sinks_.insert(sink);
} }
void SplitterSink::RemoveSink(std::shared_ptr<LogSink> sink) { void
std::lock_guard<std::mutex> _(sinks_mutex_); SplitterSink::RemoveSink(std::shared_ptr<LogSink> sink)
sinks_.erase(sink); {
std::lock_guard<std::mutex> _(sinks_mutex_);
sinks_.erase(sink);
} }
void SplitterSink::ClearSinks() { void
std::lock_guard<std::mutex> _(sinks_mutex_); SplitterSink::ClearSinks()
sinks_.clear(); {
} std::lock_guard<std::mutex> _(sinks_mutex_);
std::set<LogSink::Ptr> SplitterSink::sinks() { sinks_.clear();
std::lock_guard<std::mutex> _(sinks_mutex_);
return sinks_;
} }
} // namespace tile std::set<LogSink::Ptr>
SplitterSink::sinks()
{
std::lock_guard<std::mutex> _(sinks_mutex_);
return sinks_;
}
}// namespace tile

View File

@ -10,31 +10,34 @@
namespace tile { namespace tile {
class SplitterSink : public LogSink { class SplitterSink : public LogSink {
public: public:
using Ptr = std::shared_ptr<SplitterSink>; using Ptr = std::shared_ptr<SplitterSink>;
static Ptr Create(); static Ptr Create();
static Ptr Create(std::initializer_list<std::shared_ptr<LogSink>> init_list); static Ptr Create(std::initializer_list<std::shared_ptr<LogSink>> init_list);
~SplitterSink() override; ~SplitterSink() override;
void Send(LogSeverity severity, const char *full_filename, void Send(LogSeverity severity,
const char *base_filename, int line, const char *full_filename,
const LogMessageTime &logmsgtime, const char *message, const char *base_filename,
size_t message_len) override; int line,
void Flush() override; const LogMessageTime &logmsgtime,
const char *message,
size_t message_len) override;
void Flush() override;
void AddSink(std::shared_ptr<LogSink> sink); void AddSink(std::shared_ptr<LogSink> sink);
void RemoveSink(std::shared_ptr<LogSink> sink); void RemoveSink(std::shared_ptr<LogSink> sink);
void ClearSinks(); void ClearSinks();
std::set<LogSink::Ptr> sinks(); std::set<LogSink::Ptr> sinks();
protected: protected:
SplitterSink(); SplitterSink();
private: private:
std::set<std::shared_ptr<LogSink>> sinks_; std::set<std::shared_ptr<LogSink>> sinks_;
std::mutex sinks_mutex_; std::mutex sinks_mutex_;
bool doing_ = false; bool doing_ = false;
}; };
} // namespace tile }// namespace tile
#endif // TILE_BASE_LOGGING_SPLITTER_SINK_H #endif// TILE_BASE_LOGGING_SPLITTER_SINK_H

View File

@ -4,53 +4,57 @@
namespace tile { namespace tile {
class SimpleSink : public LogSink { class SimpleSink : public LogSink {
public: public:
using Ptr = std::shared_ptr<SimpleSink>; using Ptr = std::shared_ptr<SimpleSink>;
static Ptr Create() { return std::shared_ptr<SimpleSink>(new SimpleSink()); }
void Send(LogSeverity severity, const char *full_filename, static Ptr Create() { return std::shared_ptr<SimpleSink>(new SimpleSink()); }
const char *base_filename, int line,
const LogMessageTime &logmsgtime, const char *message, void Send(LogSeverity severity,
size_t message_len) override { const char *full_filename,
message_ = std::string(message, message_len); const char *base_filename,
} int line,
void Flush() override {} const LogMessageTime &logmsgtime,
std::string message_; const char *message,
size_t message_len) override
{
message_ = std::string(message, message_len);
}
void Flush() override {}
std::string message_;
}; };
TEST(SplitterSink, One) { TEST(SplitterSink, One)
auto sink = SimpleSink::Create(); {
auto splitter = SplitterSink::Create({sink}); auto sink = SimpleSink::Create();
splitter->Send(LogSeverity::TILE_INFO, nullptr, nullptr, 0, LogMessageTime(), auto splitter = SplitterSink::Create({sink});
"message", 7); splitter->Send(LogSeverity::TILE_INFO, nullptr, nullptr, 0, LogMessageTime(), "message", 7);
ASSERT_EQ(sink->message_, "message"); ASSERT_EQ(sink->message_, "message");
} }
TEST(SplitterSink, Two) { TEST(SplitterSink, Two)
auto sink1 = SimpleSink::Create(); {
auto sink2 = SimpleSink::Create(); auto sink1 = SimpleSink::Create();
auto splitter = SplitterSink::Create({sink1, sink2}); auto sink2 = SimpleSink::Create();
splitter->Send(LogSeverity::TILE_INFO, nullptr, nullptr, 0, LogMessageTime(), auto splitter = SplitterSink::Create({sink1, sink2});
"message", 7); splitter->Send(LogSeverity::TILE_INFO, nullptr, nullptr, 0, LogMessageTime(), "message", 7);
ASSERT_EQ(sink1->message_, "message"); ASSERT_EQ(sink1->message_, "message");
ASSERT_EQ(sink2->message_, "message"); ASSERT_EQ(sink2->message_, "message");
} }
TEST(SplitterSink, Multi) { TEST(SplitterSink, Multi)
auto splitter = SplitterSink::Create(); {
for (int i = 0; i < 100; i++) { auto splitter = SplitterSink::Create();
splitter->AddSink(SimpleSink::Create()); for (int i = 0; i < 100; i++) { splitter->AddSink(SimpleSink::Create()); }
}
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
std::stringstream ss; std::stringstream ss;
ss << "message" << i; ss << "message" << i;
auto msg = ss.str(); auto msg = ss.str();
splitter->Send(LogSeverity::TILE_INFO, nullptr, nullptr, 0, splitter->Send(LogSeverity::TILE_INFO, nullptr, nullptr, 0, LogMessageTime(), msg.data(), msg.size());
LogMessageTime(), msg.data(), msg.size());
for (auto &sink : splitter->sinks()) { for (auto &sink : splitter->sinks()) { ASSERT_EQ(std::static_pointer_cast<SimpleSink>(sink)->message_, msg); }
ASSERT_EQ(std::static_pointer_cast<SimpleSink>(sink)->message_, msg);
} }
}
} }
} // namespace tile }// namespace tile

View File

@ -32,12 +32,14 @@ namespace {
std::atomic<bool> g_quit_siganl{false}; std::atomic<bool> g_quit_siganl{false};
void QuitSignalHandler(int sig) { void
auto old = g_quit_siganl.exchange(true, std::memory_order_relaxed); QuitSignalHandler(int sig)
if (old && FLAGS_tile_abort_on_double_quit_signal) { {
// TODO: Add TILE_RAW_LOG auto old = g_quit_siganl.exchange(true, std::memory_order_relaxed);
// RAW_LOG(FATAL, "Double quit signal received. Crashing the program"); if (old && FLAGS_tile_abort_on_double_quit_signal) {
} // TODO: Add TILE_RAW_LOG
// RAW_LOG(FATAL, "Double quit signal received. Crashing the program");
}
} }
void void
@ -52,22 +54,23 @@ InstallQuitSignalHandler()
} }
}// namespace }// namespace
int Start(int argc, char **argv, std::function<int(int, char **)> cb, int
bool single_thread, bool enable_crash_catch) { Start(int argc, char **argv, std::function<int(int, char **)> cb, bool single_thread, bool enable_crash_catch)
if (enable_crash_catch) { {
// TODO: Add InstallFailureSignalHandler if (enable_crash_catch) {
// google::InstallFailureSignalHandler(); // TODO: Add InstallFailureSignalHandler
} // google::InstallFailureSignalHandler();
}
// Init gflags // Init gflags
gflags::SetVersionString(TILE_VERSION); gflags::SetVersionString(TILE_VERSION);
gflags::ParseCommandLineFlags(&argc, &argv, true); gflags::ParseCommandLineFlags(&argc, &argv, true);
detail::ApplyFlagOverrider(); detail::ApplyFlagOverrider();
AddLogSink(ConsoleSink::Create()); AddLogSink(ConsoleSink::Create());
// TODO: Add Init log level // TODO: Add Init log level
// google::InitGoogleLogging(argv[0]); // google::InitGoogleLogging(argv[0]);
TILE_LOG_INFO("Tile started. version: {}", TILE_VERSION); TILE_LOG_INFO("Tile started. version: {}", TILE_VERSION);

View File

@ -10,27 +10,29 @@ namespace tile {
namespace testing { namespace testing {
namespace { namespace {
int StartBenchmark(int argc, char **argv) { int
::benchmark::Initialize(&argc, argv); StartBenchmark(int argc, char **argv)
if (::benchmark::ReportUnrecognizedArguments(argc, argv)) { {
return 1; ::benchmark::Initialize(&argc, argv);
} if (::benchmark::ReportUnrecognizedArguments(argc, argv)) { return 1; }
::benchmark::RunSpecifiedBenchmarks(); ::benchmark::RunSpecifiedBenchmarks();
::benchmark::Shutdown(); ::benchmark::Shutdown();
return 0; return 0;
} }
} // namespace }// namespace
int InitAndRunAllBenchmarks(int *argc, char **argv) { int
InitAndRunAllBenchmarks(int *argc, char **argv)
{
// if (gflags::GetCommandLineFlagInfoOrDie("logtostderr").is_default) { // if (gflags::GetCommandLineFlagInfoOrDie("logtostderr").is_default) {
// FLAGS_logtostderr = true; // FLAGS_logtostderr = true;
// } // }
return Start(*argc, argv, StartBenchmark, true); return Start(*argc, argv, StartBenchmark, true);
} }
} // namespace testing }// namespace testing
} // namespace tile }// namespace tile
TILE_BENCHMARK_MAIN TILE_BENCHMARK_MAIN