ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
log/logging.h
Go to the documentation of this file.
1
24#pragma once
25
26#include <stdarg.h>
27// C11 stdatomic.h conflicts with MSVC's C++ <atomic> header on Windows.
28// When compiling C++ with MSVC runtime headers, the atomic types are in std:: namespace.
29// We bring them into global namespace for compatibility with C-style struct definitions.
30#if defined(__cplusplus) && defined(_WIN32)
31#include <atomic>
32using std::atomic_compare_exchange_weak_explicit;
33using std::atomic_load_explicit;
34using std::memory_order_relaxed;
35// C11 _Atomic(T) syntax doesn't work in C++ - use std::atomic<T> instead
36#define LOG_ATOMIC_UINT64 std::atomic<uint64_t>
37// C++ uses brace initialization for std::atomic
38#define LOG_ATOMIC_UINT64_INIT(val) {val}
39#else
40#include <stdatomic.h>
41// C11 _Atomic type qualifier syntax
42#define LOG_ATOMIC_UINT64 _Atomic uint64_t
43// C11 uses direct initialization for atomic types
44#define LOG_ATOMIC_UINT64_INIT(val) val
45#endif
46#include <stdbool.h>
47#include <stdint.h>
48#include <time.h>
49#include "platform/socket.h"
50#include "platform/system.h"
51
67
68#include "network/logging.h"
69
70#ifdef NDEBUG
72#define DEFAULT_LOG_LEVEL LOG_INFO
73#else
75#define DEFAULT_LOG_LEVEL LOG_DEBUG
76#endif
77
79#define MAX_LOG_SIZE (3 * 1024 * 1024)
80
82#define MAX_TERMINAL_BUFFER_SIZE (64 * 1024)
83
85#define MAX_TERMINAL_BUFFER_ENTRIES 256
86
87/* ============================================================================
88 * Logging Buffer Size Constants
89 * ============================================================================
90 * Named constants for internal buffer sizes. Messages exceeding these sizes
91 * will be truncated with no error indication.
92 */
93
95#define LOG_MSG_BUFFER_SIZE 4096
96
98#define LOG_MMAP_MSG_BUFFER_SIZE 1024
99
101#define LOG_HEADER_BUFFER_SIZE 512
102
104#define LOG_TIMESTAMP_BUFFER_SIZE 32
105
106/* ============================================================================
107 * Compile-Time Log Level Stripping
108 * ============================================================================
109 * By default, all log levels are compiled in (LOG_DEV) so that runtime
110 * verbosity flags like -vvv work in both debug and release builds.
111 *
112 * Define LOG_COMPILE_LEVEL to strip logs at compile-time for smaller binaries:
113 * -DLOG_COMPILE_LEVEL=LOG_INFO -> Strip DEV and DEBUG
114 * -DLOG_COMPILE_LEVEL=LOG_WARN -> Strip DEV, DEBUG, and INFO
115 * -DLOG_COMPILE_LEVEL=LOG_DEV -> Keep all log levels (default)
116 */
117#ifndef LOG_COMPILE_LEVEL
119#define LOG_COMPILE_LEVEL LOG_DEV
120#endif
121
123typedef struct {
124 bool use_stderr; /* true for stderr, false for stdout */
125 char *message; /* Formatted message (heap allocated) */
127
128/* Implementation details (g_log struct, color arrays) are in logging.c */
129
146
147#ifdef __cplusplus
148extern "C" {
149#endif
150
165void log_init(const char *filename, log_level_t level, bool force_stderr, bool use_mmap);
166
171void log_destroy(void);
172
178void log_set_level(log_level_t level);
179
186
192void log_set_terminal_output(bool enabled);
193
199bool log_get_terminal_output(void);
200
212void log_set_force_stderr(bool enabled);
213
219bool log_get_force_stderr(void);
220
227void log_truncate_if_large(void);
228
239void log_msg(log_level_t level, const char *file, int line, const char *func, const char *fmt, ...);
240
249void log_plain_msg(const char *fmt, ...);
250
259void log_plain_stderr_msg(const char *fmt, ...);
260
270void log_plain_stderr_nonewline_msg(const char *fmt, ...);
271
280void log_file_msg(const char *fmt, ...);
281
294void log_labeled(const char *label, log_color_t color, const char *message, ...);
295
302const char *log_level_color(log_color_t color);
303
311const char **log_get_color_array(void);
312
320
338bool log_lock_terminal(void);
339
349void log_unlock_terminal(bool previous_state);
350
361void log_set_flush_delay(unsigned int delay_ms);
362
370char *format_message(const char *format, va_list args);
371
378size_t get_current_time_formatted(char *time_buf);
379
380#include "crypto/crypto.h"
381
392asciichat_error_t log_network_message(socket_t sockfd, const struct crypto_context_t *crypto_ctx, log_level_t level,
393 remote_log_direction_t direction, const char *fmt, ...);
394
408asciichat_error_t log_net_message(socket_t sockfd, const struct crypto_context_t *crypto_ctx, log_level_t level,
409 remote_log_direction_t direction, const char *file, int line, const char *func,
410 const char *fmt, ...);
411
428#if LOG_COMPILE_LEVEL <= LOG_DEV
429#ifdef NDEBUG
430#define log_dev(...) log_msg(LOG_DEV, NULL, 0, NULL, __VA_ARGS__)
431#else
432#define log_dev(...) log_msg(LOG_DEV, __FILE__, __LINE__, __func__, __VA_ARGS__)
433#endif
434#else
435#define log_dev(...) ((void)0)
436#endif
437
446#if LOG_COMPILE_LEVEL <= LOG_DEBUG
447#ifdef NDEBUG
448#define log_debug(...) log_msg(LOG_DEBUG, NULL, 0, NULL, __VA_ARGS__)
449#else
450#define log_debug(...) log_msg(LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__)
451#endif
452#else
453#define log_debug(...) ((void)0)
454#endif
455
463#if LOG_COMPILE_LEVEL <= LOG_INFO
464#ifdef NDEBUG
465#define log_info(...) log_msg(LOG_INFO, NULL, 0, NULL, __VA_ARGS__)
466#else
467#define log_info(...) log_msg(LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__)
468#endif
469#else
470#define log_info(...) ((void)0)
471#endif
472
480#if LOG_COMPILE_LEVEL <= LOG_WARN
481#ifdef NDEBUG
482#define log_warn(...) log_msg(LOG_WARN, NULL, 0, NULL, __VA_ARGS__)
483#else
484#define log_warn(...) log_msg(LOG_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__)
485#endif
486#else
487#define log_warn(...) ((void)0)
488#endif
489
497#if LOG_COMPILE_LEVEL <= LOG_ERROR
498#ifdef NDEBUG
499#define log_error(...) log_msg(LOG_ERROR, NULL, 0, NULL, __VA_ARGS__)
500#else
501#define log_error(...) log_msg(LOG_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__)
502#endif
503#else
504#define log_error(...) ((void)0)
505#endif
506
514#ifdef NDEBUG
515#define log_fatal(...) log_msg(LOG_FATAL, NULL, 0, NULL, __VA_ARGS__)
516#else
517#define log_fatal(...) log_msg(LOG_FATAL, __FILE__, __LINE__, __func__, __VA_ARGS__)
518#endif
519
525#define log_plain(...) log_plain_msg(__VA_ARGS__)
526
532#define log_plain_stderr(...) log_plain_stderr_msg(__VA_ARGS__)
533
539#define log_plain_stderr_nonewline(...) log_plain_stderr_nonewline_msg(__VA_ARGS__)
540
546#define log_file(...) log_file_msg(__VA_ARGS__)
547
567#ifdef NDEBUG
568#define log_every(log_level, interval_us, fmt, ...) \
569 do { \
570 static LOG_ATOMIC_UINT64 _log_every_last_time = LOG_ATOMIC_UINT64_INIT(0); \
571 uint64_t _log_every_now = platform_get_monotonic_time_us(); \
572 uint64_t _log_every_last = atomic_load_explicit(&_log_every_last_time, memory_order_relaxed); \
573 if (_log_every_now - _log_every_last >= (uint64_t)(interval_us)) { \
574 if (atomic_compare_exchange_weak_explicit(&_log_every_last_time, &_log_every_last, _log_every_now, \
575 memory_order_relaxed, memory_order_relaxed)) { \
576 log_msg(LOG_##log_level, NULL, 0, NULL, fmt, ##__VA_ARGS__); \
577 } \
578 } \
579 } while (0)
580#else
581#define log_every(log_level, interval_us, fmt, ...) \
582 do { \
583 static LOG_ATOMIC_UINT64 _log_every_last_time = LOG_ATOMIC_UINT64_INIT(0); \
584 uint64_t _log_every_now = platform_get_monotonic_time_us(); \
585 uint64_t _log_every_last = atomic_load_explicit(&_log_every_last_time, memory_order_relaxed); \
586 if (_log_every_now - _log_every_last >= (uint64_t)(interval_us)) { \
587 if (atomic_compare_exchange_weak_explicit(&_log_every_last_time, &_log_every_last, _log_every_now, \
588 memory_order_relaxed, memory_order_relaxed)) { \
589 log_msg(LOG_##log_level, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__); \
590 } \
591 } \
592 } while (0)
593#endif
594
601#define log_dev_every(interval_us, fmt, ...) log_every(DEV, interval_us, fmt, ##__VA_ARGS__)
602
604#define log_debug_every(interval_us, fmt, ...) log_every(DEBUG, interval_us, fmt, ##__VA_ARGS__)
605
607#define log_info_every(interval_us, fmt, ...) log_every(INFO, interval_us, fmt, ##__VA_ARGS__)
608
610#define log_warn_every(interval_us, fmt, ...) log_every(WARN, interval_us, fmt, ##__VA_ARGS__)
611
613#define log_error_every(interval_us, fmt, ...) log_every(ERROR, interval_us, fmt, ##__VA_ARGS__)
614
616#define log_fatal_every(interval_us, fmt, ...) log_every(FATAL, interval_us, fmt, ##__VA_ARGS__)
617
620/* LOGGING_INTERNAL_ERROR macro is defined in logging.c (internal use only) */
621
622/* Network logging convenience macros (log_*_net) are defined in src/server/client.h
623 * since they require access to client_info_t. The base function log_net_message()
624 * is available here for generic use. */
625
626/* ============================================================================
627 * Lock-Free MMAP Logging
628 * ============================================================================ */
629
630/* Forward declaration - full definition in log/mmap.h */
631struct log_mmap_config;
633
654
664
671void log_disable_mmap(void);
672
684void log_shutdown_begin(void);
685
692void log_shutdown_end(void);
693
694#ifdef __cplusplus
695}
696#endif
697
/* logging */
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
void log_truncate_if_large(void)
Manually truncate large log files.
void log_plain_stderr_nonewline_msg(const char *fmt,...)
Plain logging to stderr without trailing newline.
void log_plain_msg(const char *fmt,...)
Plain logging without timestamps or levels.
bool log_get_terminal_output(void)
Get current terminal output setting.
asciichat_error_t log_enable_mmap(const char *log_path)
Enable lock-free mmap-based logging.
void log_msg(log_level_t level, const char *file, int line, const char *func, const char *fmt,...)
Log a message at a specific level.
void log_shutdown_end(void)
End shutdown phase - restore previous logging settings.
void log_destroy(void)
Destroy the logging system and close log file.
void log_set_force_stderr(bool enabled)
Force all terminal log output to stderr.
enum remote_log_direction remote_log_direction_t
Remote log packet direction enumeration.
log_level_t log_get_level(void)
Get the current minimum log level.
const char ** log_get_color_array(void)
Get the appropriate color array based on terminal capabilities.
const char * log_level_color(log_color_t color)
Get color string for a given color enum.
void log_set_flush_delay(unsigned int delay_ms)
Set the delay between flushing buffered log entries.
char * format_message(const char *format, va_list args)
Format a message using va_list.
log_color_t
Color enum for logging - indexes into color arrays.
void log_shutdown_begin(void)
Begin shutdown phase - disable console logging but keep file logging.
bool log_get_force_stderr(void)
Get current force_stderr setting.
void log_set_level(log_level_t level)
Set the minimum log level.
void log_init(const char *filename, log_level_t level, bool force_stderr, bool use_mmap)
Initialize the logging system.
asciichat_error_t log_net_message(socket_t sockfd, const struct crypto_context_t *crypto_ctx, log_level_t level, remote_log_direction_t direction, const char *file, int line, const char *func, const char *fmt,...)
Log a message to all destinations (network, file, and terminal).
bool log_lock_terminal(void)
Lock terminal output for exclusive access by the calling thread.
asciichat_error_t log_network_message(socket_t sockfd, const struct crypto_context_t *crypto_ctx, log_level_t level, remote_log_direction_t direction, const char *fmt,...)
Send a formatted log message over the network.
log_level_t
Logging levels enumeration.
Definition log/logging.h:59
void log_labeled(const char *label, log_color_t color, const char *message,...)
Print a labeled message with color.
size_t get_current_time_formatted(char *time_buf)
Get current time as formatted string.
asciichat_error_t log_enable_mmap_sized(const char *log_path, size_t max_size)
Enable lock-free mmap logging with custom file size.
void log_file_msg(const char *fmt,...)
Log to file only, no stderr output.
void log_disable_mmap(void)
Disable mmap logging and return to mutex-based logging.
void log_set_terminal_output(bool enabled)
Control stderr output to terminal.
void log_plain_stderr_msg(const char *fmt,...)
Plain logging to stderr with newline.
void log_redetect_terminal_capabilities(void)
Re-detect terminal capabilities after logging is initialized.
void log_unlock_terminal(bool previous_state)
Release terminal lock and flush buffered messages.
@ LOG_COLOR_RESET
@ LOG_COLOR_FATAL
@ LOG_COLOR_ERROR
@ LOG_COLOR_DEV
@ LOG_COLOR_DEBUG
@ LOG_COLOR_INFO
@ LOG_COLOR_WARN
@ LOG_ERROR
Definition log/logging.h:64
@ LOG_INFO
Definition log/logging.h:62
@ LOG_DEBUG
Definition log/logging.h:61
@ LOG_FATAL
Definition log/logging.h:65
@ LOG_WARN
Definition log/logging.h:63
@ LOG_DEV
Definition log/logging.h:60
int socket_t
Socket handle type (POSIX: int)
Definition socket.h:50
Network logging macros and remote log direction enumeration.
Cross-platform socket interface for ascii-chat.
Cryptographic context structure.
A single buffered log entry.
char * message
bool use_stderr
Configuration for mmap logging.
Definition log/mmap.h:51
size_t max_size
Definition log/mmap.h:53
const char * log_path
Definition log/mmap.h:52
Cross-platform system functions interface for ascii-chat.
⏱️ High-precision timing utilities using sokol_time.h and uthash