1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 13:18:13 +00:00

AK: Print timestamp, process name, and pid on all platforms

This requires duplicating some logic from Core::Process::get_name()
into AK, which seems unfortunate. But for now, this greatly improves the
log messages for testing Ladybird on Linux.

The feature is hidden behind a runtime flag with a global setter in the
same way that totally enabling/disabling dbgln is.
This commit is contained in:
Andrew Kaster 2023-12-08 13:52:20 -07:00 committed by Andrew Kaster
parent 87cbc63334
commit 4db5e2ba22
2 changed files with 87 additions and 27 deletions

View file

@ -21,9 +21,11 @@
# include <Kernel/Tasks/Thread.h> # include <Kernel/Tasks/Thread.h>
# include <Kernel/Time/TimeManagement.h> # include <Kernel/Time/TimeManagement.h>
#else #else
# include <AK/LexicalPath.h>
# include <math.h> # include <math.h>
# include <stdio.h> # include <stdio.h>
# include <string.h> # include <string.h>
# include <time.h>
#endif #endif
#if defined(AK_OS_ANDROID) #if defined(AK_OS_ANDROID)
@ -1127,6 +1129,44 @@ void vout(LogLevel log_level, StringView fmtstr, TypeErasedFormatParams& params,
#endif #endif
#ifndef KERNEL
// FIXME: Deduplicate with Core::Process:get_name()
[[gnu::used]] static DeprecatedString process_name_helper()
{
# if defined(AK_OS_SERENITY)
char buffer[BUFSIZ] = {};
int rc = get_process_name(buffer, BUFSIZ);
if (rc != 0)
return DeprecatedString {};
return StringView { buffer, strlen(buffer) };
# elif defined(AK_LIBC_GLIBC) || (defined(AK_OS_LINUX) && !defined(AK_OS_ANDROID))
return StringView { program_invocation_name, strlen(program_invocation_name) };
# elif defined(AK_OS_BSD_GENERIC) || defined(AK_OS_HAIKU)
auto const* progname = getprogname();
return StringView { progname, strlen(progname) };
# else
// FIXME: Implement process_name_helper() for other platforms.
return StringView {};
# endif
}
static StringView process_name_for_logging()
{
// NOTE: We use AK::Format in the DynamicLoader and LibC, which cannot use thread-safe statics
// Also go to extraordinary lengths here to avoid strlen() on the process name every call to dbgln
static char process_name_buf[256] = {};
static StringView process_name;
static bool process_name_retrieved = false;
if (!process_name_retrieved) {
auto path = LexicalPath(process_name_helper());
process_name_retrieved = true;
(void)path.basename().copy_characters_to_buffer(process_name_buf, sizeof(process_name_buf));
process_name = { process_name_buf, strlen(process_name_buf) };
}
return process_name;
}
#endif
static bool is_debug_enabled = true; static bool is_debug_enabled = true;
void set_debug_enabled(bool value) void set_debug_enabled(bool value)
@ -1134,6 +1174,19 @@ void set_debug_enabled(bool value)
is_debug_enabled = value; is_debug_enabled = value;
} }
// On Serenity, dbgln goes to a non-stderr output
static bool is_rich_debug_enabled =
#if defined(AK_OS_SERENITY)
true;
#else
false;
#endif
void set_rich_debug_enabled(bool value)
{
is_rich_debug_enabled = value;
}
void vdbg(StringView fmtstr, TypeErasedFormatParams& params, bool newline) void vdbg(StringView fmtstr, TypeErasedFormatParams& params, bool newline)
{ {
if (!is_debug_enabled) if (!is_debug_enabled)
@ -1141,37 +1194,43 @@ void vdbg(StringView fmtstr, TypeErasedFormatParams& params, bool newline)
StringBuilder builder; StringBuilder builder;
#ifdef AK_OS_SERENITY if (is_rich_debug_enabled) {
# ifdef KERNEL #ifdef KERNEL
if (Kernel::Processor::is_initialized() && TimeManagement::is_initialized()) { if (Kernel::Processor::is_initialized() && TimeManagement::is_initialized()) {
auto time = TimeManagement::the().monotonic_time(TimePrecision::Coarse); auto time = TimeManagement::the().monotonic_time(TimePrecision::Coarse);
if (Kernel::Thread::current()) { if (Kernel::Thread::current()) {
auto& thread = *Kernel::Thread::current(); auto& thread = *Kernel::Thread::current();
thread.process().name().with([&](auto& process_name) { thread.process().name().with([&](auto& process_name) {
builder.appendff("{}.{:03} \033[34;1m[#{} {}({}:{})]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id(), process_name.representable_view(), thread.pid().value(), thread.tid().value()); builder.appendff("{}.{:03} \033[34;1m[#{} {}({}:{})]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id(), process_name.representable_view(), thread.pid().value(), thread.tid().value());
}); });
} else {
builder.appendff("{}.{:03} \033[34;1m[#{} Kernel]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id());
}
} else { } else {
builder.appendff("{}.{:03} \033[34;1m[#{} Kernel]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id()); builder.appendff("\033[34;1m[Kernel]\033[0m: ");
} }
} else { #else
builder.appendff("\033[34;1m[Kernel]\033[0m: "); auto process_name = process_name_for_logging();
} if (!process_name.is_empty()) {
# else struct timespec ts = {};
static TriState got_process_name = TriState::Unknown; clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
static char process_name_buffer[256]; auto pid = getpid();
# ifndef AK_OS_MACOS
if (got_process_name == TriState::Unknown) { // Darwin doesn't handle thread IDs the same way other Unixes do
if (get_process_name(process_name_buffer, sizeof(process_name_buffer)) == 0) auto tid = gettid();
got_process_name = TriState::True; if (pid == tid)
else
got_process_name = TriState::False;
}
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
if (got_process_name == TriState::True)
builder.appendff("{}.{:03} \033[33;1m{}({}:{})\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000, process_name_buffer, getpid(), gettid());
# endif # endif
{
builder.appendff("{}.{:03} \033[33;1m{}({})\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000, process_name, pid);
}
# ifndef AK_OS_MACOS
else {
builder.appendff("{}.{:03} \033[33;1m{}({}:{})\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000, process_name, pid, tid);
}
# endif
}
#endif #endif
}
MUST(vformat(builder, fmtstr, params)); MUST(vformat(builder, fmtstr, params));
if (newline) if (newline)

View file

@ -691,6 +691,7 @@ void dbgln(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... par
inline void dbgln() { dbgln(""); } inline void dbgln() { dbgln(""); }
void set_debug_enabled(bool); void set_debug_enabled(bool);
void set_rich_debug_enabled(bool);
#ifdef KERNEL #ifdef KERNEL
void vdmesgln(StringView fmtstr, TypeErasedFormatParams&); void vdmesgln(StringView fmtstr, TypeErasedFormatParams&);