implemented ServerLogger colors

This commit is contained in:
Timerix 2025-11-25 18:22:55 +05:00
parent 8bc98a321d
commit 2686ca6bcf
14 changed files with 93 additions and 274 deletions

2
dependencies/tlibc vendored

@ -1 +1 @@
Subproject commit 82bd234d08e2556ae37fff8e414a72c5caaa355b Subproject commit 4c97787c27af5b7867c8a1262a3383a84a1d4957

View File

@ -10,17 +10,19 @@ typedef enum LogSeverity {
LogSeverity_Error, LogSeverity_Error,
} LogSeverity; } LogSeverity;
typedef void (*LogFunction_t)(void* logger, LogSeverity severity, cstr context, cstr msg); typedef void (*LogFunction_t)(void* logger, cstr context, LogSeverity severity, cstr msg);
#define log(severity, context, format, ...) { \
// requires defined LOGGER, LOG_FUNC, LOG_CONTEXT
#define log(severity, format, ...) { \
if(LOG_FUNC) { \ if(LOG_FUNC) { \
char* ___log_msg = sprintf_malloc(format ,##__VA_ARGS__); \ char* ___log_msg = sprintf_malloc(format ,##__VA_ARGS__); \
LOG_FUNC(LOGGER, severity, context, ___log_msg); \ LOG_FUNC(LOGGER, LOG_CONTEXT, severity, ___log_msg); \
free(___log_msg); \ free(___log_msg); \
} \ } \
} }
#define logDebug(context, format, ...) log(LogSeverity_Debug, context, format ,##__VA_ARGS__) #define logDebug(format, ...) log(LogSeverity_Debug, format ,##__VA_ARGS__)
#define logInfo(context, format, ...) log(LogSeverity_Info, context, format ,##__VA_ARGS__) #define logInfo(format, ...) log(LogSeverity_Info, format ,##__VA_ARGS__)
#define logWarn(context, format, ...) log(LogSeverity_Warn, context, format ,##__VA_ARGS__) #define logWarn(format, ...) log(LogSeverity_Warn, format ,##__VA_ARGS__)
#define logError(context, format, ...) log(LogSeverity_Error, context, format ,##__VA_ARGS__) #define logError(format, ...) log(LogSeverity_Error, format ,##__VA_ARGS__)

View File

@ -1,7 +1,7 @@
#include "tlibc/filesystem.h" #include "tlibc/filesystem.h"
#include "tlibc/term.h"
#include "tcp-chat/common_constants.h" #include "tcp-chat/common_constants.h"
#include "cli/ClientCLI/ClientCLI.h" #include "cli/ClientCLI/ClientCLI.h"
#include "cli/term.h"
#include "network/tcp-chat-protocol/v1.h" #include "network/tcp-chat-protocol/v1.h"
static const str greeting_art = STR( static const str greeting_art = STR(

View File

@ -1,24 +1,62 @@
#include "modes.h" #include "modes.h"
#include "tcp-chat/server.h" #include "tcp-chat/server.h"
#include "tlibc/time.h" #include "tlibc/time.h"
#include "tlibc/term.h"
#include <pthread.h>
typedef struct ServerLogger {
pthread_mutex_t mutex;
} ServerLogger;
static void log_func(void* logger, LogSeverity severity, cstr context, cstr msg){ void ServerLogger_construct(ServerLogger* self){
(void)logger; try_fatal_stderrcode(pthread_mutex_init(&self->mutex, NULL));
try_fatal_void(term_init());
}
void ServerLogger_destroy(ServerLogger* self){
pthread_mutex_destroy(&self->mutex);
term_resetColors();
}
static void log_func(void* _logger, cstr context, LogSeverity severity, cstr msg){
ServerLogger* logger = _logger;
cstr severity_cstr; cstr severity_cstr;
Color16 fg;
switch(severity){ switch(severity){
default: severity_cstr = "INVALID_LOG_SEVERITY"; break; default:
case LogSeverity_Debug: severity_cstr = "DBUG"; break; severity_cstr = "INVALID_LOG_SEVERITY";
case LogSeverity_Info: severity_cstr = "INFO"; break; fg = Color16_DarkRed;
case LogSeverity_Warn: severity_cstr = "WARN"; break; break;
case LogSeverity_Error: severity_cstr = "ERRR"; break; case LogSeverity_Debug:
severity_cstr = "DBUG";
fg = Color16_Gray;
break;
case LogSeverity_Info:
severity_cstr = "INFO";
fg = Color16_White;
break;
case LogSeverity_Warn:
severity_cstr = "WARN";
fg = Color16_Yellow;
break;
case LogSeverity_Error:
severity_cstr = "EROR";
fg = Color16_Red;
break;
} }
pthread_mutex_lock(&logger->mutex);
DateTime dt; DateTime dt;
DateTime_getLocal(&dt); DateTime_getLocal(&dt);
term_setFgColor16(fg);
printf("[" FMT_DateTime_text "][%s/%s]: %s\n", DT_expand(dt), context, severity_cstr, msg); printf("[" FMT_DateTime_text "][%s/%s]: %s\n", DT_expand(dt), context, severity_cstr, msg);
term_setFgColor16(Color16_Magenta);
pthread_mutex_unlock(&logger->mutex);
} }
Result(void) run_ServerMode(cstr config_path) { Result(void) run_ServerMode(cstr config_path) {
@ -34,8 +72,13 @@ Result(void) run_ServerMode(cstr config_path) {
Defer(Array_u8_destroy(&config_buf)); Defer(Array_u8_destroy(&config_buf));
str config_str = Array_u8_castTo_str(config_buf, false); str config_str = Array_u8_castTo_str(config_buf, false);
// create logger
ServerLogger logger;
ServerLogger_construct(&logger);
Defer(ServerLogger_destroy(&logger));
// init server // init server
try(Server* server, p, Server_create(config_str, NULL, log_func)); try(Server* server, p, Server_create(config_str, &logger, log_func));
Defer(Server_free(server)); Defer(Server_free(server));
// manually close file and free config_buf // manually close file and free config_buf

View File

@ -1,189 +0,0 @@
#include "term.h"
#if defined(_WIN64) || defined(_WIN32)
#include <windows.h>
#define try_win_bool(EXPR) if(!(EXPR)) { Return RESULT_ERROR_FMT(#EXPR " failed with WindowsError %lu", GetLastError()); }
#else
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#define try_zero_errno(EXPR) if((EXPR) != 0) { \
char* errno_s = strerror_malloc(errno); \
ResultVar(void) err = RESULT_ERROR_FMT(#EXPR " failed with errno: %s", strerror(errno)); \
free(errno_s); \
Return err; \
}
#endif
Result(void) term_init(){
Deferral(8);
#if defined(_WIN64) || defined(_WIN32)
DWORD mode = 0;
HANDLE console_handle;
// configure stdout
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
try_assert(console_handle != INVALID_HANDLE_VALUE);
GetConsoleMode(console_handle, &mode);
// https://learn.microsoft.com/en-us/windows/console/setconsolemode
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
mode |= ENABLE_PROCESSED_OUTPUT;
mode |= DISABLE_NEWLINE_AUTO_RETURN;
SetConsoleMode(console_handle, mode);
// configure stderr
console_handle = GetStdHandle(STD_ERROR_HANDLE);
try_assert(console_handle != INVALID_HANDLE_VALUE);
GetConsoleMode(console_handle, &mode);
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
mode |= ENABLE_PROCESSED_OUTPUT;
mode |= DISABLE_NEWLINE_AUTO_RETURN;
SetConsoleMode(console_handle, mode);
// configure stdin
console_handle = GetStdHandle(STD_INPUT_HANDLE);
try_assert(console_handle != INVALID_HANDLE_VALUE);
GetConsoleMode(console_handle, &mode);
mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
SetConsoleMode(console_handle, mode);
#endif
Return RESULT_VOID;
}
i64 getenv_int(const char* var_name){
char* s = getenv(var_name);
if(s == NULL)
return -1;
return strtoll(s, NULL, 0);
}
Result(void) term_getSize(TerminalSize* out) {
Deferral(4);
#if defined(_WIN64) || defined(_WIN32)
// helps when STD_OUT is redirected to a file
HANDLE console_handle_stderr = GetStdHandle(STD_ERROR_HANDLE);
try_assert(console_handle_stderr != INVALID_HANDLE_VALUE)
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
try_win_bool(GetConsoleScreenBufferInfo(console_handle_stderr, &consoleInfo));
out->cols = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1;
out->rows = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1;
#else
struct winsize ws = {0};
// try to get terminal size from stdin, stdout, stderr
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0 ||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 ||
ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == 0 ){
out->cols = ws.ws_col;
out->rows = ws.ws_row;
}
// try to get size from environtent variables
else {
out->cols = getenv_int("COLUMNS");
out->rows = getenv_int("LINES");
}
#endif
try_assert(out->cols > 0);
try_assert(out->rows > 0);
Return RESULT_VOID;
}
Result(void) term_readLine(char* buf, u32 bufsize) {
Deferral(1);
if(fgets(buf, bufsize, stdin) == NULL){
try_stderrcode(ferror(stdin));
}
Return RESULT_VOID;
}
Result(void) term_readLineHidden(char *buf, u32 bufsize) {
Deferral(4);
#if defined(_WIN64) || defined(_WIN32)
HANDLE console_handle_stdin = GetStdHandle(STD_INPUT_HANDLE);
try_assert(console_handle_stdin != INVALID_HANDLE_VALUE);
DWORD old_mode;
GetConsoleMode(console_handle_stdin, &old_mode);
// turn off echo
DWORD new_mode = old_mode & ~(ENABLE_ECHO_INPUT);
SetConsoleMode(console_handle_stdin, new_mode);
// restore echo
Defer(SetConsoleMode(console_handle_stdin, old_mode));
#else
struct termios old_mode, new_mode;
try_zero_errno(tcgetattr(STDIN_FILENO, &old_mode));
new_mode = old_mode;
// turn off echo
new_mode.c_lflag &= ~(ECHO);
try_zero_errno(tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_mode));
// restore echo
Defer(tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_mode));
#endif
// read line
try_void(term_readLine(buf, bufsize));
fputc('\n', stdout);
Return RESULT_VOID;
}
/*
Most of escape sequences can be found there
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
*/
#define ESC "\x1b"
#define CSI ESC"["
void term_setFgColor16(Color16 c){
printf(CSI"%um", c);
}
void term_setBgColor16(Color16 c){
printf(CSI"%um", c + 10);
}
void term_bold(){
printf(CSI"1m");
}
void term_italic(){
printf(CSI"3m");
}
void term_underline(){
printf(CSI"4m");
}
void term_strikethrough(){
printf(CSI"9m");
}
void term_resetCursor() {
printf(CSI"H");
}
void term_resetColors() {
printf(CSI"0m");
}
void term_clear() {
printf(CSI"0m" CSI"H" CSI"2J");
}
void term_eraseRow(){
printf(CSI"2K\r");
}
void term_cursorMove(u16 row, u16 column) {
printf(CSI"%u;%uH", row, column);
}
void term_cursorHide() {
printf(CSI"?25l");
}
void term_cursorShow() {
printf(CSI"?25h");
}

View File

@ -1,47 +0,0 @@
#pragma once
#include "tlibc/errors.h"
typedef struct TerminalSize {
i16 cols;
i16 rows;
} TerminalSize;
typedef enum Color16 {
Color16_Black = 30,
Color16_DarkRed = 31,
Color16_DarkGreen = 32,
Color16_DarkYellow = 33,
Color16_DarkBlue = 34,
Color16_DarkMagenta = 35,
Color16_DarkCyan = 36,
Color16_Gray = 37,
Color16_DarkGray = 90,
Color16_Red = 91,
Color16_Green = 92,
Color16_Yellow = 93,
Color16_Blue = 94,
Color16_Magenta = 95,
Color16_Cyan = 96,
Color16_White = 97
} Color16;
Result(void) term_init();
Result(void) term_getSize(TerminalSize* out);
Result(void) term_readLine(char* buf, u32 bufsize);
Result(void) term_readLineHidden(char *buf, u32 bufsize);
void term_setFgColor16(Color16 c);
void term_setBgColor16(Color16 c);
void term_bold();
void term_italic();
void term_underline();
void term_strikethrough();
void term_resetColors();
void term_clear();
void term_eraseRow();
void term_resetCursor();
void term_cursorMove(u16 row, u16 column);
void term_cursorHide();
void term_cursorShow();

View File

@ -2,11 +2,12 @@
#define LOGGER conn->server->logger #define LOGGER conn->server->logger
#define LOG_FUNC conn->server->log_func #define LOG_FUNC conn->server->log_func
#define LOG_CONTEXT log_ctx
declare_RequestHandler(GetMessageBlock) declare_RequestHandler(GetMessageBlock)
{ {
Deferral(4); Deferral(4);
logInfo(log_ctx, "requested %s", req_type_name); logInfo("requested %s", req_type_name);
// receive request // receive request
GetMessageBlockRequest req; GetMessageBlockRequest req;

View File

@ -2,11 +2,12 @@
#define LOGGER conn->server->logger #define LOGGER conn->server->logger
#define LOG_FUNC conn->server->log_func #define LOG_FUNC conn->server->log_func
#define LOG_CONTEXT log_ctx
declare_RequestHandler(Login) declare_RequestHandler(Login)
{ {
Deferral(4); Deferral(4);
logInfo(log_ctx, "requested %s", req_type_name); logInfo("requested %s", req_type_name);
// receive request // receive request
LoginRequest req; LoginRequest req;
@ -72,7 +73,7 @@ declare_RequestHandler(Login)
// authorize // authorize
conn->authorized = true; conn->authorized = true;
logInfo(log_ctx, "authorized user '%s'", username_str.data); logInfo("authorized user '%s'", username_str.data);
// send response // send response
LoginResponse res; LoginResponse res;

View File

@ -2,11 +2,12 @@
#define LOGGER conn->server->logger #define LOGGER conn->server->logger
#define LOG_FUNC conn->server->log_func #define LOG_FUNC conn->server->log_func
#define LOG_CONTEXT log_ctx
declare_RequestHandler(Register) declare_RequestHandler(Register)
{ {
Deferral(4); Deferral(4);
logInfo(log_ctx, "requested %s", req_type_name); logInfo("requested %s", req_type_name);
// receive request // receive request
RegisterRequest req; RegisterRequest req;
@ -74,7 +75,7 @@ declare_RequestHandler(Register)
idb_unlockTable(conn->server->users.table); idb_unlockTable(conn->server->users.table);
unlocked_users_cache_mutex = true; unlocked_users_cache_mutex = true;
logInfo(log_ctx, "registered user '%s'", username_str.data); logInfo("registered user '%s'", username_str.data);
// send response // send response
RegisterResponse res; RegisterResponse res;

View File

@ -2,11 +2,12 @@
#define LOGGER conn->server->logger #define LOGGER conn->server->logger
#define LOG_FUNC conn->server->log_func #define LOG_FUNC conn->server->log_func
#define LOG_CONTEXT log_ctx
declare_RequestHandler(SendMessage) declare_RequestHandler(SendMessage)
{ {
Deferral(4); Deferral(4);
logInfo(log_ctx, "requested %s", req_type_name); logInfo("requested %s", req_type_name);
// receive request // receive request
SendMessageRequest req; SendMessageRequest req;

View File

@ -2,11 +2,12 @@
#define LOGGER conn->server->logger #define LOGGER conn->server->logger
#define LOG_FUNC conn->server->log_func #define LOG_FUNC conn->server->log_func
#define LOG_CONTEXT log_ctx
declare_RequestHandler(ServerPublicInfo) declare_RequestHandler(ServerPublicInfo)
{ {
Deferral(4); Deferral(4);
logInfo(log_ctx, "requested %s", req_type_name); logInfo("requested %s", req_type_name);
// receive request // receive request
ServerPublicInfoRequest req; ServerPublicInfoRequest req;

View File

@ -2,6 +2,7 @@
#define LOGGER conn->server->logger #define LOGGER conn->server->logger
#define LOG_FUNC conn->server->log_func #define LOG_FUNC conn->server->log_func
#define LOG_CONTEXT log_ctx
Result(void) sendErrorMessage( Result(void) sendErrorMessage(
cstr log_ctx, ClientConnection* conn, PacketHeader* res_head, cstr log_ctx, ClientConnection* conn, PacketHeader* res_head,
@ -13,7 +14,7 @@ Result(void) sendErrorMessage(
if(msg.len > ERROR_MESSAGE_MAX_SIZE) if(msg.len > ERROR_MESSAGE_MAX_SIZE)
msg.len = ERROR_MESSAGE_MAX_SIZE; msg.len = ERROR_MESSAGE_MAX_SIZE;
log(log_severity, log_ctx, FMT_str, msg.len, msg.data); log(log_severity, FMT_str, msg.len, msg.data);
ErrorMessage res; ErrorMessage res;
ErrorMessage_construct(&res, res_head, msg.len); ErrorMessage_construct(&res, res_head, msg.len);

View File

@ -2,11 +2,12 @@
#define LOGGER conn->server->logger #define LOGGER conn->server->logger
#define LOG_FUNC conn->server->log_func #define LOG_FUNC conn->server->log_func
#define LOG_CONTEXT log_ctx
declare_RequestHandler(NAME) declare_RequestHandler(NAME)
{ {
Deferral(4); Deferral(4);
logInfo(log_ctx, "requested %s", req_type_name); logInfo("requested %s", req_type_name);
// receive request // receive request
NAME##Request req; NAME##Request req;

View File

@ -34,6 +34,7 @@ void Server_free(Server* self){
#define LOGGER logger #define LOGGER logger
#define LOG_FUNC log_func #define LOG_FUNC log_func
#define LOG_CONTEXT log_ctx
Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_func){ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_func){
Deferral(16); Deferral(16);
@ -46,7 +47,7 @@ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_fu
self->logger = logger; self->logger = logger;
self->log_func = log_func; self->log_func = log_func;
logDebug(log_ctx, "parsing config"); logDebug("parsing config");
// parse name // parse name
str tmp_str = str_null; str tmp_str = str_null;
@ -95,7 +96,7 @@ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_fu
try(self->db, p, idb_open(tmp_str, db_aes_key)); try(self->db, p, idb_open(tmp_str, db_aes_key));
// build users cache // build users cache
logDebug(log_ctx, "loading users..."); logDebug("loading users...");
try(self->users.table, p, try(self->users.table, p,
idb_getOrCreateTable(self->db, STR("users"), sizeof(UserInfo), false) idb_getOrCreateTable(self->db, STR("users"), sizeof(UserInfo), false)
); );
@ -115,11 +116,11 @@ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_fu
Return RESULT_ERROR_FMT("duplicate user name '"FMT_str"'", key.len, key.data); Return RESULT_ERROR_FMT("duplicate user name '"FMT_str"'", key.len, key.data);
} }
} }
logDebug(log_ctx, "loaded "FMT_u64" users", users_count); logDebug("loaded "FMT_u64" users", users_count);
// build messages cache // build messages cache
logDebug(log_ctx, "loading messages..."); logDebug("loading messages...");
try(self->messages.blocks_table, p, try(self->messages.blocks_table, p,
idb_getOrCreateTable(self->db, STR("message_blocks"), sizeof(MessageBlock), false) idb_getOrCreateTable(self->db, STR("message_blocks"), sizeof(MessageBlock), false)
); );
@ -148,7 +149,7 @@ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_fu
); );
try_void(idb_getRow(self->messages.blocks_table, id, node->value.data, false)); try_void(idb_getRow(self->messages.blocks_table, id, node->value.data, false));
} }
logDebug(log_ctx, "loaded "FMT_u64" message blocks", message_blocks_count); logDebug("loaded "FMT_u64" message blocks", message_blocks_count);
success = true; success = true;
Return RESULT_VALUE(p, self); Return RESULT_VALUE(p, self);
@ -156,21 +157,23 @@ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_fu
#undef LOGGER #undef LOGGER
#undef LOG_FUNC #undef LOG_FUNC
#undef LOG_CONTEXT
#define LOGGER server->logger #define LOGGER server->logger
#define LOG_FUNC server->log_func #define LOG_FUNC server->log_func
#define LOG_CONTEXT log_ctx
Result(void) Server_run(Server* server){ Result(void) Server_run(Server* server){
Deferral(16); Deferral(16);
cstr log_ctx = "ListenerThread"; cstr log_ctx = "ListenerThread";
logInfo(log_ctx, "starting server"); logInfo("starting server");
logDebug(log_ctx, "initializing main socket"); logDebug("initializing main socket");
try(Socket main_socket, i, socket_open_TCP()); try(Socket main_socket, i, socket_open_TCP());
try_void(socket_bind(main_socket, server->local_end)); try_void(socket_bind(main_socket, server->local_end));
try_void(socket_listen(main_socket, 512)); try_void(socket_listen(main_socket, 512));
str local_end_str = EndpointIPv4_toStr(server->local_end); str local_end_str = EndpointIPv4_toStr(server->local_end);
Defer(free(local_end_str.data)); Defer(free(local_end_str.data));
logInfo(log_ctx, "server is listening at %s", local_end_str.data); logInfo("server is listening at %s", local_end_str.data);
u64 session_id = 1; u64 session_id = 1;
while(true){ while(true){
@ -200,12 +203,12 @@ static void* handleConnection(void* _args){
if(r.error){ if(r.error){
Error_addCallPos(r.error, ErrorCallPos_here()); Error_addCallPos(r.error, ErrorCallPos_here());
str e_str = Error_toStr(r.error); str e_str = Error_toStr(r.error);
logError(log_ctx, FMT_str, e_str.len, e_str.data); logError(FMT_str, e_str.len, e_str.data);
str_free(e_str); str_free(e_str);
Error_free(r.error); Error_free(r.error);
} }
logInfo(log_ctx, "session end"); logInfo("session end");
free(args); free(args);
return NULL; return NULL;
} }
@ -214,12 +217,12 @@ static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_c
Deferral(16); Deferral(16);
Server* server = args->server; Server* server = args->server;
logInfo(log_ctx, "a client is trying to connect"); logInfo("a client is trying to connect");
ClientConnection* conn = NULL; ClientConnection* conn = NULL;
// establish encrypted connection // establish encrypted connection
try(conn, p, ClientConnection_accept(args)); try(conn, p, ClientConnection_accept(args));
Defer(ClientConnection_close(conn)); Defer(ClientConnection_close(conn));
logInfo(log_ctx, "session accepted"); logInfo("session accepted");
// handle requests // handle requests
PacketHeader req_head; PacketHeader req_head;