clog.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  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. /** \file
  17. * \ingroup clog
  18. */
  19. #include <stdarg.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <stdint.h>
  23. #include <assert.h>
  24. /* Disable for small single threaded programs
  25. * to avoid having to link with pthreads. */
  26. #ifdef WITH_CLOG_PTHREADS
  27. # include <pthread.h>
  28. # include "atomic_ops.h"
  29. #endif
  30. /* For 'isatty' to check for color. */
  31. #if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
  32. # include <unistd.h>
  33. # include <sys/time.h>
  34. #endif
  35. #if defined(_MSC_VER)
  36. # include <io.h>
  37. # include <windows.h>
  38. #endif
  39. /* For printing timestamp. */
  40. #define __STDC_FORMAT_MACROS
  41. #include <inttypes.h>
  42. /* Only other dependency (could use regular malloc too). */
  43. #include "MEM_guardedalloc.h"
  44. /* own include. */
  45. #include "CLG_log.h"
  46. /* Local utility defines */
  47. #define STREQ(a, b) (strcmp(a, b) == 0)
  48. #define STREQLEN(a, b, n) (strncmp(a, b, n) == 0)
  49. #ifdef _WIN32
  50. # define PATHSEP_CHAR '\\'
  51. #else
  52. # define PATHSEP_CHAR '/'
  53. #endif
  54. /* -------------------------------------------------------------------- */
  55. /** \name Internal Types
  56. * \{ */
  57. typedef struct CLG_IDFilter {
  58. struct CLG_IDFilter *next;
  59. /** Over alloc. */
  60. char match[0];
  61. } CLG_IDFilter;
  62. typedef struct CLogContext {
  63. /** Single linked list of types. */
  64. CLG_LogType *types;
  65. #ifdef WITH_CLOG_PTHREADS
  66. pthread_mutex_t types_lock;
  67. #endif
  68. /* exclude, include filters. */
  69. CLG_IDFilter *filters[2];
  70. bool use_color;
  71. bool use_basename;
  72. bool use_timestamp;
  73. /** Borrowed, not owned. */
  74. int output;
  75. FILE *output_file;
  76. /** For timer (use_timestamp). */
  77. uint64_t timestamp_tick_start;
  78. /** For new types. */
  79. struct {
  80. int level;
  81. } default_type;
  82. struct {
  83. void (*fatal_fn)(void *file_handle);
  84. void (*backtrace_fn)(void *file_handle);
  85. } callbacks;
  86. } CLogContext;
  87. /** \} */
  88. /* -------------------------------------------------------------------- */
  89. /** \name Mini Buffer Functionality
  90. *
  91. * Use so we can do a single call to write.
  92. * \{ */
  93. #define CLOG_BUF_LEN_INIT 512
  94. typedef struct CLogStringBuf {
  95. char *data;
  96. uint len;
  97. uint len_alloc;
  98. bool is_alloc;
  99. } CLogStringBuf;
  100. static void clg_str_init(CLogStringBuf *cstr, char *buf_stack, uint buf_stack_len)
  101. {
  102. cstr->data = buf_stack;
  103. cstr->len_alloc = buf_stack_len;
  104. cstr->len = 0;
  105. cstr->is_alloc = false;
  106. }
  107. static void clg_str_free(CLogStringBuf *cstr)
  108. {
  109. if (cstr->is_alloc) {
  110. MEM_freeN(cstr->data);
  111. }
  112. }
  113. static void clg_str_reserve(CLogStringBuf *cstr, const uint len)
  114. {
  115. if (len > cstr->len_alloc) {
  116. cstr->len_alloc *= 2;
  117. if (len > cstr->len_alloc) {
  118. cstr->len_alloc = len;
  119. }
  120. if (cstr->is_alloc) {
  121. cstr->data = MEM_reallocN(cstr->data, cstr->len_alloc);
  122. }
  123. else {
  124. /* Copy the static buffer. */
  125. char *data = MEM_mallocN(cstr->len_alloc, __func__);
  126. memcpy(data, cstr->data, cstr->len);
  127. cstr->data = data;
  128. cstr->is_alloc = true;
  129. }
  130. cstr->len_alloc = len;
  131. }
  132. }
  133. static void clg_str_append_with_len(CLogStringBuf *cstr, const char *str, const uint len)
  134. {
  135. uint len_next = cstr->len + len;
  136. clg_str_reserve(cstr, len_next);
  137. char *str_dst = cstr->data + cstr->len;
  138. memcpy(str_dst, str, len);
  139. #if 0 /* no need. */
  140. str_dst[len] = '\0';
  141. #endif
  142. cstr->len = len_next;
  143. }
  144. static void clg_str_append(CLogStringBuf *cstr, const char *str)
  145. {
  146. clg_str_append_with_len(cstr, str, strlen(str));
  147. }
  148. static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
  149. {
  150. /* Use limit because windows may use '-1' for a formatting error. */
  151. const uint len_max = 65535;
  152. uint len_avail = (cstr->len_alloc - cstr->len);
  153. if (len_avail == 0) {
  154. len_avail = CLOG_BUF_LEN_INIT;
  155. clg_str_reserve(cstr, len_avail);
  156. }
  157. while (true) {
  158. va_list args_cpy;
  159. va_copy(args_cpy, args);
  160. int retval = vsnprintf(cstr->data + cstr->len, len_avail, fmt, args_cpy);
  161. va_end(args_cpy);
  162. if (retval != -1) {
  163. cstr->len += retval;
  164. break;
  165. }
  166. else {
  167. len_avail *= 2;
  168. if (len_avail >= len_max) {
  169. break;
  170. }
  171. clg_str_reserve(cstr, len_avail);
  172. }
  173. }
  174. }
  175. /** \} */
  176. /* -------------------------------------------------------------------- */
  177. /** \name Internal Utilities
  178. * \{ */
  179. enum eCLogColor {
  180. COLOR_DEFAULT,
  181. COLOR_RED,
  182. COLOR_GREEN,
  183. COLOR_YELLOW,
  184. COLOR_RESET,
  185. };
  186. #define COLOR_LEN (COLOR_RESET + 1)
  187. static const char *clg_color_table[COLOR_LEN] = {NULL};
  188. static void clg_color_table_init(bool use_color)
  189. {
  190. for (int i = 0; i < COLOR_LEN; i++) {
  191. clg_color_table[i] = "";
  192. }
  193. if (use_color) {
  194. #ifdef _WIN32
  195. /* TODO */
  196. #else
  197. clg_color_table[COLOR_DEFAULT] = "\033[1;37m";
  198. clg_color_table[COLOR_RED] = "\033[1;31m";
  199. clg_color_table[COLOR_GREEN] = "\033[1;32m";
  200. clg_color_table[COLOR_YELLOW] = "\033[1;33m";
  201. clg_color_table[COLOR_RESET] = "\033[0m";
  202. #endif
  203. }
  204. }
  205. static const char *clg_severity_str[CLG_SEVERITY_LEN] = {
  206. [CLG_SEVERITY_INFO] = "INFO",
  207. [CLG_SEVERITY_WARN] = "WARN",
  208. [CLG_SEVERITY_ERROR] = "ERROR",
  209. [CLG_SEVERITY_FATAL] = "FATAL",
  210. };
  211. static const char *clg_severity_as_text(enum CLG_Severity severity)
  212. {
  213. bool ok = (unsigned int)severity < CLG_SEVERITY_LEN;
  214. assert(ok);
  215. if (ok) {
  216. return clg_severity_str[severity];
  217. }
  218. else {
  219. return "INVALID_SEVERITY";
  220. }
  221. }
  222. static enum eCLogColor clg_severity_to_color(enum CLG_Severity severity)
  223. {
  224. assert((unsigned int)severity < CLG_SEVERITY_LEN);
  225. enum eCLogColor color = COLOR_DEFAULT;
  226. switch (severity) {
  227. case CLG_SEVERITY_INFO:
  228. color = COLOR_DEFAULT;
  229. break;
  230. case CLG_SEVERITY_WARN:
  231. color = COLOR_YELLOW;
  232. break;
  233. case CLG_SEVERITY_ERROR:
  234. case CLG_SEVERITY_FATAL:
  235. color = COLOR_RED;
  236. break;
  237. default:
  238. /* should never get here. */
  239. assert(false);
  240. }
  241. return color;
  242. }
  243. /** \} */
  244. /* -------------------------------------------------------------------- */
  245. /** \name Context Type Access
  246. * \{ */
  247. /**
  248. * Filter the indentifier based on very basic globbing.
  249. * - `foo` exact match of `foo`.
  250. * - `foo.bar` exact match for `foo.bar`
  251. * - `foo.*` match for `foo` & `foo.bar` & `foo.bar.baz`
  252. * - `*` matches everything.
  253. */
  254. static bool clg_ctx_filter_check(CLogContext *ctx, const char *identifier)
  255. {
  256. const int identifier_len = strlen(identifier);
  257. for (uint i = 0; i < 2; i++) {
  258. const CLG_IDFilter *flt = ctx->filters[i];
  259. while (flt != NULL) {
  260. const int len = strlen(flt->match);
  261. if (STREQ(flt->match, "*") || ((len == identifier_len) && (STREQ(identifier, flt->match)))) {
  262. return (bool)i;
  263. }
  264. if ((len >= 2) && (STREQLEN(".*", &flt->match[len - 2], 2))) {
  265. if (((identifier_len == len - 2) && STREQLEN(identifier, flt->match, len - 2)) ||
  266. ((identifier_len >= len - 1) && STREQLEN(identifier, flt->match, len - 1))) {
  267. return (bool)i;
  268. }
  269. }
  270. flt = flt->next;
  271. }
  272. }
  273. return false;
  274. }
  275. /**
  276. * \note This should never be called per logging call.
  277. * Searching is only to get an initial handle.
  278. */
  279. static CLG_LogType *clg_ctx_type_find_by_name(CLogContext *ctx, const char *identifier)
  280. {
  281. for (CLG_LogType *ty = ctx->types; ty; ty = ty->next) {
  282. if (STREQ(identifier, ty->identifier)) {
  283. return ty;
  284. }
  285. }
  286. return NULL;
  287. }
  288. static CLG_LogType *clg_ctx_type_register(CLogContext *ctx, const char *identifier)
  289. {
  290. assert(clg_ctx_type_find_by_name(ctx, identifier) == NULL);
  291. CLG_LogType *ty = MEM_callocN(sizeof(*ty), __func__);
  292. ty->next = ctx->types;
  293. ctx->types = ty;
  294. strncpy(ty->identifier, identifier, sizeof(ty->identifier) - 1);
  295. ty->ctx = ctx;
  296. ty->level = ctx->default_type.level;
  297. if (clg_ctx_filter_check(ctx, ty->identifier)) {
  298. ty->flag |= CLG_FLAG_USE;
  299. }
  300. return ty;
  301. }
  302. static void clg_ctx_fatal_action(CLogContext *ctx)
  303. {
  304. if (ctx->callbacks.fatal_fn != NULL) {
  305. ctx->callbacks.fatal_fn(ctx->output_file);
  306. }
  307. fflush(ctx->output_file);
  308. abort();
  309. }
  310. static void clg_ctx_backtrace(CLogContext *ctx)
  311. {
  312. /* Note: we avoid writing fo 'FILE', for backtrace we make an exception,
  313. * if necessary we could have a version of the callback that writes to file
  314. * descriptor all at once. */
  315. ctx->callbacks.backtrace_fn(ctx->output_file);
  316. fflush(ctx->output_file);
  317. }
  318. static uint64_t clg_timestamp_ticks_get(void)
  319. {
  320. uint64_t tick;
  321. #if defined(_MSC_VER)
  322. tick = GetTickCount64();
  323. #else
  324. struct timeval tv;
  325. gettimeofday(&tv, NULL);
  326. tick = tv.tv_sec * 1000 + tv.tv_usec / 1000;
  327. #endif
  328. return tick;
  329. }
  330. /** \} */
  331. /* -------------------------------------------------------------------- */
  332. /** \name Logging API
  333. * \{ */
  334. static void write_timestamp(CLogStringBuf *cstr, const uint64_t timestamp_tick_start)
  335. {
  336. char timestamp_str[64];
  337. const uint64_t timestamp = clg_timestamp_ticks_get() - timestamp_tick_start;
  338. const uint timestamp_len = snprintf(timestamp_str,
  339. sizeof(timestamp_str),
  340. "%" PRIu64 ".%03u ",
  341. timestamp / 1000,
  342. (uint)(timestamp % 1000));
  343. clg_str_append_with_len(cstr, timestamp_str, timestamp_len);
  344. }
  345. static void write_severity(CLogStringBuf *cstr, enum CLG_Severity severity, bool use_color)
  346. {
  347. assert((unsigned int)severity < CLG_SEVERITY_LEN);
  348. if (use_color) {
  349. enum eCLogColor color = clg_severity_to_color(severity);
  350. clg_str_append(cstr, clg_color_table[color]);
  351. clg_str_append(cstr, clg_severity_as_text(severity));
  352. clg_str_append(cstr, clg_color_table[COLOR_RESET]);
  353. }
  354. else {
  355. clg_str_append(cstr, clg_severity_as_text(severity));
  356. }
  357. }
  358. static void write_type(CLogStringBuf *cstr, CLG_LogType *lg)
  359. {
  360. clg_str_append(cstr, " (");
  361. clg_str_append(cstr, lg->identifier);
  362. clg_str_append(cstr, "): ");
  363. }
  364. static void write_file_line_fn(CLogStringBuf *cstr,
  365. const char *file_line,
  366. const char *fn,
  367. const bool use_basename)
  368. {
  369. uint file_line_len = strlen(file_line);
  370. if (use_basename) {
  371. uint file_line_offset = file_line_len;
  372. while (file_line_offset-- > 0) {
  373. if (file_line[file_line_offset] == PATHSEP_CHAR) {
  374. file_line_offset++;
  375. break;
  376. }
  377. }
  378. file_line += file_line_offset;
  379. file_line_len -= file_line_offset;
  380. }
  381. clg_str_append_with_len(cstr, file_line, file_line_len);
  382. clg_str_append(cstr, " ");
  383. clg_str_append(cstr, fn);
  384. clg_str_append(cstr, ": ");
  385. }
  386. void CLG_log_str(CLG_LogType *lg,
  387. enum CLG_Severity severity,
  388. const char *file_line,
  389. const char *fn,
  390. const char *message)
  391. {
  392. CLogStringBuf cstr;
  393. char cstr_stack_buf[CLOG_BUF_LEN_INIT];
  394. clg_str_init(&cstr, cstr_stack_buf, sizeof(cstr_stack_buf));
  395. if (lg->ctx->use_timestamp) {
  396. write_timestamp(&cstr, lg->ctx->timestamp_tick_start);
  397. }
  398. write_severity(&cstr, severity, lg->ctx->use_color);
  399. write_type(&cstr, lg);
  400. {
  401. write_file_line_fn(&cstr, file_line, fn, lg->ctx->use_basename);
  402. clg_str_append(&cstr, message);
  403. }
  404. clg_str_append(&cstr, "\n");
  405. /* could be optional */
  406. int bytes_written = write(lg->ctx->output, cstr.data, cstr.len);
  407. (void)bytes_written;
  408. clg_str_free(&cstr);
  409. if (lg->ctx->callbacks.backtrace_fn) {
  410. clg_ctx_backtrace(lg->ctx);
  411. }
  412. if (severity == CLG_SEVERITY_FATAL) {
  413. clg_ctx_fatal_action(lg->ctx);
  414. }
  415. }
  416. void CLG_logf(CLG_LogType *lg,
  417. enum CLG_Severity severity,
  418. const char *file_line,
  419. const char *fn,
  420. const char *fmt,
  421. ...)
  422. {
  423. CLogStringBuf cstr;
  424. char cstr_stack_buf[CLOG_BUF_LEN_INIT];
  425. clg_str_init(&cstr, cstr_stack_buf, sizeof(cstr_stack_buf));
  426. if (lg->ctx->use_timestamp) {
  427. write_timestamp(&cstr, lg->ctx->timestamp_tick_start);
  428. }
  429. write_severity(&cstr, severity, lg->ctx->use_color);
  430. write_type(&cstr, lg);
  431. {
  432. write_file_line_fn(&cstr, file_line, fn, lg->ctx->use_basename);
  433. va_list ap;
  434. va_start(ap, fmt);
  435. clg_str_vappendf(&cstr, fmt, ap);
  436. va_end(ap);
  437. }
  438. clg_str_append(&cstr, "\n");
  439. /* could be optional */
  440. int bytes_written = write(lg->ctx->output, cstr.data, cstr.len);
  441. (void)bytes_written;
  442. clg_str_free(&cstr);
  443. if (lg->ctx->callbacks.backtrace_fn) {
  444. clg_ctx_backtrace(lg->ctx);
  445. }
  446. if (severity == CLG_SEVERITY_FATAL) {
  447. clg_ctx_fatal_action(lg->ctx);
  448. }
  449. }
  450. /** \} */
  451. /* -------------------------------------------------------------------- */
  452. /** \name Logging Context API
  453. * \{ */
  454. static void CLG_ctx_output_set(CLogContext *ctx, void *file_handle)
  455. {
  456. ctx->output_file = file_handle;
  457. ctx->output = fileno(ctx->output_file);
  458. #if defined(__unix__) || defined(__APPLE__)
  459. ctx->use_color = isatty(ctx->output);
  460. #endif
  461. }
  462. static void CLG_ctx_output_use_basename_set(CLogContext *ctx, int value)
  463. {
  464. ctx->use_basename = (bool)value;
  465. }
  466. static void CLG_ctx_output_use_timestamp_set(CLogContext *ctx, int value)
  467. {
  468. ctx->use_timestamp = (bool)value;
  469. if (ctx->use_timestamp) {
  470. ctx->timestamp_tick_start = clg_timestamp_ticks_get();
  471. }
  472. }
  473. /** Action on fatal severity. */
  474. static void CLG_ctx_fatal_fn_set(CLogContext *ctx, void (*fatal_fn)(void *file_handle))
  475. {
  476. ctx->callbacks.fatal_fn = fatal_fn;
  477. }
  478. static void CLG_ctx_backtrace_fn_set(CLogContext *ctx, void (*backtrace_fn)(void *file_handle))
  479. {
  480. ctx->callbacks.backtrace_fn = backtrace_fn;
  481. }
  482. static void clg_ctx_type_filter_append(CLG_IDFilter **flt_list,
  483. const char *type_match,
  484. int type_match_len)
  485. {
  486. if (type_match_len == 0) {
  487. return;
  488. }
  489. CLG_IDFilter *flt = MEM_callocN(sizeof(*flt) + (type_match_len + 1), __func__);
  490. flt->next = *flt_list;
  491. *flt_list = flt;
  492. memcpy(flt->match, type_match, type_match_len);
  493. /* no need to null terminate since we calloc'd */
  494. }
  495. static void CLG_ctx_type_filter_exclude(CLogContext *ctx,
  496. const char *type_match,
  497. int type_match_len)
  498. {
  499. clg_ctx_type_filter_append(&ctx->filters[0], type_match, type_match_len);
  500. }
  501. static void CLG_ctx_type_filter_include(CLogContext *ctx,
  502. const char *type_match,
  503. int type_match_len)
  504. {
  505. clg_ctx_type_filter_append(&ctx->filters[1], type_match, type_match_len);
  506. }
  507. static void CLG_ctx_level_set(CLogContext *ctx, int level)
  508. {
  509. ctx->default_type.level = level;
  510. for (CLG_LogType *ty = ctx->types; ty; ty = ty->next) {
  511. ty->level = level;
  512. }
  513. }
  514. static CLogContext *CLG_ctx_init(void)
  515. {
  516. CLogContext *ctx = MEM_callocN(sizeof(*ctx), __func__);
  517. #ifdef WITH_CLOG_PTHREADS
  518. pthread_mutex_init(&ctx->types_lock, NULL);
  519. #endif
  520. ctx->use_color = true;
  521. ctx->default_type.level = 1;
  522. CLG_ctx_output_set(ctx, stdout);
  523. return ctx;
  524. }
  525. static void CLG_ctx_free(CLogContext *ctx)
  526. {
  527. while (ctx->types != NULL) {
  528. CLG_LogType *item = ctx->types;
  529. ctx->types = item->next;
  530. MEM_freeN(item);
  531. }
  532. for (uint i = 0; i < 2; i++) {
  533. while (ctx->filters[i] != NULL) {
  534. CLG_IDFilter *item = ctx->filters[i];
  535. ctx->filters[i] = item->next;
  536. MEM_freeN(item);
  537. }
  538. }
  539. #ifdef WITH_CLOG_PTHREADS
  540. pthread_mutex_destroy(&ctx->types_lock);
  541. #endif
  542. MEM_freeN(ctx);
  543. }
  544. /** \} */
  545. /* -------------------------------------------------------------------- */
  546. /** \name Public Logging API
  547. *
  548. * Currently uses global context.
  549. * \{ */
  550. /* We could support multiple at once, for now this seems not needed. */
  551. static struct CLogContext *g_ctx = NULL;
  552. void CLG_init(void)
  553. {
  554. g_ctx = CLG_ctx_init();
  555. clg_color_table_init(g_ctx->use_color);
  556. }
  557. void CLG_exit(void)
  558. {
  559. CLG_ctx_free(g_ctx);
  560. }
  561. void CLG_output_set(void *file_handle)
  562. {
  563. CLG_ctx_output_set(g_ctx, file_handle);
  564. }
  565. void CLG_output_use_basename_set(int value)
  566. {
  567. CLG_ctx_output_use_basename_set(g_ctx, value);
  568. }
  569. void CLG_output_use_timestamp_set(int value)
  570. {
  571. CLG_ctx_output_use_timestamp_set(g_ctx, value);
  572. }
  573. void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle))
  574. {
  575. CLG_ctx_fatal_fn_set(g_ctx, fatal_fn);
  576. }
  577. void CLG_backtrace_fn_set(void (*fatal_fn)(void *file_handle))
  578. {
  579. CLG_ctx_backtrace_fn_set(g_ctx, fatal_fn);
  580. }
  581. void CLG_type_filter_exclude(const char *type_match, int type_match_len)
  582. {
  583. CLG_ctx_type_filter_exclude(g_ctx, type_match, type_match_len);
  584. }
  585. void CLG_type_filter_include(const char *type_match, int type_match_len)
  586. {
  587. CLG_ctx_type_filter_include(g_ctx, type_match, type_match_len);
  588. }
  589. void CLG_level_set(int level)
  590. {
  591. CLG_ctx_level_set(g_ctx, level);
  592. }
  593. /** \} */
  594. /* -------------------------------------------------------------------- */
  595. /** \name Logging Reference API
  596. * Use to avoid lookups each time.
  597. * \{ */
  598. void CLG_logref_init(CLG_LogRef *clg_ref)
  599. {
  600. #ifdef WITH_CLOG_PTHREADS
  601. /* Only runs once when initializing a static type in most cases. */
  602. pthread_mutex_lock(&g_ctx->types_lock);
  603. #endif
  604. if (clg_ref->type == NULL) {
  605. CLG_LogType *clg_ty = clg_ctx_type_find_by_name(g_ctx, clg_ref->identifier);
  606. if (clg_ty == NULL) {
  607. clg_ty = clg_ctx_type_register(g_ctx, clg_ref->identifier);
  608. }
  609. #ifdef WITH_CLOG_PTHREADS
  610. atomic_cas_ptr((void **)&clg_ref->type, clg_ref->type, clg_ty);
  611. #else
  612. clg_ref->type = clg_ty;
  613. #endif
  614. }
  615. #ifdef WITH_CLOG_PTHREADS
  616. pthread_mutex_unlock(&g_ctx->types_lock);
  617. #endif
  618. }
  619. /** \} */