feat(log): implement all log methods except SLogDump, SLogPend

This commit is contained in:
VDm 2024-02-18 01:49:12 +04:00
parent ec148a9af8
commit bc71b135a0
2 changed files with 322 additions and 71 deletions

View file

@ -4,10 +4,19 @@
#include "storm/Memory.hpp" #include "storm/Memory.hpp"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <ctime>
#if defined(WHOA_SYSTEM_LINUX) #if defined(WHOA_SYSTEM_LINUX)
# include <sys/stat.h> # include <sys/stat.h>
# include <sys/types.h> # include <sys/types.h>
#endif #endif
#if defined(WHOA_SYSTEM_MAC)
# include <mach/mach_time.h>
#endif
#define STORM_LOG_MAX_CHANNELS 4
#define STORM_LOG_MAX_BUFFER 0x10000
#define STORM_LOG_FLUSH_POINT 0xC000
typedef struct _LOG { typedef struct _LOG {
@ -16,25 +25,25 @@ typedef struct _LOG {
char filename[STORM_MAX_PATH]; char filename[STORM_MAX_PATH];
FILE* file; FILE* file;
uint32_t flags; uint32_t flags;
uint32_t bufferused; size_t bufferused;
uint32_t pendpoint; size_t pendpoint;
int32_t indent; int32_t indent;
int32_t timeStamp; int32_t timeStamp;
char buffer[0x10000]; char buffer[STORM_LOG_MAX_BUFFER];
} LOG; } LOG;
static uint32_t lasttime; static uint64_t lasttime = 0;
static uint32_t timestrlen; static size_t timestrlen = 0;
static char timestr[64]; static char timestr[64] = { '\0' };
static SCritSect* s_critsect[4]; static SCritSect* s_critsect[STORM_LOG_MAX_CHANNELS] = { nullptr };
static SCritSect* s_defaultdir_critsect; static SCritSect* s_defaultdir_critsect = nullptr;
static LOG* s_loghead[4]; static LOG* s_loghead[STORM_LOG_MAX_CHANNELS] = { nullptr };
static HSLOG s_sequence = 0; static HSLOG s_sequence = 0;
static char s_defaultdir[STORM_MAX_PATH]; static char s_defaultdir[STORM_MAX_PATH] = { '\0' };
static bool s_logsysteminit = false; static bool s_logsysteminit = false;
@ -56,11 +65,13 @@ static LOG* LockLog(HSLOG log, HLOCKEDLOG* lockedhandle, bool createifnecessary)
result = result->next; result = result->next;
} }
if (result) if (result) {
return result; return result;
}
if (createifnecessary) if (createifnecessary) {
result = (LOG*)SMemAlloc(sizeof(LOG), __FILE__, __LINE__, 0); result = (LOG*)SMemAlloc(sizeof(LOG), __FILE__, __LINE__, 0);
}
if (!result) { if (!result) {
s_critsect[index]->Leave(); s_critsect[index]->Leave();
@ -102,8 +113,9 @@ static void UnlockDeleteLog(LOG* logptr, HLOCKEDLOG lockedhandle) {
} }
static void FlushLog(LOG* logptr) { static void FlushLog(LOG* logptr) {
if (!logptr->bufferused) if (!logptr->bufferused) {
return; return;
}
STORM_ASSERT(logptr->file); STORM_ASSERT(logptr->file);
fwrite(logptr->buffer, 1, logptr->bufferused, logptr->file); fwrite(logptr->buffer, 1, logptr->bufferused, logptr->file);
@ -114,8 +126,9 @@ static void FlushLog(LOG* logptr) {
static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize, const char* filename) static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize, const char* filename)
{ {
if (!filename || !filename[0] || filename[1] == ':' || SStrChr(filename, '\\') || SStrChr(filename, '/')) if (!filename || !filename[0] || filename[1] == ':' || SStrChr(filename, '\\') || SStrChr(filename, '/')) {
return filename; return filename;
}
s_defaultdir_critsect->Enter(); s_defaultdir_critsect->Enter();
@ -126,8 +139,9 @@ static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
GetModuleFileNameA(NULL, newfilename, newfilenamesize); GetModuleFileNameA(NULL, newfilename, newfilenamesize);
char* slash = SStrChrR(newfilename, '\\'); char* slash = SStrChrR(newfilename, '\\');
if (slash) if (slash) {
slash[0] = '\0'; slash[0] = '\0';
}
SStrPack(newfilename, "\\", newfilenamesize); SStrPack(newfilename, "\\", newfilenamesize);
SStrPack(newfilename, filename, newfilenamesize); SStrPack(newfilename, filename, newfilenamesize);
@ -135,12 +149,14 @@ static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize
#if defined(WHOA_SYSTEM_LINUX) #if defined(WHOA_SYSTEM_LINUX)
char buffer[PATH_MAX]; char buffer[PATH_MAX];
if (!realpath("/proc/self/exe", buffer)) if (!realpath("/proc/self/exe", buffer)) {
buffer[0] = '\0'; buffer[0] = '\0';
}
char* slash = SStrChrR(buffer, '/'); char* slash = SStrChrR(buffer, '/');
if (slash) if (slash) {
slash[0] = '\0'; slash[0] = '\0';
}
SStrCopy(newfilename, buffer, newfilenamesize); SStrCopy(newfilename, buffer, newfilenamesize);
SStrPack(newfilename, "/", newfilenamesize); SStrPack(newfilename, "/", newfilenamesize);
@ -157,61 +173,71 @@ static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize
} }
static size_t PathGetRootChars(const char* path) { static size_t PathGetRootChars(const char* path) {
if (path[0] == '/') if (path[0] == '/') {
if (!SStrCmpI(path, "/Volumes/", 9)) {
const char* offset = SStrChr(path + 9, '/');
if (offset) {
return offset - path + 1;
}
}
return 1; return 1;
}
size_t length = SStrLen(path); if (SStrLen(path) < 2) {
if (length < 2)
return 0; return 0;
}
if (path[1] == ':') if (path[1] == ':') {
return (path[2] == '\\') ? 3 : 2; return (path[2] == '\\') ? 3 : 2;
}
if (path[0] != '\\' || path[1] != '\\') if (path[0] != '\\' || path[1] != '\\') {
return 0; return 0;
}
const char* v5 = path + 2; const char* slash1 = SStrChr(path + 2, '\\');
size_t v6 = 2; if (!slash1) {
do { return 0;
if (v5) }
v5 = SStrChr(v5, '\\') + 1;
--v6;
} while (v6);
if (v5) const char* slash2 = SStrChr(slash1 + 1, '\\');
return v5 - path; if (!slash2) {
return 0;
}
return length; return slash2 - path + 1;
} }
static void PathStripFilename(char* path) { static void PathStripFilename(char* path) {
char* v2; // edi char* slash = SStrChrR(path, '/');
char* v3; // eax char* backslash = SStrChrR(path, '\\');
char* v4; // eax if (slash <= backslash) {
slash = backslash;
}
v2 = SStrChrR(path, '\\'); if (!slash) {
v3 = SStrChrR(path, '/'); return;
if (v2 <= v3) }
v2 = v3;
if (v2) { char* relative = &path[PathGetRootChars(path)];
v4 = &path[PathGetRootChars(path)]; if (slash >= relative) {
if (v2 >= v4) slash[1] = 0;
v2[1] = 0; }
else else {
*v4 = 0; relative[0] = 0;
} }
} }
static void PathConvertSlashes(char* path) { static void PathConvertSlashes(char* path) {
while (*path) { while (*path) {
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
if (*path == '/') if (*path == '/') {
*path = '\\'; *path = '\\';
}
#else #else
if (*path == '\\') if (*path == '\\') {
*path = '/'; *path = '/';
}
#endif #endif
path++; path++;
} }
@ -224,21 +250,22 @@ static bool CreateFileDirectory(const char* path) {
SStrCopy(buffer, path, STORM_MAX_PATH); SStrCopy(buffer, path, STORM_MAX_PATH);
PathStripFilename(buffer); PathStripFilename(buffer);
char* v1 = &buffer[PathGetRootChars(buffer)]; char* relative = &buffer[PathGetRootChars(buffer)];
PathConvertSlashes(v1); PathConvertSlashes(relative);
for (size_t i = 0; v1[i]; ++i) { for (size_t i = 0; relative[i]; ++i) {
if (v1[i] != '\\' && v1[i] != '/') if (relative[i] != '\\' && relative[i] != '/') {
continue; continue;
}
char slash = v1[i]; char slash = relative[i];
v1[i] = '\0'; relative[i] = '\0';
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
CreateDirectoryA(buffer, NULL); CreateDirectoryA(buffer, NULL);
#else #else
mkdir(buffer, 0755); mkdir(buffer, 0755);
#endif #endif
v1[i] = slash; relative[i] = slash;
} }
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
@ -261,35 +288,124 @@ static bool OpenLogFile(const char* filename, FILE** file, uint32_t flags) {
return false; return false;
} }
void SLogInitialize() { static void OutputIndent(LOG* logptr) {
if (s_logsysteminit) int32_t indent = logptr->indent;
return; if (indent > 0) {
if (indent >= 128) {
indent = 128;
}
memset(&logptr->buffer[logptr->bufferused], ' ', indent);
logptr->buffer[indent + logptr->bufferused] = 0;
logptr->bufferused += indent;
}
}
for (size_t i = 0; i < sizeof(s_loghead) / sizeof(s_loghead[0]); ++i) static void OutputReturn(LOG* logptr) {
// strcpy(&logptr->buffer[logptr->bufferused], "\r\n");
// logptr->bufferused += 2;
// No need to write "\r\n" with fopen() in text mode
logptr->buffer[logptr->bufferused] = '\n';
logptr->bufferused++;
}
static void OutputTime(LOG* logptr, bool show) {
if (logptr->timeStamp == 0) {
return;
}
uint64_t ticks = 0;
#if defined(WHOA_SYSTEM_WIN)
ticks = GetTickCount64();
#endif
#if defined(WHOA_SYSTEM_LINUX)
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) {
ticks = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}
#endif
#if defined(WHOA_SYSTEM_MAC)
ticks = mach_absolute_time();
#endif
if (ticks != lasttime) {
lasttime = ticks;
time_t t = time(nullptr);
struct tm* ts = localtime(&t);
// No milliseconds for now
timestrlen = SStrPrintf(timestr,
sizeof(timestr),
"%d/%d %02d:%02d:%02d.%03d ",
ts->tm_mon + 1,
ts->tm_mday,
ts->tm_hour,
ts->tm_min,
ts->tm_sec,
0);
}
if (show) {
memcpy(&logptr->buffer[logptr->bufferused], timestr, timestrlen);
} else {
memset(&logptr->buffer[logptr->bufferused], ' ', timestrlen);
}
logptr->bufferused += timestrlen;
logptr->buffer[logptr->bufferused] = '\0';
}
static bool PrepareLog(LOG* logptr) {
if (logptr->file) {
return true;
}
if (OpenLogFile(logptr->filename, &logptr->file, logptr->flags)) {
return true;
}
logptr->filename[0] = '\0';
return false;
}
void SLogInitialize() {
if (s_logsysteminit) {
return;
}
for (size_t i = 0; i < STORM_LOG_MAX_CHANNELS; ++i) {
s_critsect[i] = new SCritSect(); s_critsect[i] = new SCritSect();
}
s_defaultdir_critsect = new SCritSect(); s_defaultdir_critsect = new SCritSect();
s_logsysteminit = true; s_logsysteminit = true;
} }
bool SLogIsInitialized() { int SLogIsInitialized() {
return s_logsysteminit; return s_logsysteminit ? 1 : 0;
} }
void SLogDestroy() { void SLogDestroy() {
// TODO: SLogFlushAll(); for (size_t i = 0; i < STORM_LOG_MAX_CHANNELS; ++i) {
// TODO: for (...) { SLogClose } s_critsect[i]->Enter();
for (LOG* log = s_loghead[i]; log; log = log->next) {
for (size_t i = 0; i < sizeof(s_loghead) / sizeof(s_loghead[0]); ++i) if (log->file) {
FlushLog(log);
fclose(log->file);
}
}
s_critsect[i]->Leave();
delete s_critsect[i]; delete s_critsect[i];
}
delete s_defaultdir_critsect; delete s_defaultdir_critsect;
s_logsysteminit = false; s_logsysteminit = false;
} }
uint32_t SLogCreate(const char* filename, uint32_t flags, HSLOG* log) { int SLogCreate(const char* filename, uint32_t flags, HSLOG* log) {
STORM_ASSERT(filename); STORM_ASSERT(filename);
STORM_ASSERT(*filename); STORM_ASSERT(*filename);
STORM_ASSERT(log); STORM_ASSERT(log);
@ -299,8 +415,7 @@ uint32_t SLogCreate(const char* filename, uint32_t flags, HSLOG* log) {
*log = 0; *log = 0;
if (flags & 2) if (flags & 2) {
{
filename = ""; filename = "";
flags &= ~1u; flags &= ~1u;
} }
@ -325,13 +440,15 @@ uint32_t SLogCreate(const char* filename, uint32_t flags, HSLOG* log) {
} }
void SLogClose(HSLOG log) { void SLogClose(HSLOG log) {
if (!s_logsysteminit) if (!s_logsysteminit) {
return; return;
}
HLOCKEDLOG lockedhandle; HLOCKEDLOG lockedhandle;
LOG* logptr = LockLog(log, &lockedhandle, false); LOG* logptr = LockLog(log, &lockedhandle, false);
if (!logptr) if (!logptr) {
return; return;
}
if (logptr->file) { if (logptr->file) {
FlushLog(logptr); FlushLog(logptr);
@ -340,3 +457,122 @@ void SLogClose(HSLOG log) {
UnlockDeleteLog(logptr, lockedhandle); UnlockDeleteLog(logptr, lockedhandle);
} }
void SLogFlush(HSLOG log) {
HLOCKEDLOG lockedhandle;
LOG* logptr = LockLog(log, &lockedhandle, false);
if (logptr) {
if (logptr->file) {
FlushLog(logptr);
}
UnlockLog(lockedhandle);
}
}
void SLogFlushAll() {
for (size_t i = 0; i < STORM_LOG_MAX_CHANNELS; ++i) {
s_critsect[i]->Enter();
for (LOG* log = s_loghead[i]; log; log = log->next) {
if (log->file) {
FlushLog(log);
}
}
s_critsect[i]->Leave();
}
}
void SLogGetDefaultDirectory(char* dirname, size_t dirnamesize) {
s_defaultdir_critsect->Enter();
SStrCopy(dirname, s_defaultdir, dirnamesize);
s_defaultdir_critsect->Leave();
}
void SLogSetDefaultDirectory(const char* dirname) {
s_defaultdir_critsect->Enter();
size_t size = SStrCopy(s_defaultdir, dirname, STORM_MAX_PATH);
PathConvertSlashes(s_defaultdir);
#if defined(WHOA_SYSTEM_WIN)
char slash = '\\';
#else
char slash = '/';
#endif
if (size < STORM_MAX_PATH - 1 && s_defaultdir[size - 1] != slash) {
s_defaultdir[size] = slash;
s_defaultdir[size + 1] = 0;
}
s_defaultdir_critsect->Leave();
}
int32_t SLogSetAbsIndent(HSLOG log, int32_t indent) {
HLOCKEDLOG lockedhandle;
LOG* logptr = LockLog(log, &lockedhandle, false);
if (logptr) {
int32_t result = logptr->indent;
logptr->indent = indent;
UnlockLog(lockedhandle);
return result;
}
return 0;
}
int32_t SLogSetIndent(HSLOG log, int32_t deltaIndent) {
HLOCKEDLOG lockedhandle;
LOG* logptr = LockLog(log, &lockedhandle, false);
if (logptr) {
int32_t result = logptr->indent;
logptr->indent = result + deltaIndent;
UnlockLog(lockedhandle);
return result;
}
return 0;
}
void SLogSetTimestamp(HSLOG log, int32_t timeStamp) {
HLOCKEDLOG lockedhandle;
LOG* logptr = LockLog(log, &lockedhandle, false);
if (logptr) {
logptr->timeStamp = timeStamp;
UnlockLog(lockedhandle);
}
}
void SLogVWrite(HSLOG log, const char* format, va_list arglist) {
HLOCKEDLOG lockedhandle;
LOG* logptr = LockLog(log, &lockedhandle, false);
if (!logptr) {
return;
}
if (PrepareLog(logptr)) {
OutputTime(logptr, true);
OutputIndent(logptr);
int count = vsnprintf(
&logptr->buffer[logptr->bufferused],
STORM_LOG_MAX_BUFFER - logptr->bufferused,
format,
arglist);
if (count > 0) {
logptr->bufferused += count;
}
OutputReturn(logptr);
#if defined(WHOA_SYSTEM_WIN)
// if (g_opt.echotooutputdebugstring)
OutputDebugStringA(&logptr->buffer[logptr->pendpoint]);
#endif
logptr->pendpoint = logptr->bufferused;
if (logptr->bufferused >= STORM_LOG_FLUSH_POINT) {
FlushLog(logptr);
}
}
UnlockLog(lockedhandle);
}
void SLogWrite(HSLOG log, const char* format, ...) {
va_list arglist;
va_start(arglist, format);
SLogVWrite(log, format, arglist);
}

View file

@ -10,4 +10,19 @@ DECLARE_STRICT_HANDLE(HSLOG);
DECLARE_STRICT_HANDLE(HLOCKEDLOG); DECLARE_STRICT_HANDLE(HLOCKEDLOG);
void SLogInitialize();
int SLogIsInitialized();
void SLogDestroy();
int SLogCreate(const char* filename, uint32_t flags, HSLOG* log);
void SLogClose(HSLOG log);
void SLogFlush(HSLOG log);
void SLogFlushAll();
void SLogGetDefaultDirectory(char* dirname, size_t dirnamesize);
void SLogSetDefaultDirectory(const char* dirname);
int32_t SLogSetAbsIndent(HSLOG log, int32_t indent);
int32_t SLogSetIndent(HSLOG log, int32_t deltaIndent);
void SLogVWrite(HSLOG log, const char* format, va_list arglist);
void SLogWrite(HSLOG log, const char* format, ...);
#endif #endif