30#if defined(__cplusplus) && defined(_WIN32)
32using std::atomic_compare_exchange_weak_explicit;
33using std::atomic_load_explicit;
34using std::memory_order_relaxed;
36#define LOG_ATOMIC_UINT64 std::atomic<uint64_t>
38#define LOG_ATOMIC_UINT64_INIT(val) {val}
42#define LOG_ATOMIC_UINT64 _Atomic uint64_t
44#define LOG_ATOMIC_UINT64_INIT(val) val
72#define DEFAULT_LOG_LEVEL LOG_INFO
75#define DEFAULT_LOG_LEVEL LOG_DEBUG
79#define MAX_LOG_SIZE (3 * 1024 * 1024)
82#define MAX_TERMINAL_BUFFER_SIZE (64 * 1024)
85#define MAX_TERMINAL_BUFFER_ENTRIES 256
95#define LOG_MSG_BUFFER_SIZE 4096
98#define LOG_MMAP_MSG_BUFFER_SIZE 1024
101#define LOG_HEADER_BUFFER_SIZE 512
104#define LOG_TIMESTAMP_BUFFER_SIZE 32
117#ifndef LOG_COMPILE_LEVEL
119#define LOG_COMPILE_LEVEL LOG_DEV
239void log_msg(
log_level_t level,
const char *file,
int line,
const char *func,
const char *fmt, ...);
410 const char *fmt, ...);
428#if LOG_COMPILE_LEVEL <= LOG_DEV
430#define log_dev(...) log_msg(LOG_DEV, NULL, 0, NULL, __VA_ARGS__)
432#define log_dev(...) log_msg(LOG_DEV, __FILE__, __LINE__, __func__, __VA_ARGS__)
435#define log_dev(...) ((void)0)
446#if LOG_COMPILE_LEVEL <= LOG_DEBUG
448#define log_debug(...) log_msg(LOG_DEBUG, NULL, 0, NULL, __VA_ARGS__)
450#define log_debug(...) log_msg(LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__)
453#define log_debug(...) ((void)0)
463#if LOG_COMPILE_LEVEL <= LOG_INFO
465#define log_info(...) log_msg(LOG_INFO, NULL, 0, NULL, __VA_ARGS__)
467#define log_info(...) log_msg(LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__)
470#define log_info(...) ((void)0)
480#if LOG_COMPILE_LEVEL <= LOG_WARN
482#define log_warn(...) log_msg(LOG_WARN, NULL, 0, NULL, __VA_ARGS__)
484#define log_warn(...) log_msg(LOG_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__)
487#define log_warn(...) ((void)0)
497#if LOG_COMPILE_LEVEL <= LOG_ERROR
499#define log_error(...) log_msg(LOG_ERROR, NULL, 0, NULL, __VA_ARGS__)
501#define log_error(...) log_msg(LOG_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__)
504#define log_error(...) ((void)0)
515#define log_fatal(...) log_msg(LOG_FATAL, NULL, 0, NULL, __VA_ARGS__)
517#define log_fatal(...) log_msg(LOG_FATAL, __FILE__, __LINE__, __func__, __VA_ARGS__)
525#define log_plain(...) log_plain_msg(__VA_ARGS__)
532#define log_plain_stderr(...) log_plain_stderr_msg(__VA_ARGS__)
539#define log_plain_stderr_nonewline(...) log_plain_stderr_nonewline_msg(__VA_ARGS__)
546#define log_file(...) log_file_msg(__VA_ARGS__)
568#define log_every(log_level, interval_us, fmt, ...) \
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__); \
581#define log_every(log_level, interval_us, fmt, ...) \
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__); \
601#define log_dev_every(interval_us, fmt, ...) log_every(DEV, interval_us, fmt, ##__VA_ARGS__)
604#define log_debug_every(interval_us, fmt, ...) log_every(DEBUG, interval_us, fmt, ##__VA_ARGS__)
607#define log_info_every(interval_us, fmt, ...) log_every(INFO, interval_us, fmt, ##__VA_ARGS__)
610#define log_warn_every(interval_us, fmt, ...) log_every(WARN, interval_us, fmt, ##__VA_ARGS__)
613#define log_error_every(interval_us, fmt, ...) log_every(ERROR, interval_us, fmt, ##__VA_ARGS__)
616#define log_fatal_every(interval_us, fmt, ...) log_every(FATAL, interval_us, fmt, ##__VA_ARGS__)
asciichat_error_t
Error and exit codes - unified status values (0-255)
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.
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.
Network logging macros and remote log direction enumeration.
Cross-platform socket interface for ascii-chat.
Cryptographic context structure.
A single buffered log entry.
Configuration for mmap logging.
Cross-platform system functions interface for ascii-chat.
⏱️ High-precision timing utilities using sokol_time.h and uthash