10 #define EXOTIC_LOGAX_H
23 #if defined(_WIN32) && defined(LOGAX_USE_OLD_CONSOLE_MODE)
34 #ifdef __STDC_VERSION__
35 #define __LOGAX_STDC_VERSION__ __STDC_VERSION__
38 #if __cplusplus > 199711L
39 #define __LOGAX_STDC_VERSION__ __cplusplus
43 #ifndef __LOGAX_STDC_VERSION__
45 #define __LOGAX_FUNCTION__ __FUNCTION__
47 #define __LOGAX_FUNCTION__ "<unknown>"
51 #define __LOGAX_FUNCTION__ __func__
52 #define LOGAX_NULL NULL
55 #if defined(_WIN32) && defined(LOGAX_USE_OLD_CONSOLE_MODE)
57 #define LOGAX_RESET_TERMINAL 15
58 #define LOGAX_FOREGROUND_TRACE 11
59 #define LOGAX_FOREGROUND_DEBUG 2
60 #define LOGAX_FOREGROUND_INFO 5
61 #define LOGAX_FOREGROUND_WARN 6
62 #define LOGAX_FOREGROUND_ERROR 4
63 #define LOGAX_FOREGROUND_FATAL 4
64 #define LOGAX_RESET_TERMINAL_ATTR() SetConsoleTextAttribute(logax_hConsole, logax_default_color);
68 #define LOGAX_RESET_TERMINAL "\x1B[0m"
69 #define LOGAX_FOREGROUND_TRACE "\x1B[36m"
70 #define LOGAX_FOREGROUND_DEBUG "\x1B[32m"
71 #define LOGAX_FOREGROUND_INFO "\x1B[35m"
72 #define LOGAX_FOREGROUND_WARN "\x1B[33m"
73 #define LOGAX_FOREGROUND_ERROR "\x1B[31m"
74 #define LOGAX_FOREGROUND_FATAL "\x1B[31m"
75 #define LOGAX_RESET_TERMINAL_ATTR() fprintf(stream, "%s", LOGAX_RESET_TERMINAL)
79 #ifndef LOGAX_LOGGER_NO_CALLBACK
83 #ifndef LOGAX_MAX_CALLBACKS
84 #define LOGAX_MAX_CALLBACKS 5
92 typedef void (*
logax_callback)(
const char *date,
const char *time,
const int level,
const char *file,
const size_t line_number,
const char *function_name,
const char *fmt, ...);
101 #ifndef LOGAX_NO_TIME
109 #ifndef LOGAX_NO_COLORING
119 #define LOGAX_OPTION_QUITE LOGAX_OPTION_QUIET
136 #define GET_LEVEL_STRING(level) ((level == LOGAX_LEVEL_TRACE) ? "TRACE" :\
137 (level == LOGAX_LEVEL_DEBUG) ? "DEBUG" :\
138 (level == LOGAX_LEVEL_INFO) ? "INFO" :\
139 (level == LOGAX_LEVEL_WARN) ? "WARN" :\
140 (level == LOGAX_LEVEL_ERROR) ? "ERROR" :\
141 (level == LOGAX_LEVEL_FATAL) ? "FATAL" : "")
160 #if !defined(LOGAX_NO_OUTPUT_STREAM)
163 #ifndef LOGAX_LOGGER_NO_CALLBACK
176 static void logax_init_logger(
LogaxLogger *logax_logger) {
179 #ifndef LOGAX_NO_COLORING
182 #ifndef LOGAX_NO_TIME
185 #if defined(stdout) && !defined(LOGAX_NO_OUTPUT_STREAM)
188 #ifndef LOGAX_LOGGER_NO_CALLBACK
195 #if !defined(LOGAX_NO_OUTPUT_STREAM)
202 #ifndef LOGAX_NO_COLORING
205 #ifndef LOGAX_NO_TIME
209 #ifndef LOGAX_LOGGER_NO_CALLBACK
217 #ifndef LOGAX_LOGGER_NO_CALLBACK
225 logax_logger->
callbacks[index] = callback;
232 #define logax_logger_add_callback(logax_logger, callback)
238 #define logax_add_flag(flags, flag) flags |= flag;
243 #define logax_set_flag logax_add_flag
248 #define logax_remove_flag(flags, flag) flags &= ~flag;
253 #define logax_clear_flag logax_remove_flag
258 #define logax_set_formatter(logax_logger, new_formatter) {\
259 if ((logax_logger)->flags & LOGAX_FORMATTER_TEXT) logax_remove_flag((logax_logger)->flags, LOGAX_FORMATTER_TEXT);\
260 if ((logax_logger)->flags & LOGAX_FORMATTER_KEY_VALUE) logax_remove_flag((logax_logger)->flags, LOGAX_FORMATTER_KEY_VALUE);\
261 if ((logax_logger)->flags & LOGAX_FORMATTER_JSON) logax_remove_flag((logax_logger)->flags, LOGAX_FORMATTER_JSON);\
262 logax_add_flag((logax_logger)->flags, new_formatter);\
268 #define logax_set_quiet(logax_logger, make_quiet) {\
269 if (!make_quiet && ((logax_logger)->flags & LOGAX_OPTION_QUIET)) { logax_remove_flag((logax_logger)->flags, LOGAX_OPTION_QUIET); }\
270 else if (make_quiet && !((logax_logger)->flags & LOGAX_OPTION_QUIET)) { logax_add_flag((logax_logger)->flags, LOGAX_OPTION_QUIET); }\
276 #define logax_set_quite logax_set_quiet
278 #ifndef LOGAX_NO_OUTPUT_STREAM
282 static size_t logax_cstr_length(
char char_array[]) {
284 if (char_array ==
LOGAX_NULL) {
return length; }
285 while(char_array[length] !=
'\0') {
294 static void logax_replace_char(
char const*
const file_path,
char formatted_file_name[],
char old_char,
char new_char) {
295 unsigned i = 0, j = -1;
296 while (file_path[i] !=
'\0') {
297 if (file_path[i] == old_char) {
298 formatted_file_name[i] = new_char;
300 formatted_file_name[i] = file_path[i];
304 formatted_file_name[i] =
'\0';
310 static void logax_extract_name_only(
char const*
const file_path,
char formatted_file_name[]) {
311 unsigned i = 0, j = -1;
312 while (file_path[i] !=
'\0') {
313 if (file_path[i] ==
'\\' || file_path[i] ==
'/') {
315 }
else if (j != -1) {
316 formatted_file_name[j] = file_path[i];
321 formatted_file_name[j] =
'\0';
324 #if defined(_WIN32) && defined(LOGAX_USE_OLD_CONSOLE_MODE)
326 int initialized_h_console = 0;
327 HANDLE logax_hConsole;
332 #define LOGAX_Iinitialized_HCONSOLE() if (!initialized_h_console) {\
333 CONSOLE_SCREEN_BUFFER_INFO info;\
334 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)) {\
335 logax_default_color = info.wAttributes;\
337 logax_hConsole = GetStdHandle(STD_OUTPUT_HANDLE);\
338 initialized_h_console = 1;\
341 #ifndef LOGAX_NO_COLORING
342 #define LOGAX_DELEGATE_FPRINT_STR(foreground, text) if (is_colored) { SetConsoleTextAttribute(logax_hConsole, foreground); } fprintf(stream, "%s", text); if (is_colored) { LOGAX_RESET_TERMINAL_ATTR(); }
343 #define LOGAX_DELEGATE_FPRINT_SIZE_T(foreground, text) if (is_colored) { SetConsoleTextAttribute(logax_hConsole, foreground); } fprintf(stream, "%zu", text); if (is_colored) {LOGAX_RESET_TERMINAL_ATTR(); }
345 #define LOGAX_DELEGATE_FPRINT_STR(foreground, text) fprintf(stream, "%s", text);
346 #define LOGAX_DELEGATE_FPRINT_SIZE_T(foreground, text) fprintf(stream, "%zu", text);
349 #ifndef LOGAX_NO_COLORING
353 #define LOGAX_WRITE_COLOR_CODE(color) SetConsoleTextAttribute(logax_hConsole, color);
355 #define LOGAX_WRITE_COLOR_CODE(color)
361 #define LOGAX_WRITE_LEVEL_COLOR__INTERNALL__(prefix_value, level, suffix_value)\
363 fprintf(stream, "%s", prefix_value); LOGAX_DELEGATE_FPRINT_STR(LOGAX_FOREGROUND_##level, #level); fprintf(stream, "%s", suffix_value);\
365 fprintf(stream, "%s%s%s", prefix_value, #level, suffix_value);\
369 #define LOGAX_Iinitialized_HCONSOLE()
371 #ifndef LOGAX_NO_COLORING
372 #define LOGAX_DELEGATE_FPRINT_STR(foreground, text) if (is_colored) { fprintf(stream, "%s%s%s", foreground, text, LOGAX_RESET_TERMINAL); } else { fprintf(stream, "%s", text); }
373 #define LOGAX_DELEGATE_FPRINT_SIZE_T(foreground, text) if (is_colored) { fprintf(stream, "%s%zu%s", foreground, text, LOGAX_RESET_TERMINAL); } else { fprintf(stream, "%zu", text); }
375 #define LOGAX_DELEGATE_FPRINT_STR(foreground, text) fprintf(stream, "%s", text);
376 #define LOGAX_DELEGATE_FPRINT_SIZE_T(foreground, text) fprintf(stream, "%zu", text);
379 #ifndef LOGAX_NO_COLORING
383 #define LOGAX_WRITE_COLOR_CODE(color) if (is_colored) { fprintf(stream, "%s", color); }
385 #define LOGAX_WRITE_COLOR_CODE(color)
391 #define LOGAX_WRITE_LEVEL_COLOR__INTERNALL__(prefix_value, level, suffix_value)\
392 if (is_colored) { LOGAX_DELEGATE_FPRINT_STR(LOGAX_FOREGROUND_##level, #level); fprintf(stream, "%s", suffix_value); }\
393 else fprintf(stream, "%s%s%s", prefix_value, #level, suffix_value);
399 static void logax_write_text_format_to_stream_final__internal__(FILE *stream,
int flags,
const char *file_path,
const size_t line_number,
const char *function_name,
const char *fmt, va_list va_args) {
402 #ifndef LOGAX_NO_COLORING
405 unsigned is_colored = 0;
407 unsigned print_comma = 0;
411 #ifndef LOGAX_NO_TIME
413 struct tm *current_time = localtime(&time_raw);
415 char date_buffer[16];
416 date_buffer[strftime(date_buffer,
sizeof(date_buffer),
"%Y-%m-%d", current_time)] =
'\0';
418 fprintf(stream,
"%s", date_buffer);
421 char time_buffer[16];
422 time_buffer[strftime(time_buffer,
sizeof(time_buffer),
"%H:%M:%S", current_time)] =
'\0';
423 if (print_comma) { fprintf(stream,
" "); }
else { print_comma = 1; }
424 fprintf(stream,
"%s", time_buffer);
428 if (print_comma && has_any_level) { fprintf(stream,
" "); }
else if (has_any_level) { print_comma = 1; }
444 char formatted_file_name[logax_cstr_length((
char *)file_path)];
446 logax_replace_char((
char *)file_path, formatted_file_name,
'\\',
'/');
448 logax_extract_name_only(file_path, formatted_file_name);
450 if (print_comma) { fprintf(stream,
" "); }
else { print_comma = 1; }
451 fprintf(stream,
"%s", formatted_file_name);
455 fprintf(stream,
"%zu", line_number);
459 if (print_comma) { fprintf(stream,
" "); }
else { print_comma = 1; }
460 fprintf(stream,
"--- [%s\t]", function_name);
462 if (print_comma) { fprintf(stream,
" "); }
463 vfprintf(stream, fmt, va_args);
464 fprintf(stream,
"\n");
470 static void logax_write_text_format_to_stream__internal__(FILE *stream,
int flags,
const char *file_path,
const size_t line_number,
const char *function_name,
const char *fmt, ...) {
472 va_start(va_args, fmt);
473 logax_write_text_format_to_stream_final__internal__(stream, flags, file_path, line_number, function_name, fmt, va_args);
480 #define logax_write_text_format_to_stream(stream, flags, fmt, ...) logax_write_text_format_to_stream__internal__(stream, flags, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__)
485 static void logax_write_key_value_format_to_stream_final__internal__(FILE *stream,
int flags,
const char *file_path,
const size_t line_number,
const char *function_name,
const char *fmt, va_list va_args) {
488 unsigned is_colored = 0;
489 unsigned print_comma = 0;
493 #ifndef LOGAX_NO_TIME
495 struct tm *current_time = localtime(&time_raw);
497 char date_buffer[16];
498 date_buffer[strftime(date_buffer,
sizeof(date_buffer),
"%Y-%m-%d", current_time)] =
'\0';
500 fprintf(stream,
"date=\"%s\"", date_buffer);
503 char time_buffer[16];
504 time_buffer[strftime(time_buffer,
sizeof(time_buffer),
"%H:%M:%S", current_time)] =
'\0';
505 if (print_comma) { fprintf(stream,
" "); }
else { print_comma = 1; }
506 fprintf(stream,
"time=\"%s\"", time_buffer);
510 if (print_comma && has_any_level) { fprintf(stream,
" "); }
else if (has_any_level) { print_comma = 1; }
526 char formatted_file_name[logax_cstr_length((
char *)file_path)];
528 logax_replace_char((
char *)file_path, formatted_file_name,
'\\',
'/');
530 logax_extract_name_only(file_path, formatted_file_name);
532 if (print_comma) { fprintf(stream,
" "); }
else { print_comma = 1; }
533 fprintf(stream,
"file=\"%s\"", formatted_file_name);
536 if (print_comma) { fprintf(stream,
" "); }
else { print_comma = 1; }
537 fprintf(stream,
"line_number=%zu", line_number);
540 if (print_comma) { fprintf(stream,
" "); }
else { print_comma = 1; }
541 fprintf(stream,
"function=\"%s\"", function_name);
543 if (print_comma) { fprintf(stream,
" "); }
544 fprintf(stream,
"message=\"");
545 vfprintf(stream, fmt, va_args);
546 fprintf(stream,
"\"\n");
552 static void logax_write_key_value_format_to_stream__internal__(FILE *stream,
int flags,
const char *file_path,
const size_t line_number,
const char *function_name,
const char *fmt, ...) {
554 va_start(va_args, fmt);
555 logax_write_key_value_format_to_stream_final__internal__(stream, flags, file_path, line_number, function_name, fmt, va_args);
562 #define logax_write_key_value_format_to_stream(stream, flags, fmt, ...) logax_write_key_value_format_to_stream__internal__(stream, flags, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__)
567 #define LOGAX_INTERNAL_WRITE_JSON_STR(key, value)\
568 LOGAX_DELEGATE_FPRINT_STR(LOGAX_FOREGROUND_DEBUG, "\"" key "\""); fprintf(stream, ":");\
569 LOGAX_WRITE_COLOR_CODE(LOGAX_FOREGROUND_TRACE); fprintf(stream, "\"%s\"", value); if (is_colored) { LOGAX_RESET_TERMINAL_ATTR(); }
574 #define LOGAX_INTERNAL_WRITE_JSON_SIZE_T(key, value)\
575 LOGAX_DELEGATE_FPRINT_STR(LOGAX_FOREGROUND_DEBUG, "\"" key "\""); fprintf(stream, ":");\
576 LOGAX_DELEGATE_FPRINT_SIZE_T(LOGAX_FOREGROUND_TRACE, value);
581 static void logax_write_json_format_to_stream_final__internal__(FILE *stream,
int flags,
const char *file_path,
const size_t line_number,
const char *function_name,
const char *fmt, va_list va_args) {
584 #ifndef LOGAX_NO_COLORING
587 unsigned is_colored = 0;
589 unsigned print_comma = 0;
593 fprintf(stream,
"{");
594 #ifndef LOGAX_NO_TIME
596 struct tm *current_time = localtime(&time_raw);
598 char date_buffer[16];
599 date_buffer[strftime(date_buffer,
sizeof(date_buffer),
"%Y-%m-%d", current_time)] =
'\0';
605 char time_buffer[16];
606 time_buffer[strftime(time_buffer,
sizeof(time_buffer),
"%H:%M:%S", current_time)] =
'\0';
607 if (print_comma) { fprintf(stream,
","); }
else { print_comma = 1; }
612 if (print_comma && has_any_level) { fprintf(stream,
","); }
else if (has_any_level) { print_comma = 1; }
628 char formatted_file_name[logax_cstr_length((
char *)file_path)];
630 logax_replace_char((
char *)file_path, formatted_file_name,
'\\',
'/');
632 logax_extract_name_only(file_path, formatted_file_name);
634 if (print_comma) { fprintf(stream,
","); }
else { print_comma = 1; }
638 if (print_comma) { fprintf(stream,
","); }
else { print_comma = 1; }
642 if (print_comma) { fprintf(stream,
","); }
else { print_comma = 1; }
645 if (print_comma) { fprintf(stream,
","); }
649 fprintf(stream,
"\""); vfprintf(stream, fmt, va_args); fprintf(stream,
"\"");
652 fprintf(stream,
"\""); vfprintf(stream, fmt, va_args); fprintf(stream,
"\"");
654 fprintf(stream,
"},\n");
660 static void logax_write_json_format_to_stream__internal__(FILE *stream,
int flags,
const char *file_path,
const size_t line_number,
const char *function_name,
const char *fmt, ...) {
662 va_start(va_args, fmt);
663 logax_write_json_format_to_stream_final__internal__(stream, flags, file_path, line_number, function_name, fmt, va_args);
670 #define logax_write_json_format_to_stream(stream, flags, fmt, ...) logax_write_json_format_to_stream__internal__(stream, flags, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__)
672 #define logax_write_text_format_to_stream(stream, flags, fmt, ...)
673 #define logax_write_key_value_format_to_stream(stream, flags, fmt, ...)
674 #define logax_write_json_format_to_stream(stream, flags, fmt, ...)
678 #if !defined(LOGAX_NO_OUTPUT_STREAM) && !defined(LOGAX_LOGGER_NO_OUTPUT_STREAM)
682 static void logax_logger_write(
LogaxLogger *logax_logger,
int level,
const char *file_path,
const size_t line_number,
const char *function_name,
const char *fmt, ...) {
683 logax_logger->
flags |= level;
688 logax_write_json_format_to_stream_final__internal__(logax_logger->
output_stream, logax_logger->
flags, file_path, line_number, function_name, fmt, args);
690 logax_write_key_value_format_to_stream_final__internal__(logax_logger->
output_stream, logax_logger->
flags, file_path, line_number, function_name, fmt, args);
692 logax_write_text_format_to_stream_final__internal__(logax_logger->
output_stream, logax_logger->
flags, file_path, line_number, function_name, fmt, args);
695 logax_logger->
flags &= ~level;
698 #define logax_logger_write(logax_logger, level, file_path, line_number, function_name, fmt, ...)
701 #ifndef LOGAX_LOGGER_NO_CALLBACK
705 #ifndef LOGAX_NO_TIME
706 #define logax_logger_report_to_callback(logax_logger, level, fmt, ...) {\
708 char time_buffer__logax_tmp_var__[16];\
709 char date_buffer__logax_tmp_var__[16];\
710 time_t time_raw__logax_tmp_var__ = time(LOGAX_NULL);\
711 struct tm *current_time__logax_tmp_var__ = localtime(&time_raw__logax_tmp_var__);\
712 date_buffer__logax_tmp_var__[strftime(date_buffer__logax_tmp_var__, sizeof(date_buffer__logax_tmp_var__), "%Y-%m-%d", current_time__logax_tmp_var__)] = '\0';\
713 time_buffer__logax_tmp_var__[strftime(time_buffer__logax_tmp_var__, sizeof(time_buffer__logax_tmp_var__), "%H:%M:%S", current_time__logax_tmp_var__)] = '\0';\
714 for (; index < LOGAX_MAX_CALLBACKS; index++) {\
715 logax_callback callback = (logax_logger)->callbacks[index];\
716 if (callback != LOGAX_NULL) {\
717 callback(date_buffer__logax_tmp_var__, time_buffer__logax_tmp_var__, level, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__);\
722 #define logax_logger_report_to_callback(logax_logger, level, fmt, ...) {\
724 for (; index < LOGAX_MAX_CALLBACKS; index++) {\
725 logax_callback callback = (logax_logger)->callbacks[index];\
726 if (callback != LOGAX_NULL) {\
727 callback(LOGAX_NULL, LOGAX_NULL, level, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__);\
733 #define logax_logger_report_to_callback(logax_logger, level, fmt, ...)
739 #define logax_logger_trace(logax_logger, fmt, ...) logax_logger_write(logax_logger, LOGAX_LEVEL_TRACE, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__);\
740 logax_logger_report_to_callback(logax_logger, LOGAX_LEVEL_TRACE, fmt, __VA_ARGS__)
745 #define logax_logger_debug(logax_logger, fmt, ...) logax_logger_write(logax_logger, LOGAX_LEVEL_DEBUG, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__);\
746 logax_logger_report_to_callback(logax_logger, LOGAX_LEVEL_DEBUG, fmt, __VA_ARGS__)
751 #define logax_logger_info(logax_logger, fmt, ...) logax_logger_write(logax_logger, LOGAX_LEVEL_INFO, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__);\
752 logax_logger_report_to_callback(logax_logger, LOGAX_LEVEL_INFO, fmt, __VA_ARGS__)
757 #define logax_logger_warn(logax_logger, fmt, ...) logax_logger_write(logax_logger, LOGAX_LEVEL_WARN, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__);\
758 logax_logger_report_to_callback(logax_logger, LOGAX_LEVEL_WARN, fmt, __VA_ARGS__)
763 #define logax_logger_error(logax_logger, fmt, ...) logax_logger_write(logax_logger, LOGAX_LEVEL_ERROR, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__);\
764 logax_logger_report_to_callback(logax_logger, LOGAX_LEVEL_ERROR, fmt, __VA_ARGS__)
769 #define logax_logger_fatal(logax_logger, fmt, ...) logax_logger_write(logax_logger, LOGAX_LEVEL_FATAL, __FILE__, __LINE__, __LOGAX_FUNCTION__, fmt, __VA_ARGS__);\
770 logax_logger_report_to_callback(logax_logger, LOGAX_LEVEL_FATAL, fmt, __VA_ARGS__)