fix: accurate timestamp in daemon logs (#7009)

* fix: accurate timestamp in daemon logs

* fix: gtk build errors

* fixup! fix: gtk build errors

* code review: use system_clock typedefs

* code review: use the full buffer for string view

* fixup! fix: accurate timestamp in daemon logs

* code review: limit exposure of `using`
This commit is contained in:
Yat Ho 2024-08-14 06:57:52 +08:00 committed by GitHub
parent 1ae39f8725
commit 04c115f79c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 45 additions and 23 deletions

View File

@ -5,6 +5,7 @@
#include <array> #include <array>
#include <cerrno> #include <cerrno>
#include <chrono>
#include <cstdio> /* printf */ #include <cstdio> /* printf */
#include <iostream> #include <iostream>
#include <iterator> /* std::back_inserter */ #include <iterator> /* std::back_inserter */
@ -269,6 +270,7 @@ auto onFileAdded(tr_session* session, std::string_view dirname, std::string_view
void printMessage( void printMessage(
FILE* ostream, FILE* ostream,
std::chrono::system_clock::time_point now,
tr_log_level level, tr_log_level level,
std::string_view name, std::string_view name,
std::string_view message, std::string_view message,
@ -288,9 +290,9 @@ void printMessage(
if (ostream != nullptr) if (ostream != nullptr)
{ {
auto timestr = std::array<char, 64>{}; auto buf = std::array<char, 64>{};
tr_logGetTimeStr(std::data(timestr), std::size(timestr)); auto const timestr = tr_logGetTimeStr(now, std::data(buf), std::size(buf));
fmt::print(ostream, "[{:s}] {:s} {:s}\n", std::data(timestr), levelName(level), out.c_str()); fmt::print(ostream, "[{:s}] {:s} {:s}\n", timestr, levelName(level), out.c_str());
} }
#ifdef HAVE_SYSLOG #ifdef HAVE_SYSLOG
@ -329,13 +331,24 @@ void printMessage(
#endif #endif
} }
void printMessage(
FILE* ostream,
tr_log_level level,
std::string_view name,
std::string_view message,
std::string_view filename,
long line)
{
printMessage(ostream, std::chrono::system_clock::now(), level, name, message, filename, line);
}
void pumpLogMessages(FILE* log_stream) void pumpLogMessages(FILE* log_stream)
{ {
tr_log_message* list = tr_logGetQueue(); tr_log_message* list = tr_logGetQueue();
for (tr_log_message const* l = list; l != nullptr; l = l->next) for (tr_log_message const* l = list; l != nullptr; l = l->next)
{ {
printMessage(log_stream, l->level, l->name, l->message, l->file, l->line); printMessage(log_stream, l->when, l->level, l->name, l->message, l->file, l->line);
} }
// two reasons to not flush stderr: // two reasons to not flush stderr:

View File

@ -37,6 +37,7 @@
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <array> #include <array>
#include <chrono>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <utility> #include <utility>
@ -201,11 +202,12 @@ void MessageLogWindow::Impl::level_combo_changed_cb(Gtk::ComboBox* combo_box)
namespace namespace
{ {
using std::chrono::system_clock;
/* similar to asctime, but is utf8-clean */ /* similar to asctime, but is utf8-clean */
Glib::ustring gtr_asctime(time_t t) Glib::ustring gtr_asctime(system_clock::time_point t)
{ {
return Glib::DateTime::create_now_local(t).format("%a %b %e %T %Y"); /* ctime equiv */ return Glib::DateTime::create_now_local(system_clock::to_time_t(t)).format("%a %b %e %T %Y"); /* ctime equiv */
} }
} // namespace } // namespace
@ -324,7 +326,7 @@ void renderText(
void renderTime(Gtk::CellRendererText* renderer, Gtk::TreeModel::const_iterator const& iter) void renderTime(Gtk::CellRendererText* renderer, Gtk::TreeModel::const_iterator const& iter)
{ {
auto const* const node = iter->get_value(message_log_cols.tr_msg); auto const* const node = iter->get_value(message_log_cols.tr_msg);
renderer->property_text() = Glib::DateTime::create_now_local(node->when).format("%T"); renderer->property_text() = Glib::DateTime::create_now_local(std::chrono::system_clock::to_time_t(node->when)).format("%T");
setForegroundColor(renderer, node->level); setForegroundColor(renderer, node->level);
} }

View File

@ -111,7 +111,7 @@ void logAddImpl(
{ {
auto* const newmsg = new tr_log_message{}; auto* const newmsg = new tr_log_message{};
newmsg->level = level; newmsg->level = level;
newmsg->when = tr_time(); newmsg->when = std::chrono::system_clock::now();
newmsg->message = std::move(msg); newmsg->message = std::move(msg);
newmsg->file = file; newmsg->file = file;
newmsg->line = line; newmsg->line = line;
@ -133,16 +133,16 @@ void logAddImpl(
} }
else else
{ {
auto timestr = std::array<char, 64U>{}; auto buf = std::array<char, 64U>{};
tr_logGetTimeStr(std::data(timestr), std::size(timestr)); auto const timestr = tr_logGetTimeStr(std::data(buf), std::size(buf));
if (std::empty(name)) if (std::empty(name))
{ {
fmt::print(stderr, "[{:s}] {:s}\n", std::data(timestr), msg); fmt::print(stderr, "[{:s}] {:s}\n", timestr, msg);
} }
else else
{ {
fmt::print("[{:s}] {:s}: {:s}\n", std::data(timestr), name, msg); fmt::print("[{:s}] {:s}: {:s}\n", timestr, name, msg);
} }
} }
#endif #endif
@ -194,19 +194,23 @@ void tr_logFreeQueue(tr_log_message* freeme)
// --- // ---
char* tr_logGetTimeStr(char* buf, size_t buflen) std::string_view tr_logGetTimeStr(std::chrono::system_clock::time_point now, char* buf, size_t buflen)
{ {
auto const a = std::chrono::system_clock::now(); auto const now_tm = fmt::localtime(std::chrono::system_clock::to_time_t(now));
auto const a_tm = fmt::localtime(std::chrono::system_clock::to_time_t(a)); auto const subseconds = now - std::chrono::time_point_cast<std::chrono::seconds>(now);
auto const subseconds = a - std::chrono::time_point_cast<std::chrono::seconds>(a);
auto const [out, len] = fmt::format_to_n( auto const [out, len] = fmt::format_to_n(
buf, buf,
buflen - 1, buflen,
"{0:%FT%T.}{1:0>3%Q}{0:%z}", "{0:%FT%T.}{1:0>3%Q}{0:%z}",
a_tm, now_tm,
std::chrono::duration_cast<std::chrono::milliseconds>(subseconds)); std::chrono::duration_cast<std::chrono::milliseconds>(subseconds));
*out = '\0'; return { buf, len };
return buf; }
std::string_view tr_logGetTimeStr(char* buf, size_t buflen)
{
auto const a = std::chrono::system_clock::now();
return tr_logGetTimeStr(a, buf, buflen);
} }
void tr_logAddMessage(char const* file, long line, tr_log_level level, std::string&& msg, std::string_view name) void tr_logAddMessage(char const* file, long line, tr_log_level level, std::string&& msg, std::string_view name)

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <chrono>
#include <cstddef> // size_t #include <cstddef> // size_t
#include <ctime> #include <ctime>
#include <optional> #include <optional>
@ -53,7 +54,7 @@ struct tr_log_message
long line; long line;
// when the message was generated // when the message was generated
time_t when; std::chrono::system_clock::time_point when;
// torrent name or code module name associated with the message // torrent name or code module name associated with the message
std::string name; std::string name;
@ -110,4 +111,5 @@ void tr_logAddMessage(
// --- // ---
char* tr_logGetTimeStr(char* buf, size_t buflen); std::string_view tr_logGetTimeStr(std::chrono::system_clock::time_point now, char* buf, size_t buflen);
std::string_view tr_logGetTimeStr(char* buf, size_t buflen);

View File

@ -250,9 +250,10 @@ static NSTimeInterval const kUpdateSeconds = 0.75;
auto const file_string = std::string{ currentMessage->file }; auto const file_string = std::string{ currentMessage->file };
NSString* file = [(@(file_string.c_str())).lastPathComponent stringByAppendingFormat:@":%ld", currentMessage->line]; NSString* file = [(@(file_string.c_str())).lastPathComponent stringByAppendingFormat:@":%ld", currentMessage->line];
auto const secs_since_1970 = std::chrono::system_clock::to_time_t(currentMessage->when);
NSDictionary* message = @{ NSDictionary* message = @{
@"Message" : @(currentMessage->message.c_str()), @"Message" : @(currentMessage->message.c_str()),
@"Date" : [NSDate dateWithTimeIntervalSince1970:currentMessage->when], @"Date" : [NSDate dateWithTimeIntervalSince1970:secs_since_1970],
@"Index" : @(currentIndex++), //more accurate when sorting by date @"Index" : @(currentIndex++), //more accurate when sorting by date
@"Level" : @(currentMessage->level), @"Level" : @(currentMessage->level),
@"Name" : name, @"Name" : name,