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