Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024, 2025 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : #include "monetdb_config.h"
14 : #include "gdk.h"
15 : #include "gdk_private.h"
16 : #include "mutils.h"
17 :
18 : #define DEFAULT_ADAPTER TRC_NAME(BASIC)
19 : #define DEFAULT_LOG_LEVEL TRC_NAME(M_ERROR)
20 : #define DEFAULT_FLUSH_LEVEL TRC_NAME(M_DEBUG)
21 :
22 : #define FILE_NAME "mdbtrace.log"
23 :
24 : #define AS_STR(x) #x
25 : #define STR(x) AS_STR(x)
26 :
27 : #define GENERATE_STRING(STRING) #STRING,
28 :
29 : static FILE *active_tracer;
30 : MT_Lock GDKtracer_lock = MT_LOCK_INITIALIZER(GDKtracer_lock);
31 :
32 : static char *file_name;
33 :
34 : static ATOMIC_TYPE cur_adapter = ATOMIC_VAR_INIT(DEFAULT_ADAPTER);
35 :
36 : static log_level_t cur_flush_level = DEFAULT_FLUSH_LEVEL;
37 :
38 : static bool write_to_tracer = false;
39 :
40 : #define GENERATE_LOG_LEVEL(COMP) ATOMIC_VAR_INIT((ATOMIC_BASE_TYPE) DEFAULT_LOG_LEVEL),
41 : ATOMIC_TYPE lvl_per_component[] = {
42 : FOREACH_COMP(GENERATE_LOG_LEVEL)
43 : };
44 :
45 : static const char *adapter_str[] = {
46 : FOREACH_ADPTR(GENERATE_STRING)
47 : };
48 :
49 : static const char *layer_str[] = {
50 : FOREACH_LAYER(GENERATE_STRING)
51 : };
52 :
53 : static const char *component_str[] = {
54 : FOREACH_COMP(GENERATE_STRING)
55 : };
56 :
57 : static const char *level_str[] = {
58 : FOREACH_LEVEL(GENERATE_STRING)
59 : };
60 :
61 :
62 : #define MXW "20"
63 :
64 : #define TS_SIZE ((size_t) 20) /* buffer size needed for timestamp */
65 :
66 :
67 : /*
68 : * GDKtracer Stream Macros
69 : */
70 : // Exception
71 : #define GDK_TRACER_EXCEPTION(MSG) \
72 : fprintf(stderr, \
73 : "%s " \
74 : "%-"MXW"s " \
75 : "%"MXW"s:%d " \
76 : "%"MXW"s " \
77 : "%-"MXW"s " \
78 : "%-"MXW"s # "MSG, \
79 : get_timestamp((char[TS_SIZE]){0}, TS_SIZE), \
80 : __FILE__, \
81 : __func__, \
82 : __LINE__, \
83 : STR(M_CRITICAL), \
84 : STR(GDK_TRACER), \
85 : MT_thread_getname());
86 : #define GDK_TRACER_EXCEPTION2(MSG, ...) \
87 : fprintf(stderr, \
88 : "%s " \
89 : "%-"MXW"s " \
90 : "%"MXW"s:%d " \
91 : "%"MXW"s " \
92 : "%-"MXW"s " \
93 : "%-"MXW"s # "MSG, \
94 : get_timestamp((char[TS_SIZE]){0}, TS_SIZE), \
95 : __FILE__, \
96 : __func__, \
97 : __LINE__, \
98 : STR(M_CRITICAL), \
99 : STR(GDK_TRACER), \
100 : MT_thread_getname(), \
101 : __VA_ARGS__);
102 :
103 :
104 : #define GDK_TRACER_RESET_OUTPUT() \
105 : do { \
106 : write_to_tracer = false; \
107 : for (int i = 0; !write_to_tracer && i < (int) TRC_NAME(COMPONENTS_COUNT); i++) { \
108 : write_to_tracer = (log_level_t) ATOMIC_GET(&lvl_per_component[i]) > DEFAULT_LOG_LEVEL; \
109 : } \
110 : } while(0)
111 :
112 : static inline char *
113 333193 : get_timestamp(char *datetime, size_t dtsz)
114 : {
115 333193 : time_t now = time(NULL);
116 333347 : struct tm tmp;
117 333347 : (void) localtime_r(&now, &tmp);
118 333944 : strftime(datetime, dtsz, "%Y-%m-%d %H:%M:%S", &tmp);
119 :
120 333944 : return datetime;
121 : }
122 :
123 :
124 : // When BASIC adapter is active, all the log messages are getting printed to a file.
125 : // This function prepares a file in order to write the contents of the buffer when necessary.
126 : static gdk_return
127 709 : GDKtracer_init_trace_file(const char *dbpath, const char *dbtrace)
128 : {
129 709 : char *fn;
130 :
131 : /* we use malloc/free instead of GDKmalloc/GDKfree to avoid
132 : * possible recursion */
133 : #undef malloc
134 : #undef free
135 709 : if (dbtrace == NULL) {
136 709 : write_to_tracer = false;
137 709 : if (dbpath == NULL) {
138 350 : active_tracer = stderr;
139 350 : return GDK_SUCCEED;
140 : }
141 359 : size_t fnl = strlen(dbpath) + strlen(DIR_SEP_STR) + strlen(FILE_NAME) + 1;
142 359 : fn = malloc(fnl);
143 359 : if (fn == NULL) {
144 0 : GDK_TRACER_EXCEPTION("malloc failure\n");
145 0 : active_tracer = stderr;
146 0 : return GDK_FAIL;
147 : }
148 359 : if (strconcat_len(fn, fnl, dbpath, DIR_SEP_STR, FILE_NAME, NULL)
149 : >= fnl) {
150 : /* cannot happen */
151 0 : goto too_long;
152 : }
153 : } else {
154 0 : write_to_tracer = true;
155 0 : size_t fnl = strlen(dbtrace) + 1;
156 0 : fn = malloc(fnl);
157 0 : if (fn == NULL) {
158 0 : GDK_TRACER_EXCEPTION("malloc failure\n");
159 0 : active_tracer = stderr;
160 0 : return GDK_FAIL;
161 : }
162 0 : if (strcpy_len(fn, dbtrace, fnl)
163 : >= fnl) {
164 : /* cannot happen */
165 0 : goto too_long;
166 : }
167 : }
168 359 : free(file_name);
169 359 : file_name = fn;
170 :
171 359 : active_tracer = MT_fopen(file_name, "a");
172 :
173 359 : if (active_tracer == NULL) {
174 0 : GDK_TRACER_EXCEPTION2("Failed to open %s: %s\n", file_name,
175 0 : GDKstrerror(errno, (char[64]){0}, 64));
176 : /* uninitialize */
177 0 : free(file_name);
178 0 : file_name = NULL;
179 0 : active_tracer = stderr;
180 0 : return GDK_FAIL;
181 : }
182 :
183 : return GDK_SUCCEED;
184 :
185 0 : too_long:
186 0 : GDK_TRACER_EXCEPTION("path name for dbtrace file too long\n");
187 : /* uninitialize */
188 0 : free(fn);
189 0 : free(file_name);
190 0 : file_name = NULL;
191 0 : active_tracer = stderr;
192 0 : return GDK_FAIL;
193 : }
194 :
195 : static gdk_return
196 349 : _GDKtracer_init_basic_adptr(void)
197 : {
198 349 : return GDKtracer_init_trace_file(GDKgetenv("gdk_dbpath"),
199 : GDKgetenv("gdk_dbtrace"));
200 : }
201 :
202 : static void
203 356 : set_level_for_layer(int layer, log_level_t level)
204 : {
205 356 : const char *tok = NULL;
206 :
207 : // make sure we initialize before changing the component level
208 356 : MT_lock_set(&GDKtracer_lock);
209 356 : if (file_name == NULL) {
210 1 : _GDKtracer_init_basic_adptr();
211 : }
212 356 : MT_lock_unset(&GDKtracer_lock);
213 :
214 10680 : for (int i = 0; i < TRC_NAME(COMPONENTS_COUNT); i++) {
215 10324 : if (layer == TRC_NAME(MDB_ALL)) {
216 10324 : ATOMIC_SET(&lvl_per_component[i], (ATOMIC_BASE_TYPE) level);
217 : } else {
218 0 : tok = component_str[i];
219 :
220 0 : switch (layer) {
221 0 : case TRC_NAME(SQL_ALL):
222 0 : if (strncmp(tok, "SQL_", 4) == 0)
223 0 : ATOMIC_SET(&lvl_per_component[i], (ATOMIC_BASE_TYPE) level);
224 : break;
225 0 : case TRC_NAME(MAL_ALL):
226 0 : if (strncmp(tok, "MAL_", 4) == 0)
227 0 : ATOMIC_SET(&lvl_per_component[i], (ATOMIC_BASE_TYPE) level);
228 : break;
229 0 : case TRC_NAME(GDK_ALL):
230 0 : if (strncmp(tok, "GDK", 3) == 0)
231 0 : ATOMIC_SET(&lvl_per_component[i], (ATOMIC_BASE_TYPE) level);
232 : break;
233 : default:
234 : break;
235 : }
236 : }
237 : }
238 356 : MT_lock_set(&GDKtracer_lock);
239 10680 : GDK_TRACER_RESET_OUTPUT();
240 356 : MT_lock_unset(&GDKtracer_lock);
241 356 : }
242 :
243 : static inline adapter_t
244 1 : find_adapter(const char *adptr)
245 : {
246 1 : if (adptr == NULL)
247 : return TRC_NAME(ADAPTERS_COUNT);
248 :
249 3 : for (int i = 0; i < (int) TRC_NAME(ADAPTERS_COUNT); i++) {
250 3 : if (strcasecmp(adapter_str[i], adptr) == 0) {
251 1 : return (adapter_t) i;
252 : }
253 : }
254 : return TRC_NAME(ADAPTERS_COUNT);
255 : }
256 :
257 : static inline log_level_t
258 473 : find_level(const char *lvl)
259 : {
260 473 : if (lvl == NULL)
261 : return TRC_NAME(LOG_LEVELS_COUNT);
262 :
263 2246 : for (int i = 0; i < (int) TRC_NAME(LOG_LEVELS_COUNT); i++) {
264 2246 : if (strcasecmp(level_str[i] + 2, lvl) == 0) {
265 473 : return (log_level_t) i;
266 : }
267 : }
268 : return TRC_NAME(LOG_LEVELS_COUNT);
269 : }
270 :
271 : static inline layer_t
272 0 : find_layer(const char *layer)
273 : {
274 0 : if (layer == NULL)
275 : return TRC_NAME(LAYERS_COUNT);
276 0 : for (int i = 0; i < (int) TRC_NAME(LAYERS_COUNT); i++) {
277 0 : if (strcasecmp(layer_str[i], layer) == 0) {
278 0 : return (layer_t) i;
279 : }
280 : }
281 : return TRC_NAME(LAYERS_COUNT);
282 : }
283 :
284 : static inline component_t
285 5467 : find_component(const char *comp)
286 : {
287 : /* special case for the (currently) three components that end in _ */
288 5467 : if (comp == NULL || *comp == 0 || comp[strlen(comp) - 1] == '_')
289 : return TRC_NAME(COMPONENTS_COUNT);
290 :
291 49604 : for (int i = 0; i < (int) TRC_NAME(COMPONENTS_COUNT); i++) {
292 49604 : if (strcasecmp(component_str[i], comp) == 0) {
293 5467 : return (component_t) i;
294 : }
295 : }
296 : return TRC_NAME(COMPONENTS_COUNT);
297 : }
298 :
299 :
300 :
301 : /**
302 : *
303 : * API CALLS
304 : *
305 : */
306 : static volatile sig_atomic_t interrupted = 0;
307 :
308 : void
309 0 : GDKtracer_reinit_basic(int sig)
310 : {
311 0 : (void) sig;
312 0 : interrupted = 1;
313 0 : }
314 :
315 : static void
316 0 : reinit(void)
317 : {
318 : /* called locked */
319 :
320 0 : interrupted = 0;
321 :
322 : // GDKtracer needs to reopen the file only in
323 : // case the adapter is BASIC
324 0 : if ((adapter_t) ATOMIC_GET(&cur_adapter) != TRC_NAME(BASIC))
325 : return;
326 :
327 0 : if (active_tracer) {
328 0 : if (active_tracer != stderr)
329 0 : fclose(active_tracer);
330 : else
331 0 : fflush(active_tracer);
332 0 : active_tracer = NULL;
333 : }
334 0 : _GDKtracer_init_basic_adptr();
335 : }
336 :
337 :
338 : gdk_return
339 356 : GDKtracer_stop(void)
340 : {
341 356 : set_level_for_layer(TRC_NAME(MDB_ALL), DEFAULT_LOG_LEVEL);
342 356 : if (active_tracer) {
343 356 : if (active_tracer != stderr)
344 355 : fclose(active_tracer);
345 : else
346 1 : fflush(active_tracer);
347 356 : active_tracer = NULL;
348 : }
349 356 : return GDK_SUCCEED;
350 : }
351 :
352 : gdk_return
353 473 : GDKtracer_set_component_level(const char *comp, const char *lvl)
354 : {
355 473 : log_level_t level = find_level(lvl);
356 473 : component_t component = find_component(comp);
357 :
358 473 : if (level == TRC_NAME(LOG_LEVELS_COUNT)) {
359 0 : GDKerror("unknown level\n");
360 0 : return GDK_FAIL;
361 : }
362 473 : if (component == TRC_NAME(COMPONENTS_COUNT)) {
363 0 : GDKerror("unknown component\n");
364 0 : return GDK_FAIL;
365 : }
366 :
367 : // make sure we initialize before changing the component level
368 473 : MT_lock_set(&GDKtracer_lock);
369 473 : if (file_name == NULL) {
370 348 : _GDKtracer_init_basic_adptr();
371 : }
372 473 : write_to_tracer |= level > DEFAULT_LOG_LEVEL;
373 473 : MT_lock_unset(&GDKtracer_lock);
374 :
375 473 : ATOMIC_SET(&lvl_per_component[component], (ATOMIC_BASE_TYPE) level);
376 :
377 473 : return GDK_SUCCEED;
378 : }
379 :
380 : const char *
381 238 : GDKtracer_get_component_level(const char *comp)
382 : {
383 238 : component_t component = find_component(comp);
384 :
385 238 : if (component == TRC_NAME(COMPONENTS_COUNT)) {
386 0 : GDKerror("unknown component\n");
387 0 : return NULL;
388 : }
389 238 : return level_str[ATOMIC_GET(&lvl_per_component[component])];
390 : }
391 :
392 :
393 : gdk_return
394 4756 : GDKtracer_reset_component_level(const char *comp)
395 : {
396 4756 : component_t component = find_component(comp);
397 :
398 4756 : if (component == TRC_NAME(COMPONENTS_COUNT)) {
399 0 : GDKerror("unknown component\n");
400 0 : return GDK_FAIL;
401 : }
402 4756 : ATOMIC_SET(&lvl_per_component[component], (ATOMIC_BASE_TYPE) DEFAULT_LOG_LEVEL);
403 4756 : MT_lock_set(&GDKtracer_lock);
404 64426 : GDK_TRACER_RESET_OUTPUT();
405 4756 : MT_lock_unset(&GDKtracer_lock);
406 :
407 4756 : return GDK_SUCCEED;
408 : }
409 :
410 :
411 : gdk_return
412 0 : GDKtracer_set_layer_level(const char *layer, const char *lvl)
413 : {
414 0 : layer_t lyr = find_layer(layer);
415 0 : log_level_t level = find_level(lvl);
416 0 : if (level == TRC_NAME(LOG_LEVELS_COUNT)) {
417 0 : GDKerror("unknown level\n");
418 0 : return GDK_FAIL;
419 : }
420 0 : if (lyr == TRC_NAME(LAYERS_COUNT)) {
421 0 : GDKerror("unknown layer\n");
422 0 : return GDK_FAIL;
423 : }
424 :
425 0 : set_level_for_layer(lyr, level);
426 0 : return GDK_SUCCEED;
427 : }
428 :
429 :
430 : gdk_return
431 0 : GDKtracer_reset_layer_level(const char *layer)
432 : {
433 0 : layer_t lyr = find_layer(layer);
434 0 : if (lyr == TRC_NAME(LAYERS_COUNT)) {
435 0 : GDKerror("unknown layer\n");
436 0 : return GDK_FAIL;
437 : }
438 :
439 0 : set_level_for_layer(lyr, DEFAULT_LOG_LEVEL);
440 0 : return GDK_SUCCEED;
441 : }
442 :
443 :
444 : gdk_return
445 0 : GDKtracer_set_flush_level(const char *lvl)
446 : {
447 0 : log_level_t level = find_level(lvl);
448 0 : if (level == TRC_NAME(LOG_LEVELS_COUNT)) {
449 0 : GDKerror("unknown level\n");
450 0 : return GDK_FAIL;
451 : }
452 :
453 0 : cur_flush_level = level;
454 0 : return GDK_SUCCEED;
455 : }
456 :
457 :
458 : gdk_return
459 0 : GDKtracer_reset_flush_level(void)
460 : {
461 0 : cur_flush_level = DEFAULT_FLUSH_LEVEL;
462 0 : return GDK_SUCCEED;
463 : }
464 :
465 :
466 : gdk_return
467 1 : GDKtracer_set_adapter(const char *adapter)
468 : {
469 1 : adapter_t adptr = find_adapter(adapter);
470 1 : if (adptr == TRC_NAME(ADAPTERS_COUNT)) {
471 0 : GDKerror("unknown adapter\n");
472 0 : return GDK_FAIL;
473 : }
474 :
475 : // Here when switching between adapters we can open/close the file
476 : // But it is not so important to keep it open in case the adapter switches
477 : // From BASIC to other => close the file
478 : // From other to BASIC => open the file
479 :
480 1 : ATOMIC_SET(&cur_adapter, adptr);
481 :
482 1 : return GDK_SUCCEED;
483 : }
484 :
485 :
486 : gdk_return
487 0 : GDKtracer_reset_adapter(void)
488 : {
489 0 : ATOMIC_SET(&cur_adapter, DEFAULT_ADAPTER);
490 0 : return GDK_SUCCEED;
491 : }
492 :
493 : static bool add_ts; /* add timestamp to error message to stderr */
494 :
495 : gdk_return
496 360 : GDKtracer_init(const char *dbpath, const char *dbtrace)
497 : {
498 360 : MT_lock_set(&GDKtracer_lock);
499 : #ifdef _MSC_VER
500 : add_ts = GetFileType(GetStdHandle(STD_ERROR_HANDLE)) != FILE_TYPE_PIPE;
501 : #else
502 360 : add_ts = isatty(2) || lseek(2, 0, SEEK_CUR) != (off_t) -1 || errno != ESPIPE;
503 : #endif
504 360 : gdk_return rc = GDKtracer_init_trace_file(dbpath, dbtrace);
505 360 : MT_lock_unset(&GDKtracer_lock);
506 360 : return rc;
507 : }
508 :
509 : gdk_return
510 0 : GDKtracer_set_tracefile(const char *tracefile)
511 : {
512 0 : return GDKtracer_init(NULL, tracefile);
513 : }
514 :
515 : void
516 332866 : GDKtracer_log(const char *file, const char *func, int lineno,
517 : log_level_t level, component_t comp,
518 : const char *syserr,
519 : const char *fmt, ...)
520 : {
521 332866 : int bytes_written;
522 332866 : char buffer[512]; /* should be plenty big enough for a message */
523 332866 : va_list va;
524 332866 : char ts[TS_SIZE];
525 332866 : char *msg = NULL;
526 332866 : bool isexit;
527 332866 : static char file_prefix[] = __FILE__;
528 332866 : static size_t prefix_length = (size_t) -1;
529 :
530 332866 : if (prefix_length == (size_t) -1) {
531 : /* first time, calculate prefix of file name */
532 194 : msg = strstr(file_prefix, "gdk" DIR_SEP_STR "gdk_tracer.c");
533 194 : if (msg == NULL)
534 0 : prefix_length = 0;
535 : else
536 194 : prefix_length = (size_t) (msg - file_prefix);
537 : }
538 332866 : if (prefix_length != 0 &&
539 333223 : strncmp(file, file_prefix, prefix_length) == 0)
540 333109 : file += prefix_length;
541 :
542 332866 : va_start(va, fmt);
543 332866 : int pad = (int) strlen(file);
544 332866 : pad = (pad > 40) ? 0 : 40 - pad;
545 332866 : bytes_written = snprintf(buffer, sizeof(buffer),
546 : "%s " /* timestamp */
547 : "%10s " /* level */
548 : "%-8s " /* component */
549 : "%-20s " /* thread name */
550 : "%s:%-5d %*s" /* file, lineno, pad */
551 : "%-20s ", /* function */
552 : get_timestamp(ts, sizeof(ts)),
553 : level_str[level],
554 : component_str[comp],
555 : MT_thread_getname(),
556 : file, lineno, pad, "",
557 : func);
558 333342 : if (bytes_written > 0 && bytes_written < (int) sizeof(buffer)) {
559 333580 : msg = buffer + bytes_written;
560 : } else {
561 : /* exceedingly unlikely that we ever come here */
562 : msg = buffer;
563 : bytes_written = 0;
564 : }
565 333342 : bytes_written = vsnprintf(msg,
566 : sizeof(buffer) - bytes_written,
567 : fmt, va);
568 333342 : isexit = strstr(msg, EXITING_MSG) != NULL;
569 333342 : va_end(va);
570 333342 : if (bytes_written < 0) {
571 0 : if ((adapter_t) ATOMIC_GET(&cur_adapter) != TRC_NAME(MBEDDED))
572 0 : GDK_TRACER_EXCEPTION("Failed to write logs\n");
573 12493 : return;
574 : }
575 333342 : char *p;
576 333342 : if ((p = strchr(buffer, '\n')) != NULL)
577 197321 : *p = '\0';
578 :
579 333342 : if (level <= TRC_NAME(M_ERROR) && (comp == TRC_NAME(GDK) || comp == TRC_NAME(GEOM))) {
580 : /* append message to GDKerrbuf (if set) */
581 1601 : char *buf = GDKerrbuf;
582 1601 : if (buf) {
583 1599 : size_t n = strlen(buf);
584 4797 : snprintf(buf + n, GDKMAXERRLEN - n,
585 : "%s%s: %s%s%s\n",
586 : isexit ? "" : GDKERROR,
587 : func, msg,
588 : syserr ? ": " : "",
589 : syserr ? syserr : "");
590 : }
591 : }
592 :
593 : /* don't write to file in embedded case, but set the GDK error buffer */
594 333342 : if ((adapter_t) ATOMIC_GET(&cur_adapter) == TRC_NAME(MBEDDED))
595 : return;
596 :
597 333146 : MT_lock_set(&GDKtracer_lock);
598 333951 : if (interrupted)
599 0 : reinit();
600 :
601 333951 : if (level <= TRC_NAME(M_WARNING) || (ATOMIC_GET(&GDKdebug) & TESTINGMASK)) {
602 677418 : fprintf(level <= TRC_NAME(M_ERROR) && !isexit ? stderr : stdout,
603 : "#%s%s%s: %s: %s: %s%s%s\n",
604 : add_ts ? ts : "",
605 333756 : add_ts ? ": " : "",
606 333756 : MT_thread_getname(), func, level_str[level] + 2,
607 : msg, syserr ? ": " : "",
608 : syserr ? syserr : "");
609 333756 : if (active_tracer == NULL || active_tracer == stderr || !write_to_tracer) {
610 12297 : MT_lock_unset(&GDKtracer_lock);
611 12297 : return;
612 : }
613 : }
614 321654 : if (active_tracer == NULL) {
615 0 : MT_lock_unset(&GDKtracer_lock);
616 0 : return;
617 : }
618 321654 : if (syserr)
619 0 : fprintf(active_tracer, "%s: %s\n", buffer, syserr);
620 : else
621 321654 : fprintf(active_tracer, "%s\n", buffer);
622 :
623 : // Flush the current buffer in case the event is
624 : // important depending on the flush-level
625 : // Always flush CRITICAL and ERROR messages - prevent cases
626 : // like mserver5 refusing to start due to allocated port
627 : // and the error is never reported to the user because it
628 : // is still in the buffer which it never gets flushed.
629 321654 : if (level == cur_flush_level || level <= TRC_NAME(M_ERROR))
630 41171 : fflush(active_tracer);
631 321654 : MT_lock_unset(&GDKtracer_lock);
632 : }
633 :
634 :
635 : gdk_return
636 0 : GDKtracer_flush_buffer(void)
637 : {
638 0 : if (active_tracer)
639 0 : fflush(active_tracer);
640 0 : return GDK_SUCCEED;
641 : }
642 :
643 :
644 : gdk_return
645 0 : GDKtracer_fill_comp_info(BAT *id, BAT *component, BAT *log_level)
646 : {
647 0 : for (int i = 0; i < TRC_NAME(COMPONENTS_COUNT); i++) {
648 0 : if (BUNappend(id, &i, false) != GDK_SUCCEED)
649 0 : return GDK_FAIL;
650 :
651 0 : if (BUNappend(component, component_str[i], false) != GDK_SUCCEED)
652 : return GDK_FAIL;
653 :
654 0 : if (BUNappend(log_level, level_str[ATOMIC_GET(&lvl_per_component[i])], false) != GDK_SUCCEED)
655 : return GDK_FAIL;
656 : }
657 :
658 0 : return GDK_SUCCEED;
659 : }
|