Blender  V2.93
clog.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 /* Disable for small single threaded programs
29  * to avoid having to link with pthreads. */
30 #ifdef WITH_CLOG_PTHREADS
31 # include "atomic_ops.h"
32 # include <pthread.h>
33 #endif
34 
35 /* For 'isatty' to check for color. */
36 #if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
37 # include <sys/time.h>
38 # include <unistd.h>
39 #endif
40 
41 #if defined(_MSC_VER)
42 # include <Windows.h>
43 
44 # include <VersionHelpers.h> /* This needs to be included after Windows.h. */
45 # include <io.h>
46 # if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
47 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
48 # endif
49 #endif
50 
51 /* For printing timestamp. */
52 #define __STDC_FORMAT_MACROS
53 #include <inttypes.h>
54 
55 /* Only other dependency (could use regular malloc too). */
56 #include "MEM_guardedalloc.h"
57 
58 /* own include. */
59 #include "CLG_log.h"
60 
61 /* Local utility defines */
62 #define STREQ(a, b) (strcmp(a, b) == 0)
63 #define STREQLEN(a, b, n) (strncmp(a, b, n) == 0)
64 
65 #ifdef _WIN32
66 # define PATHSEP_CHAR '\\'
67 #else
68 # define PATHSEP_CHAR '/'
69 #endif
70 
71 /* -------------------------------------------------------------------- */
75 typedef struct CLG_IDFilter {
76  struct CLG_IDFilter *next;
78  char match[0];
80 
81 typedef struct CLogContext {
86 #ifdef WITH_CLOG_PTHREADS
87  pthread_mutex_t types_lock;
88 #endif
89 
90  /* exclude, include filters. */
92  bool use_color;
95 
97  int output;
98  FILE *output_file;
99 
102 
104  struct {
105  int level;
107 
108  struct {
109  void (*error_fn)(void *file_handle);
110  void (*fatal_fn)(void *file_handle);
111  void (*backtrace_fn)(void *file_handle);
114 
117 /* -------------------------------------------------------------------- */
123 #define CLOG_BUF_LEN_INIT 512
124 
125 typedef struct CLogStringBuf {
126  char *data;
129  bool is_alloc;
131 
132 static void clg_str_init(CLogStringBuf *cstr, char *buf_stack, uint buf_stack_len)
133 {
134  cstr->data = buf_stack;
135  cstr->len_alloc = buf_stack_len;
136  cstr->len = 0;
137  cstr->is_alloc = false;
138 }
139 
140 static void clg_str_free(CLogStringBuf *cstr)
141 {
142  if (cstr->is_alloc) {
143  MEM_freeN(cstr->data);
144  }
145 }
146 
147 static void clg_str_reserve(CLogStringBuf *cstr, const uint len)
148 {
149  if (len > cstr->len_alloc) {
150  cstr->len_alloc *= 2;
151  if (len > cstr->len_alloc) {
152  cstr->len_alloc = len;
153  }
154 
155  if (cstr->is_alloc) {
156  cstr->data = MEM_reallocN(cstr->data, cstr->len_alloc);
157  }
158  else {
159  /* Copy the static buffer. */
160  char *data = MEM_mallocN(cstr->len_alloc, __func__);
161  memcpy(data, cstr->data, cstr->len);
162  cstr->data = data;
163  cstr->is_alloc = true;
164  }
165  }
166 }
167 
168 static void clg_str_append_with_len(CLogStringBuf *cstr, const char *str, const uint len)
169 {
170  uint len_next = cstr->len + len;
171  clg_str_reserve(cstr, len_next);
172  char *str_dst = cstr->data + cstr->len;
173  memcpy(str_dst, str, len);
174 #if 0 /* no need. */
175  str_dst[len] = '\0';
176 #endif
177  cstr->len = len_next;
178 }
179 
180 static void clg_str_append(CLogStringBuf *cstr, const char *str)
181 {
182  clg_str_append_with_len(cstr, str, strlen(str));
183 }
184 
185 ATTR_PRINTF_FORMAT(2, 0)
186 static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
187 {
188  /* Use limit because windows may use '-1' for a formatting error. */
189  const uint len_max = 65535;
190  while (true) {
191  uint len_avail = cstr->len_alloc - cstr->len;
192 
193  va_list args_cpy;
194  va_copy(args_cpy, args);
195  int retval = vsnprintf(cstr->data + cstr->len, len_avail, fmt, args_cpy);
196  va_end(args_cpy);
197 
198  if (retval < 0) {
199  /* Some encoding error happened, not much we can do here, besides skipping/canceling this
200  * message. */
201  break;
202  }
203  else if ((uint)retval <= len_avail) {
204  /* Copy was successful. */
205  cstr->len += (uint)retval;
206  break;
207  }
208  else {
209  /* vsnprintf was not successful, due to lack of allocated space, retval contains expected
210  * length of the formatted string, use it to allocate required amount of memory. */
211  uint len_alloc = cstr->len + (uint)retval;
212  if (len_alloc >= len_max) {
213  /* Safe upper-limit, just in case... */
214  break;
215  }
216  clg_str_reserve(cstr, len_alloc);
217  len_avail = cstr->len_alloc - cstr->len;
218  }
219  }
220 }
221 
224 /* -------------------------------------------------------------------- */
233 
235 };
236 #define COLOR_LEN (COLOR_RESET + 1)
237 
238 static const char *clg_color_table[COLOR_LEN] = {NULL};
239 #ifdef _WIN32
240 static DWORD clg_previous_console_mode = 0;
241 #endif
242 
243 static void clg_color_table_init(bool use_color)
244 {
245  for (int i = 0; i < COLOR_LEN; i++) {
246  clg_color_table[i] = "";
247  }
248  if (use_color) {
249  clg_color_table[COLOR_DEFAULT] = "\033[1;37m";
250  clg_color_table[COLOR_RED] = "\033[1;31m";
251  clg_color_table[COLOR_GREEN] = "\033[1;32m";
252  clg_color_table[COLOR_YELLOW] = "\033[1;33m";
253  clg_color_table[COLOR_RESET] = "\033[0m";
254  }
255 }
256 
257 static const char *clg_severity_str[CLG_SEVERITY_LEN] = {
258  [CLG_SEVERITY_INFO] = "INFO",
259  [CLG_SEVERITY_WARN] = "WARN",
260  [CLG_SEVERITY_ERROR] = "ERROR",
261  [CLG_SEVERITY_FATAL] = "FATAL",
262 };
263 
264 static const char *clg_severity_as_text(enum CLG_Severity severity)
265 {
266  bool ok = (unsigned int)severity < CLG_SEVERITY_LEN;
267  assert(ok);
268  if (ok) {
269  return clg_severity_str[severity];
270  }
271  else {
272  return "INVALID_SEVERITY";
273  }
274 }
275 
276 static enum eCLogColor clg_severity_to_color(enum CLG_Severity severity)
277 {
278  assert((unsigned int)severity < CLG_SEVERITY_LEN);
279  enum eCLogColor color = COLOR_DEFAULT;
280  switch (severity) {
281  case CLG_SEVERITY_INFO:
282  color = COLOR_DEFAULT;
283  break;
284  case CLG_SEVERITY_WARN:
285  color = COLOR_YELLOW;
286  break;
287  case CLG_SEVERITY_ERROR:
288  case CLG_SEVERITY_FATAL:
289  color = COLOR_RED;
290  break;
291  default:
292  /* should never get here. */
293  assert(false);
294  }
295  return color;
296 }
297 
300 /* -------------------------------------------------------------------- */
312 static bool clg_ctx_filter_check(CLogContext *ctx, const char *identifier)
313 {
314  const size_t identifier_len = strlen(identifier);
315  for (uint i = 0; i < 2; i++) {
316  const CLG_IDFilter *flt = ctx->filters[i];
317  while (flt != NULL) {
318  const size_t len = strlen(flt->match);
319  if (STREQ(flt->match, "*") || ((len == identifier_len) && (STREQ(identifier, flt->match)))) {
320  return (bool)i;
321  }
322  if (flt->match[0] == '*' && flt->match[len - 1] == '*') {
323  char *match = MEM_callocN(sizeof(char) * len - 1, __func__);
324  memcpy(match, flt->match + 1, len - 2);
325  if (strstr(identifier, match) != NULL) {
326  return (bool)i;
327  }
328  }
329  else if ((len >= 2) && (STREQLEN(".*", &flt->match[len - 2], 2))) {
330  if (((identifier_len == len - 2) && STREQLEN(identifier, flt->match, len - 2)) ||
331  ((identifier_len >= len - 1) && STREQLEN(identifier, flt->match, len - 1))) {
332  return (bool)i;
333  }
334  }
335  flt = flt->next;
336  }
337  }
338  return false;
339 }
340 
345 static CLG_LogType *clg_ctx_type_find_by_name(CLogContext *ctx, const char *identifier)
346 {
347  for (CLG_LogType *ty = ctx->types; ty; ty = ty->next) {
348  if (STREQ(identifier, ty->identifier)) {
349  return ty;
350  }
351  }
352  return NULL;
353 }
354 
355 static CLG_LogType *clg_ctx_type_register(CLogContext *ctx, const char *identifier)
356 {
357  assert(clg_ctx_type_find_by_name(ctx, identifier) == NULL);
358  CLG_LogType *ty = MEM_callocN(sizeof(*ty), __func__);
359  ty->next = ctx->types;
360  ctx->types = ty;
361  strncpy(ty->identifier, identifier, sizeof(ty->identifier) - 1);
362  ty->ctx = ctx;
363  ty->level = ctx->default_type.level;
364 
365  if (clg_ctx_filter_check(ctx, ty->identifier)) {
366  ty->flag |= CLG_FLAG_USE;
367  }
368  return ty;
369 }
370 
372 {
373  if (ctx->callbacks.error_fn != NULL) {
374  ctx->callbacks.error_fn(ctx->output_file);
375  }
376 }
377 
379 {
380  if (ctx->callbacks.fatal_fn != NULL) {
381  ctx->callbacks.fatal_fn(ctx->output_file);
382  }
383  fflush(ctx->output_file);
384  abort();
385 }
386 
388 {
389  /* Note: we avoid writing to 'FILE', for back-trace we make an exception,
390  * if necessary we could have a version of the callback that writes to file
391  * descriptor all at once. */
393  fflush(ctx->output_file);
394 }
395 
397 {
398  uint64_t tick;
399 #if defined(_MSC_VER)
400  tick = GetTickCount64();
401 #else
402  struct timeval tv;
403  gettimeofday(&tv, NULL);
404  tick = tv.tv_sec * 1000 + tv.tv_usec / 1000;
405 #endif
406  return tick;
407 }
408 
411 /* -------------------------------------------------------------------- */
415 static void write_timestamp(CLogStringBuf *cstr, const uint64_t timestamp_tick_start)
416 {
417  char timestamp_str[64];
418  const uint64_t timestamp = clg_timestamp_ticks_get() - timestamp_tick_start;
419  const uint timestamp_len = snprintf(timestamp_str,
420  sizeof(timestamp_str),
421  "%" PRIu64 ".%03u ",
422  timestamp / 1000,
423  (uint)(timestamp % 1000));
424  clg_str_append_with_len(cstr, timestamp_str, timestamp_len);
425 }
426 
427 static void write_severity(CLogStringBuf *cstr, enum CLG_Severity severity, bool use_color)
428 {
429  assert((unsigned int)severity < CLG_SEVERITY_LEN);
430  if (use_color) {
431  enum eCLogColor color = clg_severity_to_color(severity);
432  clg_str_append(cstr, clg_color_table[color]);
433  clg_str_append(cstr, clg_severity_as_text(severity));
435  }
436  else {
437  clg_str_append(cstr, clg_severity_as_text(severity));
438  }
439 }
440 
441 static void write_type(CLogStringBuf *cstr, CLG_LogType *lg)
442 {
443  clg_str_append(cstr, " (");
444  clg_str_append(cstr, lg->identifier);
445  clg_str_append(cstr, "): ");
446 }
447 
449  const char *file_line,
450  const char *fn,
451  const bool use_basename)
452 {
453  uint file_line_len = strlen(file_line);
454  if (use_basename) {
455  uint file_line_offset = file_line_len;
456  while (file_line_offset-- > 0) {
457  if (file_line[file_line_offset] == PATHSEP_CHAR) {
458  file_line_offset++;
459  break;
460  }
461  }
462  file_line += file_line_offset;
463  file_line_len -= file_line_offset;
464  }
465  clg_str_append_with_len(cstr, file_line, file_line_len);
466 
467  clg_str_append(cstr, " ");
468  clg_str_append(cstr, fn);
469  clg_str_append(cstr, ": ");
470 }
471 
473  enum CLG_Severity severity,
474  const char *file_line,
475  const char *fn,
476  const char *message)
477 {
478  CLogStringBuf cstr;
479  char cstr_stack_buf[CLOG_BUF_LEN_INIT];
480  clg_str_init(&cstr, cstr_stack_buf, sizeof(cstr_stack_buf));
481 
482  if (lg->ctx->use_timestamp) {
484  }
485 
486  write_severity(&cstr, severity, lg->ctx->use_color);
487  write_type(&cstr, lg);
488 
489  {
490  write_file_line_fn(&cstr, file_line, fn, lg->ctx->use_basename);
491  clg_str_append(&cstr, message);
492  }
493  clg_str_append(&cstr, "\n");
494 
495  /* could be optional */
496  int bytes_written = write(lg->ctx->output, cstr.data, cstr.len);
497  (void)bytes_written;
498 
499  clg_str_free(&cstr);
500 
501  if (lg->ctx->callbacks.backtrace_fn) {
502  clg_ctx_backtrace(lg->ctx);
503  }
504 
505  if (severity == CLG_SEVERITY_FATAL) {
507  }
508 }
509 
511  enum CLG_Severity severity,
512  const char *file_line,
513  const char *fn,
514  const char *fmt,
515  ...)
516 {
517  CLogStringBuf cstr;
518  char cstr_stack_buf[CLOG_BUF_LEN_INIT];
519  clg_str_init(&cstr, cstr_stack_buf, sizeof(cstr_stack_buf));
520 
521  if (lg->ctx->use_timestamp) {
523  }
524 
525  write_severity(&cstr, severity, lg->ctx->use_color);
526  write_type(&cstr, lg);
527 
528  {
529  write_file_line_fn(&cstr, file_line, fn, lg->ctx->use_basename);
530 
531  va_list ap;
532  va_start(ap, fmt);
533  clg_str_vappendf(&cstr, fmt, ap);
534  va_end(ap);
535  }
536  clg_str_append(&cstr, "\n");
537 
538  /* could be optional */
539  int bytes_written = write(lg->ctx->output, cstr.data, cstr.len);
540  (void)bytes_written;
541 
542  clg_str_free(&cstr);
543 
544  if (lg->ctx->callbacks.backtrace_fn) {
545  clg_ctx_backtrace(lg->ctx);
546  }
547 
548  if (severity == CLG_SEVERITY_ERROR) {
550  }
551 
552  if (severity == CLG_SEVERITY_FATAL) {
554  }
555 }
556 
559 /* -------------------------------------------------------------------- */
563 static void CLG_ctx_output_set(CLogContext *ctx, void *file_handle)
564 {
565  ctx->output_file = file_handle;
566  ctx->output = fileno(ctx->output_file);
567 #if defined(__unix__) || defined(__APPLE__)
568  ctx->use_color = isatty(ctx->output);
569 #elif defined(WIN32)
570  /* As of Windows 10 build 18298 all the standard consoles supports color
571  * like the Linux Terminal do, but it needs to be turned on.
572  * To turn on colors we need to enable virtual terminal processing by passing the flag
573  * ENABLE_VIRTUAL_TERMINAL_PROCESSING into SetConsoleMode.
574  * If the system doesn't support virtual terminal processing it will fail silently and the flag
575  * will not be set. */
576 
577  GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &clg_previous_console_mode);
578 
579  ctx->use_color = 0;
580  if (IsWindows10OrGreater() && isatty(ctx->output)) {
581  DWORD mode = clg_previous_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
582  if (SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), mode)) {
583  ctx->use_color = 1;
584  }
585  }
586 #endif
587 }
588 
589 static void CLG_ctx_output_use_basename_set(CLogContext *ctx, int value)
590 {
591  ctx->use_basename = (bool)value;
592 }
593 
594 static void CLG_ctx_output_use_timestamp_set(CLogContext *ctx, int value)
595 {
596  ctx->use_timestamp = (bool)value;
597  if (ctx->use_timestamp) {
599  }
600 }
601 
603 static void CLT_ctx_error_fn_set(CLogContext *ctx, void (*error_fn)(void *file_handle))
604 {
605  ctx->callbacks.error_fn = error_fn;
606 }
607 
609 static void CLG_ctx_fatal_fn_set(CLogContext *ctx, void (*fatal_fn)(void *file_handle))
610 {
611  ctx->callbacks.fatal_fn = fatal_fn;
612 }
613 
614 static void CLG_ctx_backtrace_fn_set(CLogContext *ctx, void (*backtrace_fn)(void *file_handle))
615 {
616  ctx->callbacks.backtrace_fn = backtrace_fn;
617 }
618 
620  const char *type_match,
621  int type_match_len)
622 {
623  if (type_match_len == 0) {
624  return;
625  }
626  CLG_IDFilter *flt = MEM_callocN(sizeof(*flt) + (type_match_len + 1), __func__);
627  flt->next = *flt_list;
628  *flt_list = flt;
629  memcpy(flt->match, type_match, type_match_len);
630  /* no need to null terminate since we calloc'd */
631 }
632 
634  const char *type_match,
635  int type_match_len)
636 {
637  clg_ctx_type_filter_append(&ctx->filters[0], type_match, type_match_len);
638 }
639 
641  const char *type_match,
642  int type_match_len)
643 {
644  clg_ctx_type_filter_append(&ctx->filters[1], type_match, type_match_len);
645 }
646 
647 static void CLG_ctx_level_set(CLogContext *ctx, int level)
648 {
649  ctx->default_type.level = level;
650  for (CLG_LogType *ty = ctx->types; ty; ty = ty->next) {
651  ty->level = level;
652  }
653 }
654 
656 {
657  CLogContext *ctx = MEM_callocN(sizeof(*ctx), __func__);
658 #ifdef WITH_CLOG_PTHREADS
659  pthread_mutex_init(&ctx->types_lock, NULL);
660 #endif
661  ctx->default_type.level = 1;
662  CLG_ctx_output_set(ctx, stdout);
663 
664  return ctx;
665 }
666 
667 static void CLG_ctx_free(CLogContext *ctx)
668 {
669 #if defined(WIN32)
670  SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), clg_previous_console_mode);
671 #endif
672  while (ctx->types != NULL) {
673  CLG_LogType *item = ctx->types;
674  ctx->types = item->next;
675  MEM_freeN(item);
676  }
677 
678  while (ctx->refs != NULL) {
679  CLG_LogRef *item = ctx->refs;
680  ctx->refs = item->next;
681  item->type = NULL;
682  }
683 
684  for (uint i = 0; i < 2; i++) {
685  while (ctx->filters[i] != NULL) {
686  CLG_IDFilter *item = ctx->filters[i];
687  ctx->filters[i] = item->next;
688  MEM_freeN(item);
689  }
690  }
691 #ifdef WITH_CLOG_PTHREADS
692  pthread_mutex_destroy(&ctx->types_lock);
693 #endif
694  MEM_freeN(ctx);
695 }
696 
699 /* -------------------------------------------------------------------- */
705 /* We could support multiple at once, for now this seems not needed. */
706 static struct CLogContext *g_ctx = NULL;
707 
708 void CLG_init(void)
709 {
710  g_ctx = CLG_ctx_init();
711 
713 }
714 
715 void CLG_exit(void)
716 {
718 }
719 
720 void CLG_output_set(void *file_handle)
721 {
722  CLG_ctx_output_set(g_ctx, file_handle);
723 }
724 
726 {
728 }
729 
731 {
733 }
734 
735 void CLG_error_fn_set(void (*error_fn)(void *file_handle))
736 {
738 }
739 
740 void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle))
741 {
743 }
744 
745 void CLG_backtrace_fn_set(void (*fatal_fn)(void *file_handle))
746 {
748 }
749 
750 void CLG_type_filter_exclude(const char *type_match, int type_match_len)
751 {
752  CLG_ctx_type_filter_exclude(g_ctx, type_match, type_match_len);
753 }
754 
755 void CLG_type_filter_include(const char *type_match, int type_match_len)
756 {
757  CLG_ctx_type_filter_include(g_ctx, type_match, type_match_len);
758 }
759 
761 {
763 }
764 
767 /* -------------------------------------------------------------------- */
774 {
775 #ifdef WITH_CLOG_PTHREADS
776  /* Only runs once when initializing a static type in most cases. */
777  pthread_mutex_lock(&g_ctx->types_lock);
778 #endif
779  if (clg_ref->type == NULL) {
780  /* Add to the refs list so we can NULL the pointers to 'type' when CLG_exit() is called. */
781  clg_ref->next = g_ctx->refs;
782  g_ctx->refs = clg_ref;
783 
785  if (clg_ty == NULL) {
786  clg_ty = clg_ctx_type_register(g_ctx, clg_ref->identifier);
787  }
788 #ifdef WITH_CLOG_PTHREADS
789  atomic_cas_ptr((void **)&clg_ref->type, clg_ref->type, clg_ty);
790 #else
791  clg_ref->type = clg_ty;
792 #endif
793  }
794 #ifdef WITH_CLOG_PTHREADS
795  pthread_mutex_unlock(&g_ctx->types_lock);
796 #endif
797 }
798 
800 {
801  if (clg_ref->type == NULL) {
802  CLG_logref_init(clg_ref);
803  }
804  return clg_ref->type->ctx->use_color;
805 }
806 
#define va_copy(a, b)
Definition: BLI_dynstr.c:45
size_t ATTR_PRINTF_FORMAT(3, 4)
unsigned int uint
Definition: BLI_sys_types.h:83
#define snprintf
Definition: BLI_winstuff.h:69
CLG_Severity
Definition: CLG_log.h:99
@ CLG_SEVERITY_INFO
Definition: CLG_log.h:100
@ CLG_SEVERITY_WARN
Definition: CLG_log.h:101
@ CLG_SEVERITY_FATAL
Definition: CLG_log.h:103
@ CLG_SEVERITY_ERROR
Definition: CLG_log.h:102
@ CLG_FLAG_USE
Definition: CLG_log.h:96
#define CLG_SEVERITY_LEN
Definition: CLG_log.h:105
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE void * atomic_cas_ptr(void **v, void *old, void *_new)
static void CLG_ctx_output_set(CLogContext *ctx, void *file_handle)
Definition: clog.c:563
void CLG_type_filter_exclude(const char *type_match, int type_match_len)
Definition: clog.c:750
static void clg_ctx_fatal_action(CLogContext *ctx)
Definition: clog.c:378
void CLG_output_set(void *file_handle)
Definition: clog.c:720
static void CLG_ctx_free(CLogContext *ctx)
Definition: clog.c:667
void CLG_output_use_basename_set(int value)
Definition: clog.c:725
void CLG_exit(void)
Definition: clog.c:715
void CLG_error_fn_set(void(*error_fn)(void *file_handle))
Definition: clog.c:735
struct CLG_IDFilter CLG_IDFilter
static void clg_ctx_error_action(CLogContext *ctx)
Definition: clog.c:371
void CLG_backtrace_fn_set(void(*fatal_fn)(void *file_handle))
Definition: clog.c:745
static void CLG_ctx_output_use_timestamp_set(CLogContext *ctx, int value)
Definition: clog.c:594
static uint64_t clg_timestamp_ticks_get(void)
Definition: clog.c:396
static void clg_str_append_with_len(CLogStringBuf *cstr, const char *str, const uint len)
Definition: clog.c:168
struct CLogContext CLogContext
static void write_timestamp(CLogStringBuf *cstr, const uint64_t timestamp_tick_start)
Definition: clog.c:415
#define CLOG_BUF_LEN_INIT
Definition: clog.c:123
#define STREQLEN(a, b, n)
Definition: clog.c:63
void CLG_fatal_fn_set(void(*fatal_fn)(void *file_handle))
Definition: clog.c:740
static void clg_str_append(CLogStringBuf *cstr, const char *str)
Definition: clog.c:180
static const char * clg_color_table[COLOR_LEN]
Definition: clog.c:238
static void CLG_ctx_fatal_fn_set(CLogContext *ctx, void(*fatal_fn)(void *file_handle))
Definition: clog.c:609
void CLG_type_filter_include(const char *type_match, int type_match_len)
Definition: clog.c:755
void CLG_logref_init(CLG_LogRef *clg_ref)
Definition: clog.c:773
static void clg_ctx_type_filter_append(CLG_IDFilter **flt_list, const char *type_match, int type_match_len)
Definition: clog.c:619
void CLG_level_set(int level)
Definition: clog.c:760
static struct CLogContext * g_ctx
Definition: clog.c:706
static CLG_LogType * clg_ctx_type_register(CLogContext *ctx, const char *identifier)
Definition: clog.c:355
static CLogContext * CLG_ctx_init(void)
Definition: clog.c:655
struct CLogStringBuf CLogStringBuf
static void clg_str_free(CLogStringBuf *cstr)
Definition: clog.c:140
void CLG_output_use_timestamp_set(int value)
Definition: clog.c:730
static void CLG_ctx_output_use_basename_set(CLogContext *ctx, int value)
Definition: clog.c:589
void CLG_init(void)
Definition: clog.c:708
static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
Definition: clog.c:186
static void clg_str_init(CLogStringBuf *cstr, char *buf_stack, uint buf_stack_len)
Definition: clog.c:132
static void clg_ctx_backtrace(CLogContext *ctx)
Definition: clog.c:387
static void CLG_ctx_backtrace_fn_set(CLogContext *ctx, void(*backtrace_fn)(void *file_handle))
Definition: clog.c:614
#define PATHSEP_CHAR
Definition: clog.c:68
#define COLOR_LEN
Definition: clog.c:236
static const char * clg_severity_str[CLG_SEVERITY_LEN]
Definition: clog.c:257
static void clg_str_reserve(CLogStringBuf *cstr, const uint len)
Definition: clog.c:147
void CLG_logf(CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn, const char *fmt,...)
Definition: clog.c:510
static void CLG_ctx_type_filter_exclude(CLogContext *ctx, const char *type_match, int type_match_len)
Definition: clog.c:633
static void write_type(CLogStringBuf *cstr, CLG_LogType *lg)
Definition: clog.c:441
eCLogColor
Definition: clog.c:228
@ COLOR_DEFAULT
Definition: clog.c:229
@ COLOR_RED
Definition: clog.c:230
@ COLOR_YELLOW
Definition: clog.c:232
@ COLOR_GREEN
Definition: clog.c:231
@ COLOR_RESET
Definition: clog.c:234
static void clg_color_table_init(bool use_color)
Definition: clog.c:243
static void CLG_ctx_level_set(CLogContext *ctx, int level)
Definition: clog.c:647
int CLG_color_support_get(CLG_LogRef *clg_ref)
Definition: clog.c:799
void CLG_log_str(CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn, const char *message)
Definition: clog.c:472
static bool clg_ctx_filter_check(CLogContext *ctx, const char *identifier)
Definition: clog.c:312
static CLG_LogType * clg_ctx_type_find_by_name(CLogContext *ctx, const char *identifier)
Definition: clog.c:345
#define STREQ(a, b)
Definition: clog.c:62
static void CLG_ctx_type_filter_include(CLogContext *ctx, const char *type_match, int type_match_len)
Definition: clog.c:640
static const char * clg_severity_as_text(enum CLG_Severity severity)
Definition: clog.c:264
static enum eCLogColor clg_severity_to_color(enum CLG_Severity severity)
Definition: clog.c:276
static void write_severity(CLogStringBuf *cstr, enum CLG_Severity severity, bool use_color)
Definition: clog.c:427
static void CLT_ctx_error_fn_set(CLogContext *ctx, void(*error_fn)(void *file_handle))
Definition: clog.c:603
static void write_file_line_fn(CLogStringBuf *cstr, const char *file_line, const char *fn, const bool use_basename)
Definition: clog.c:448
#define str(s)
#define PRIu64
Definition: inttypes.h:135
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
unsigned __int64 uint64_t
Definition: stdint.h:93
char match[0]
Definition: clog.c:78
struct CLG_IDFilter * next
Definition: clog.c:76
const char * identifier
Definition: CLG_log.h:119
struct CLG_LogRef * next
Definition: CLG_log.h:121
CLG_LogType * type
Definition: CLG_log.h:120
char identifier[64]
Definition: CLG_log.h:110
struct CLG_LogType * next
Definition: CLG_log.h:109
enum CLG_LogFlag flag
Definition: CLG_log.h:115
struct CLogContext * ctx
Definition: CLG_log.h:112
int level
Definition: CLG_log.h:114
bool use_basename
Definition: clog.c:93
void(* fatal_fn)(void *file_handle)
Definition: clog.c:110
void(* error_fn)(void *file_handle)
Definition: clog.c:109
CLG_LogRef * refs
Definition: clog.c:85
struct CLogContext::@1185 callbacks
bool use_timestamp
Definition: clog.c:94
uint64_t timestamp_tick_start
Definition: clog.c:101
FILE * output_file
Definition: clog.c:98
int level
Definition: clog.c:105
int output
Definition: clog.c:97
struct CLogContext::@1184 default_type
void(* backtrace_fn)(void *file_handle)
Definition: clog.c:111
bool use_color
Definition: clog.c:92
CLG_IDFilter * filters[2]
Definition: clog.c:91
CLG_LogType * types
Definition: clog.c:83
bool is_alloc
Definition: clog.c:129
char * data
Definition: clog.c:126
uint len_alloc
Definition: clog.c:128
uint len
Definition: clog.c:127
uint len
uint len_alloc