power_play/src/base/base_win32/base_win32_log.c
2025-11-08 21:27:32 -06:00

154 lines
4.5 KiB
C

W32_SharedLogState W32_shared_log_state = ZI;
////////////////////////////////////////////////////////////
//~ @hookdef Init hooks
void InitLogSystem(String logfile_path)
{
__prof;
W32_SharedLogState *g = &W32_shared_log_state;
g->logs_arena = AcquireArena(Gibi(64));
g->log_msgs_arena = AcquireArena(Gibi(64));
g->readable_log_events = ArenaNext(g->logs_arena, LogEvent);
if (logfile_path.len > 0)
{
TempArena scratch = BeginScratchNoConflict();
{
wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path);
g->logfile = CreateFileW(path_wstr,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
}
EndScratch(scratch);
}
Atomic32Set(&g->initialized, 1);
}
////////////////////////////////////////////////////////////
//~ Log
void W32_Log(i32 level, String msg)
{
__prof;
W32_SharedLogState *g = &W32_shared_log_state;
TempArena scratch = BeginScratchNoConflict();
if (Atomic32Fetch(&g->initialized))
{
LogLevelSettings settings = log_settings[level];
if (level < 0 || level >= LogLevel_Count)
{
Panic(Lit("Invalid log level"));
}
__profmsg((char *)msg.text, msg.len, settings.color);
DateTime datetime = LocalDateTime();
i64 now_ns = TimeNs();
i32 thread_id = GetCurrentThreadId();
i32 fiber_id = FiberId();
//- Log message to file
/* TODO: Log asynchronously */
{
String shorthand = settings.shorthand;
String msg_formatted = StringF(
scratch.arena,
"[%F:%F:%F.%F] |%F| <%F> [%F] %F\n",
/* Time */
FmtUintZ(datetime.hour, 2),
FmtUintZ(datetime.minute, 2),
FmtUintZ(datetime.second, 2),
FmtUintZ(datetime.milliseconds, 3),
/* Thread id */
FmtUintZ(thread_id, 5),
/* Fiber id */
FmtUintZ(fiber_id, 4),
/* Level */
FmtString(shorthand),
/* Message */
FmtString(msg)
);
WriteFile(g->logfile, msg_formatted.text, msg_formatted.len, 0, 0);
}
//- Log message to queue
/* TODO: Log asynchronously */
LockTicketMutex(&g->logs_tm);
{
/* Get staged data */
LogEvent *ev = PushStruct(g->logs_arena, LogEvent);
ev->msg = PushString(g->log_msgs_arena, msg);
ev->datetime = datetime;
ev->time_ns = now_ns;
ev->level = level;
ev->thread_id = thread_id;
ev->fiber_id = fiber_id;
ev->id = g->logs_count++;
ev->level_id = g->log_level_counts[level]++;
Atomic64Set(&g->readable_logs_count, g->logs_count);
}
UnlockTicketMutex(&g->logs_tm);
}
EndScratch(scratch);
}
////////////////////////////////////////////////////////////
//~ @hookdef Log hooks
/* Panic log function is separate to enforce zero side effects other than
* immediately writing to log file. */
void LogPanic(String msg)
{
W32_SharedLogState *g = &W32_shared_log_state;
if (Atomic32Fetch(&g->initialized))
{
String beg = Lit("******** PANICKING ********\n");
String end = Lit("\n***************************\n");
WriteFile(g->logfile, beg.text, beg.len, 0, 0);
WriteFile(g->logfile, msg.text, msg.len, 0, 0);
WriteFile(g->logfile, end.text, end.len, 0, 0);
}
}
void Log_(i32 level, String msg)
{
W32_Log(level, msg);
}
void LogF_(i32 level, String fmt, ...)
{
W32_SharedLogState *g = &W32_shared_log_state;
if (Atomic32Fetch(&g->initialized))
{
TempArena scratch = BeginScratchNoConflict();
va_list args;
va_start(args, fmt);
{
String msg = FormatStringV(scratch.arena, fmt, args);
W32_Log(level, msg);
}
va_end(args);
EndScratch(scratch);
}
}
LogEventsArray GetLogEvents(void)
{
W32_SharedLogState *g = &W32_shared_log_state;
LogEventsArray result = ZI;
result.count = Atomic64Fetch(&g->readable_logs_count);
if (result.count > 0)
{
result.logs = g->readable_log_events;
}
return result;
}