liblogax
logax.h
Go to the documentation of this file.
1 
9 #ifndef EXOTIC_LOGAX_H
10 #define EXOTIC_LOGAX_H
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 #include <stdio.h>
17 #include <stdarg.h>
18 
19 #ifndef LOGAX_NO_TIME
20 #include <time.h>
21 #endif
22 
23 #if defined(_WIN32) && defined(LOGAX_USE_OLD_CONSOLE_MODE)
24 #include <windows.h>
25 #endif
26 
34 #ifdef __STDC_VERSION__
35  #define __LOGAX_STDC_VERSION__ __STDC_VERSION__
36 #else
37  #ifdef __cplusplus
38  #if __cplusplus > 199711L
39  #define __LOGAX_STDC_VERSION__ __cplusplus
40  #endif
41  #endif
42 #endif
43 #ifndef __LOGAX_STDC_VERSION__
44  #ifdef __FUNCTION__
45  #define __LOGAX_FUNCTION__ __FUNCTION__
46  #else
47  #define __LOGAX_FUNCTION__ "<unknown>"
48  #endif
49  #define LOGAX_NULL 0L
50 #else
51  #define __LOGAX_FUNCTION__ __func__
52  #define LOGAX_NULL NULL
53 #endif
54 
55 #if defined(_WIN32) && defined(LOGAX_USE_OLD_CONSOLE_MODE)
56 
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);
66 #else
67 
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)
77 #endif
78 
79 #ifndef LOGAX_LOGGER_NO_CALLBACK
80 
83 #ifndef LOGAX_MAX_CALLBACKS
84 #define LOGAX_MAX_CALLBACKS 5
85 #endif
86 
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, ...);
93 #endif
94 
101 #ifndef LOGAX_NO_TIME
102  LOGAX_OPTION_DATE = 1 << 2,
103  LOGAX_OPTION_TIME = 1 << 3,
105 #endif
109 #ifndef LOGAX_NO_COLORING
111 #endif
113  LOGAX_OPTION_ALL = 1 << 15
114 };
115 
116 /*
117 
118 */
119 #define LOGAX_OPTION_QUITE LOGAX_OPTION_QUIET
120 
125  LOGAX_LEVEL_TRACE = 1 << 16,
126  LOGAX_LEVEL_DEBUG = 1 << 17,
127  LOGAX_LEVEL_INFO = 1 << 18,
128  LOGAX_LEVEL_WARN = 1 << 19,
129  LOGAX_LEVEL_ERROR = 1 << 20,
130  LOGAX_LEVEL_FATAL = 1 << 21
131 };
132 
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" : "")
142 
150 };
151 
159  int flags;
160 #if !defined(LOGAX_NO_OUTPUT_STREAM)
162 #endif
163 #ifndef LOGAX_LOGGER_NO_CALLBACK
165 #endif
166 };
167 
172 
176 static void logax_init_logger(LogaxLogger *logax_logger) {
177  int index = 0;
179 #ifndef LOGAX_NO_COLORING
180  logax_logger->flags |= LOGAX_OPTION_COLORED;
181 #endif
182 #ifndef LOGAX_NO_TIME
183  logax_logger->flags |= LOGAX_OPTION_DATE_TIME;
184 #endif
185 #if defined(stdout) && !defined(LOGAX_NO_OUTPUT_STREAM)
186  logax_logger->output_stream = stdout;
187 #endif
188 #ifndef LOGAX_LOGGER_NO_CALLBACK
189  for (; index < LOGAX_MAX_CALLBACKS; index++) {
190  logax_logger->callbacks[index] = LOGAX_NULL;
191  }
192 #endif
193 }
194 
195 #if !defined(LOGAX_NO_OUTPUT_STREAM)
196 
199 static void logax_init_logger_ws(LogaxLogger *logax_logger, FILE *output_stream) {
200  int index = 0;
202 #ifndef LOGAX_NO_COLORING
203  logax_logger->flags |= LOGAX_OPTION_COLORED;
204 #endif
205 #ifndef LOGAX_NO_TIME
206  logax_logger->flags |= LOGAX_OPTION_DATE_TIME;
207 #endif
208  logax_logger->output_stream = output_stream;
209 #ifndef LOGAX_LOGGER_NO_CALLBACK
210  for (; index < LOGAX_MAX_CALLBACKS; index++) {
211  logax_logger->callbacks[index] = LOGAX_NULL;
212  }
213 #endif
214 }
215 #endif
216 
217 #ifndef LOGAX_LOGGER_NO_CALLBACK
218 
221 static unsigned logax_logger_add_callback(LogaxLogger *logax_logger, logax_callback callback) {
222  int index = 0;;
223  for (; index < LOGAX_MAX_CALLBACKS; index++) {
224  if (logax_logger->callbacks[index] == LOGAX_NULL) {
225  logax_logger->callbacks[index] = callback;
226  return index;
227  }
228  }
229  return -1;
230 }
231 #else
232 #define logax_logger_add_callback(logax_logger, callback)
233 #endif
234 
238 #define logax_add_flag(flags, flag) flags |= flag;
239 
243 #define logax_set_flag logax_add_flag
244 
248 #define logax_remove_flag(flags, flag) flags &= ~flag;
249 
253 #define logax_clear_flag logax_remove_flag
254 
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);\
263  }
264 
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); }\
271  }
272 
276 #define logax_set_quite logax_set_quiet
277 
278 #ifndef LOGAX_NO_OUTPUT_STREAM
279 /*
280 
281 */
282 static size_t logax_cstr_length(char char_array[]) {
283  size_t length = 0;
284  if (char_array == LOGAX_NULL) { return length; }
285  while(char_array[length] != '\0') {
286  length++;
287  }
288  return length;
289 }
290 
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;
299  } else {
300  formatted_file_name[i] = file_path[i];
301  }
302  ++i;
303  }
304  formatted_file_name[i] = '\0';
305 }
306 
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] == '/') {
314  j = 0;
315  } else if (j != -1) {
316  formatted_file_name[j] = file_path[i];
317  j++;
318  }
319  ++i;
320  }
321  formatted_file_name[j] = '\0';
322 }
323 
324 #if defined(_WIN32) && defined(LOGAX_USE_OLD_CONSOLE_MODE)
325 int logax_default_color = LOGAX_RESET_TERMINAL;
326 int initialized_h_console = 0;
327 HANDLE logax_hConsole;
328 
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;\
336  }\
337  logax_hConsole = GetStdHandle(STD_OUTPUT_HANDLE);\
338  initialized_h_console = 1;\
339  }
340 
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(); }
344 #else
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);
347 #endif
348 
349 #ifndef LOGAX_NO_COLORING
350 
353 #define LOGAX_WRITE_COLOR_CODE(color) SetConsoleTextAttribute(logax_hConsole, color);
354 #else
355 #define LOGAX_WRITE_COLOR_CODE(color)
356 #endif
357 
361 #define LOGAX_WRITE_LEVEL_COLOR__INTERNALL__(prefix_value, level, suffix_value)\
362  if (is_colored) {\
363  fprintf(stream, "%s", prefix_value); LOGAX_DELEGATE_FPRINT_STR(LOGAX_FOREGROUND_##level, #level); fprintf(stream, "%s", suffix_value);\
364  } else {\
365  fprintf(stream, "%s%s%s", prefix_value, #level, suffix_value);\
366  }
367 #else
368 
369 #define LOGAX_Iinitialized_HCONSOLE()
370 
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); }
374 #else
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);
377 #endif
378 
379 #ifndef LOGAX_NO_COLORING
380 
383 #define LOGAX_WRITE_COLOR_CODE(color) if (is_colored) { fprintf(stream, "%s", color); }
384 #else
385 #define LOGAX_WRITE_COLOR_CODE(color)
386 #endif
387 
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);
394 #endif
395 
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) {
400  if (flags & LOGAX_OPTION_QUIET) return;
402 #ifndef LOGAX_NO_COLORING
403  unsigned is_colored = (flags & LOGAX_OPTION_COLORED || (flags & LOGAX_OPTION_ALL));
404 #else
405  unsigned is_colored = 0;
406 #endif
407  unsigned print_comma = 0;
408  unsigned has_any_level = (flags & LOGAX_LEVEL_TRACE) || (flags & LOGAX_LEVEL_DEBUG) || (flags & LOGAX_LEVEL_INFO) ||
410  /* date and time */
411 #ifndef LOGAX_NO_TIME
412  time_t time_raw = time(LOGAX_NULL);
413  struct tm *current_time = localtime(&time_raw);
414  if ((flags & LOGAX_OPTION_DATE_TIME) || (flags & LOGAX_OPTION_DATE || (flags & LOGAX_OPTION_ALL))) {
415  char date_buffer[16];
416  date_buffer[strftime(date_buffer, sizeof(date_buffer), "%Y-%m-%d", current_time)] = '\0';
417  print_comma = 1;
418  fprintf(stream, "%s", date_buffer);
419  }
420  if ((flags & LOGAX_OPTION_DATE_TIME) || (flags & LOGAX_OPTION_TIME || (flags & LOGAX_OPTION_ALL))) {
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);
425  }
426 #endif
427  /* logging level */
428  if (print_comma && has_any_level) { fprintf(stream, " "); } else if (has_any_level) { print_comma = 1; }
429  if (flags & LOGAX_LEVEL_TRACE) {
431  } else if (flags & LOGAX_LEVEL_DEBUG) {
433  } else if (flags & LOGAX_LEVEL_INFO) {
435  } else if (flags & LOGAX_LEVEL_WARN) {
437  } else if (flags & LOGAX_LEVEL_ERROR) {
439  } else if (flags & LOGAX_LEVEL_FATAL) {
441  }
442  /* file path and line number */
443  if ((flags & LOGAX_OPTION_FILE_PATH) || (flags & LOGAX_OPTION_FILE_NAME_ONLY) || (flags & LOGAX_OPTION_ALL)) {
444  char formatted_file_name[logax_cstr_length((char *)file_path)];
445  if (flags & LOGAX_OPTION_FILE_PATH) {
446  logax_replace_char((char *)file_path, formatted_file_name, '\\', '/');
447  } else {
448  logax_extract_name_only(file_path, formatted_file_name);
449  }
450  if (print_comma) { fprintf(stream, " "); } else { print_comma = 1; }
451  fprintf(stream, "%s", formatted_file_name);
452  if (flags & LOGAX_OPTION_LINE_NUMBER || (flags & LOGAX_OPTION_ALL)) { fprintf(stream, ":"); }
453  }
454  if (flags & LOGAX_OPTION_LINE_NUMBER || (flags & LOGAX_OPTION_ALL)) {
455  fprintf(stream, "%zu", line_number);
456  if (flags & LOGAX_OPTION_FUNCTION || (flags & LOGAX_OPTION_ALL)) { fprintf(stream, " "); }
457  }
458  if (flags & LOGAX_OPTION_FUNCTION || (flags & LOGAX_OPTION_ALL)) {
459  if (print_comma) { fprintf(stream, " "); } else { print_comma = 1; }
460  fprintf(stream, "--- [%s\t]", function_name);
461  }
462  if (print_comma) { fprintf(stream, " "); }
463  vfprintf(stream, fmt, va_args);
464  fprintf(stream, "\n");
465 }
466 
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, ...) {
471  va_list va_args;
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);
474  va_end(va_args);
475 }
476 
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__)
481 
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) {
486  if (flags & LOGAX_OPTION_QUIET) return;
488  unsigned is_colored = 0;
489  unsigned print_comma = 0;
490  unsigned has_any_level = (flags & LOGAX_LEVEL_TRACE) || (flags & LOGAX_LEVEL_DEBUG) || (flags & LOGAX_LEVEL_INFO) ||
491  (flags & LOGAX_LEVEL_WARN) || (flags & LOGAX_LEVEL_ERROR) || (flags & LOGAX_LEVEL_FATAL);
492  /* date and time */
493 #ifndef LOGAX_NO_TIME
494  time_t time_raw = time(LOGAX_NULL);
495  struct tm *current_time = localtime(&time_raw);
496  if ((flags & LOGAX_OPTION_DATE_TIME) || (flags & LOGAX_OPTION_DATE || (flags & LOGAX_OPTION_ALL))) {
497  char date_buffer[16];
498  date_buffer[strftime(date_buffer, sizeof(date_buffer), "%Y-%m-%d", current_time)] = '\0';
499  print_comma = 1;
500  fprintf(stream, "date=\"%s\"", date_buffer);
501  }
502  if ((flags & LOGAX_OPTION_DATE_TIME) || (flags & LOGAX_OPTION_TIME || (flags & LOGAX_OPTION_ALL))) {
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);
507  }
508 #endif
509  /* logging level */
510  if (print_comma && has_any_level) { fprintf(stream, " "); } else if (has_any_level) { print_comma = 1; }
511  if (flags & LOGAX_LEVEL_TRACE) {
512  LOGAX_WRITE_LEVEL_COLOR__INTERNALL__("level=\"", TRACE, "\"");
513  } else if (flags & LOGAX_LEVEL_DEBUG) {
514  LOGAX_WRITE_LEVEL_COLOR__INTERNALL__("level=\"", DEBUG, "\"");
515  } else if (flags & LOGAX_LEVEL_INFO) {
516  LOGAX_WRITE_LEVEL_COLOR__INTERNALL__("level=\"", INFO, "\"");
517  } else if (flags & LOGAX_LEVEL_WARN) {
518  LOGAX_WRITE_LEVEL_COLOR__INTERNALL__("level=\"", WARN, "\"");
519  } else if (flags & LOGAX_LEVEL_ERROR) {
520  LOGAX_WRITE_LEVEL_COLOR__INTERNALL__("level=\"", ERROR, "\"");
521  } else if (flags & LOGAX_LEVEL_FATAL) {
522  LOGAX_WRITE_LEVEL_COLOR__INTERNALL__("level=\"", FATAL, "\"");
523  }
524  /* file path and line number */
525  if ((flags & LOGAX_OPTION_FILE_PATH) || (flags & LOGAX_OPTION_FILE_NAME_ONLY) || (flags & LOGAX_OPTION_ALL)) {
526  char formatted_file_name[logax_cstr_length((char *)file_path)];
527  if (flags & LOGAX_OPTION_FILE_PATH) {
528  logax_replace_char((char *)file_path, formatted_file_name, '\\', '/');
529  } else {
530  logax_extract_name_only(file_path, formatted_file_name);
531  }
532  if (print_comma) { fprintf(stream, " "); } else { print_comma = 1; }
533  fprintf(stream, "file=\"%s\"", formatted_file_name);
534  }
535  if (flags & LOGAX_OPTION_LINE_NUMBER || (flags & LOGAX_OPTION_ALL)) {
536  if (print_comma) { fprintf(stream, " "); } else { print_comma = 1; }
537  fprintf(stream, "line_number=%zu", line_number);
538  }
539  if (flags & LOGAX_OPTION_FUNCTION || (flags & LOGAX_OPTION_ALL)) {
540  if (print_comma) { fprintf(stream, " "); } else { print_comma = 1; }
541  fprintf(stream, "function=\"%s\"", function_name);
542  }
543  if (print_comma) { fprintf(stream, " "); }
544  fprintf(stream, "message=\"");
545  vfprintf(stream, fmt, va_args);
546  fprintf(stream, "\"\n");
547 }
548 
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, ...) {
553  va_list va_args;
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);
556  va_end(va_args);
557 }
558 
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__)
563 
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(); }
570 
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);
577 
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) {
582  if (flags & LOGAX_OPTION_QUIET) return;
584 #ifndef LOGAX_NO_COLORING
585  unsigned is_colored = (flags & LOGAX_OPTION_COLORED || (flags & LOGAX_OPTION_ALL));
586 #else
587  unsigned is_colored = 0;
588 #endif
589  unsigned print_comma = 0;
590  unsigned has_any_level = (flags & LOGAX_LEVEL_TRACE) || (flags & LOGAX_LEVEL_DEBUG) || (flags & LOGAX_LEVEL_INFO) ||
591  (flags & LOGAX_LEVEL_WARN) || (flags & LOGAX_LEVEL_ERROR) || (flags & LOGAX_LEVEL_FATAL);
592  /* date and time */
593  fprintf(stream, "{");
594 #ifndef LOGAX_NO_TIME
595  time_t time_raw = time(LOGAX_NULL);
596  struct tm *current_time = localtime(&time_raw);
597  if ((flags & LOGAX_OPTION_DATE_TIME) || (flags & LOGAX_OPTION_DATE || (flags & LOGAX_OPTION_ALL))) {
598  char date_buffer[16];
599  date_buffer[strftime(date_buffer, sizeof(date_buffer), "%Y-%m-%d", current_time)] = '\0';
600 
601  print_comma = 1;
602  LOGAX_INTERNAL_WRITE_JSON_STR("date", date_buffer);
603  }
604  if ((flags & LOGAX_OPTION_DATE_TIME) || (flags & LOGAX_OPTION_TIME) || (flags & LOGAX_OPTION_ALL)) {
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; }
608  LOGAX_INTERNAL_WRITE_JSON_STR("time", time_buffer);
609  }
610 #endif
611  /* logging level */
612  if (print_comma && has_any_level) { fprintf(stream, ","); } else if (has_any_level) { print_comma = 1; }
613  if (flags & LOGAX_LEVEL_TRACE) {
614  LOGAX_INTERNAL_WRITE_JSON_STR("level", "TRACE");
615  } else if (flags & LOGAX_LEVEL_DEBUG) {
616  LOGAX_INTERNAL_WRITE_JSON_STR("level", "DEBUG");
617  } else if (flags & LOGAX_LEVEL_INFO) {
618  LOGAX_INTERNAL_WRITE_JSON_STR("level", "INFO");
619  } else if (flags & LOGAX_LEVEL_WARN) {
620  LOGAX_INTERNAL_WRITE_JSON_STR("level", "WARN");
621  } else if (flags & LOGAX_LEVEL_ERROR) {
622  LOGAX_INTERNAL_WRITE_JSON_STR("level", "ERROR");
623  } else if (flags & LOGAX_LEVEL_FATAL) {
624  LOGAX_INTERNAL_WRITE_JSON_STR("level", "FATAL");
625  }
626  /* file path and line number */
627  if ((flags & LOGAX_OPTION_FILE_PATH) || (flags & LOGAX_OPTION_FILE_NAME_ONLY) || (flags & LOGAX_OPTION_ALL)) {
628  char formatted_file_name[logax_cstr_length((char *)file_path)];
629  if (flags & LOGAX_OPTION_FILE_PATH) {
630  logax_replace_char((char *)file_path, formatted_file_name, '\\', '/');
631  } else {
632  logax_extract_name_only(file_path, formatted_file_name);
633  }
634  if (print_comma) { fprintf(stream, ","); } else { print_comma = 1; }
635  LOGAX_INTERNAL_WRITE_JSON_STR("file", formatted_file_name);
636  }
637  if (flags & LOGAX_OPTION_LINE_NUMBER || (flags & LOGAX_OPTION_ALL)) {
638  if (print_comma) { fprintf(stream, ","); } else { print_comma = 1; }
639  LOGAX_INTERNAL_WRITE_JSON_SIZE_T("line_number", line_number);
640  }
641  if (flags & LOGAX_OPTION_FUNCTION || (flags & LOGAX_OPTION_ALL)) {
642  if (print_comma) { fprintf(stream, ","); } else { print_comma = 1; }
643  LOGAX_INTERNAL_WRITE_JSON_STR("function", function_name);
644  }
645  if (print_comma) { fprintf(stream, ","); }
646  LOGAX_DELEGATE_FPRINT_STR(LOGAX_FOREGROUND_DEBUG, "\"message\""); fprintf(stream, ":");
647  if (is_colored) {
649  fprintf(stream, "\""); vfprintf(stream, fmt, va_args); fprintf(stream, "\"");
651  } else {
652  fprintf(stream, "\""); vfprintf(stream, fmt, va_args); fprintf(stream, "\"");
653  }
654  fprintf(stream, "},\n");
655 }
656 
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, ...) {
661  va_list va_args;
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);
664  va_end(va_args);
665 }
666 
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__)
671 #else
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, ...)
675 
676 #endif
677 
678 #if !defined(LOGAX_NO_OUTPUT_STREAM) && !defined(LOGAX_LOGGER_NO_OUTPUT_STREAM)
679 
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;
684  va_list args;
685 
686  va_start(args, fmt);
687  if (logax_logger->flags & LOGAX_FORMATTER_JSON) {
688  logax_write_json_format_to_stream_final__internal__(logax_logger->output_stream, logax_logger->flags, file_path, line_number, function_name, fmt, args);
689  } else if (logax_logger->flags & LOGAX_FORMATTER_KEY_VALUE) {
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);
691  } else {
692  logax_write_text_format_to_stream_final__internal__(logax_logger->output_stream, logax_logger->flags, file_path, line_number, function_name, fmt, args);
693  }
694  va_end(args);
695  logax_logger->flags &= ~level;
696 }
697 #else
698 #define logax_logger_write(logax_logger, level, file_path, line_number, function_name, fmt, ...)
699 #endif
700 
701 #ifndef LOGAX_LOGGER_NO_CALLBACK
702 /* TODO: Refractor to a function */
705 #ifndef LOGAX_NO_TIME
706  #define logax_logger_report_to_callback(logax_logger, level, fmt, ...) {\
707  int index = 0;\
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__);\
718  }\
719  }\
720  }
721 #else
722  #define logax_logger_report_to_callback(logax_logger, level, fmt, ...) {\
723  int index = 0;\
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__);\
728  }\
729  }\
730  }
731 #endif
732 #else
733 #define logax_logger_report_to_callback(logax_logger, level, fmt, ...)
734 #endif
735 
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__)
741 
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__)
747 
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__)
753 
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__)
759 
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__)
765 
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__)
771 
772 
773 #ifdef __cplusplus
774 }
775 #endif
776 
777 #endif
LOGAX_LEVEL_ERROR
@ LOGAX_LEVEL_ERROR
Definition: logax.h:129
LOGAX_INTERNAL_WRITE_JSON_SIZE_T
#define LOGAX_INTERNAL_WRITE_JSON_SIZE_T(key, value)
Definition: logax.h:574
logax_logger_s::flags
int flags
Definition: logax.h:159
LOGAX_OPTION_TIME
@ LOGAX_OPTION_TIME
Definition: logax.h:103
LOGAX_LEVEL_WARN
@ LOGAX_LEVEL_WARN
Definition: logax.h:128
LOGAX_FORMATTER_JSON
@ LOGAX_FORMATTER_JSON
Definition: logax.h:149
LOGAX_RESET_TERMINAL_ATTR
#define LOGAX_RESET_TERMINAL_ATTR()
Definition: logax.h:75
LOGAX_RESET_TERMINAL
#define LOGAX_RESET_TERMINAL
Definition: logax.h:68
logax_callback
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,...)
Definition: logax.h:92
LogaxOption
LogaxOption
Definition: logax.h:99
LOGAX_LEVEL_INFO
@ LOGAX_LEVEL_INFO
Definition: logax.h:127
LOGAX_OPTION_DATE_TIME
@ LOGAX_OPTION_DATE_TIME
Definition: logax.h:104
logax_logger_s::output_stream
FILE * output_stream
Definition: logax.h:161
LOGAX_NULL
#define LOGAX_NULL
Definition: logax.h:49
logax_logger_s
Definition: logax.h:158
LOGAX_OPTION_QUIET
@ LOGAX_OPTION_QUIET
Definition: logax.h:100
LOGAX_WRITE_LEVEL_COLOR__INTERNALL__
#define LOGAX_WRITE_LEVEL_COLOR__INTERNALL__(prefix_value, level, suffix_value)
Definition: logax.h:391
LogaxFormatter
LogaxFormatter
Definition: logax.h:146
LOGAX_DELEGATE_FPRINT_STR
#define LOGAX_DELEGATE_FPRINT_STR(foreground, text)
Definition: logax.h:372
LOGAX_LEVEL_TRACE
@ LOGAX_LEVEL_TRACE
Definition: logax.h:125
LOGAX_LEVEL_FATAL
@ LOGAX_LEVEL_FATAL
Definition: logax.h:130
LOGAX_OPTION_LINE_NUMBER
@ LOGAX_OPTION_LINE_NUMBER
Definition: logax.h:108
LOGAX_OPTION_COLORED
@ LOGAX_OPTION_COLORED
Definition: logax.h:110
LOGAX_MAX_CALLBACKS
#define LOGAX_MAX_CALLBACKS
Definition: logax.h:84
logax_logger_s::callbacks
logax_callback callbacks[LOGAX_MAX_CALLBACKS]
Definition: logax.h:164
LOGAX_OPTION_FUNCTION
@ LOGAX_OPTION_FUNCTION
Definition: logax.h:112
LOGAX_WRITE_COLOR_CODE
#define LOGAX_WRITE_COLOR_CODE(color)
Definition: logax.h:383
LOGAX_OPTION_ALL
@ LOGAX_OPTION_ALL
Definition: logax.h:113
LOGAX_OPTION_FILE_NAME_ONLY
@ LOGAX_OPTION_FILE_NAME_ONLY
Definition: logax.h:107
LOGAX_FORMATTER_KEY_VALUE
@ LOGAX_FORMATTER_KEY_VALUE
Definition: logax.h:148
LOGAX_OPTION_FILE_PATH
@ LOGAX_OPTION_FILE_PATH
Definition: logax.h:106
LOGAX_INTERNAL_WRITE_JSON_STR
#define LOGAX_INTERNAL_WRITE_JSON_STR(key, value)
Definition: logax.h:567
LOGAX_FORMATTER_TEXT
@ LOGAX_FORMATTER_TEXT
Definition: logax.h:147
LOGAX_OPTION_DATE
@ LOGAX_OPTION_DATE
Definition: logax.h:102
LogaxLevel
LogaxLevel
Definition: logax.h:124
LOGAX_LEVEL_DEBUG
@ LOGAX_LEVEL_DEBUG
Definition: logax.h:126
LOGAX_FOREGROUND_DEBUG
#define LOGAX_FOREGROUND_DEBUG
Definition: logax.h:70
LOGAX_Iinitialized_HCONSOLE
#define LOGAX_Iinitialized_HCONSOLE()
Definition: logax.h:369
LOGAX_FOREGROUND_TRACE
#define LOGAX_FOREGROUND_TRACE
Definition: logax.h:69