blob: b842cbd98bb768c2c5d1a54399500d540a886c58 [file] [log] [blame]
Radek Krejci5aeea3a2018-09-05 13:29:36 +02001/**
2 * @file log.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Logger routines implementations
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Christian Hopps32874e12021-05-01 09:43:54 -040015#define _GNU_SOURCE /* asprintf, strdup */
16#include <sys/cdefs.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020017
18#include "log.h"
Radek Krejcib7db73a2018-10-24 14:18:40 +020019
Radek Krejci5aeea3a2018-09-05 13:29:36 +020020#include <assert.h>
Radek Krejcic04f0a22018-09-21 15:49:45 +020021#include <inttypes.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include <pthread.h>
Radek Krejci5aeea3a2018-09-05 13:29:36 +020023#include <stdarg.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include <stdint.h>
Radek Krejci5aeea3a2018-09-05 13:29:36 +020025#include <stdio.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include <stdlib.h>
27#include <string.h>
Radek Krejci5aeea3a2018-09-05 13:29:36 +020028
Radek Krejci535ea9f2020-05-29 16:01:05 +020029#include "common.h"
Radek Krejciaa45bda2020-07-20 07:43:38 +020030#include "compat.h"
Radek Krejciaddfc9a2020-12-17 20:46:35 +010031#include "in_internal.h"
Radek Krejci0935f412019-08-20 16:15:18 +020032#include "plugins_exts.h"
Radek Krejci77114102021-03-10 15:21:57 +010033#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020034#include "tree_data.h"
35#include "tree_schema.h"
Radek Krejci5aeea3a2018-09-05 13:29:36 +020036
Radek Krejci52b6d512020-10-12 12:33:17 +020037volatile LY_LOG_LEVEL ly_ll = LY_LLWRN;
Radek Krejci1deb5be2020-08-26 16:43:36 +020038volatile uint32_t ly_log_opts = LY_LOLOG | LY_LOSTORE_LAST;
Michal Vaskod8085612020-08-21 12:55:23 +020039static ly_log_clb log_clb;
Radek Krejci857189e2020-09-01 13:26:36 +020040static volatile ly_bool path_flag = 1;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020041#ifndef NDEBUG
Radek Krejci68433c92020-10-12 17:03:55 +020042volatile uint32_t ly_ldbg_groups = 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020043#endif
44
Radek Krejciddace2c2021-01-08 11:30:56 +010045THREAD_LOCAL struct ly_log_location_s log_location = {0};
46
Radek Krejci94aa9942018-09-07 17:12:17 +020047/* how many bytes add when enlarging buffers */
48#define LY_BUF_STEP 128
49
Radek Krejcid33273d2018-10-25 14:55:52 +020050API LY_ERR
51ly_errcode(const struct ly_ctx *ctx)
52{
53 struct ly_err_item *i;
54
Radek Krejci572ee602020-09-16 14:35:08 +020055 i = ly_err_last(ctx);
Radek Krejcid33273d2018-10-25 14:55:52 +020056 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020057 return i->no;
Radek Krejcid33273d2018-10-25 14:55:52 +020058 }
59
60 return LY_SUCCESS;
61}
62
Radek Krejci5aeea3a2018-09-05 13:29:36 +020063API LY_VECODE
64ly_vecode(const struct ly_ctx *ctx)
65{
66 struct ly_err_item *i;
67
Radek Krejci572ee602020-09-16 14:35:08 +020068 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020069 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020070 return i->vecode;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020071 }
72
73 return LYVE_SUCCESS;
74}
75
76API const char *
77ly_errmsg(const struct ly_ctx *ctx)
78{
79 struct ly_err_item *i;
80
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020081 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020082
Radek Krejci572ee602020-09-16 14:35:08 +020083 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020084 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020085 return i->msg;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020086 }
87
88 return NULL;
89}
90
91API const char *
92ly_errpath(const struct ly_ctx *ctx)
93{
94 struct ly_err_item *i;
95
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020096 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020097
Radek Krejci572ee602020-09-16 14:35:08 +020098 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020099 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +0200100 return i->path;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200101 }
102
103 return NULL;
104}
105
106API const char *
107ly_errapptag(const struct ly_ctx *ctx)
108{
109 struct ly_err_item *i;
110
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200111 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200112
Radek Krejci572ee602020-09-16 14:35:08 +0200113 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200114 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +0200115 return i->apptag;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200116 }
117
118 return NULL;
119}
120
Radek Krejcidb0ee022021-03-15 16:53:44 +0100121API LY_ERR
122ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag, const char *err_msg, ...)
Radek Krejcie7b95092019-05-15 11:03:07 +0200123{
Radek Krejcidb0ee022021-03-15 16:53:44 +0100124 char *msg = NULL;
125 struct ly_err_item *e;
Radek Krejcie7b95092019-05-15 11:03:07 +0200126
Radek Krejcid43298b2021-03-25 16:17:15 +0100127 if (!err || (ecode == LY_SUCCESS)) {
Radek Krejcidb0ee022021-03-15 16:53:44 +0100128 /* nothing to do */
129 return ecode;
130 }
131
132 e = malloc(sizeof *e);
133 LY_CHECK_ERR_RET(!e, LOGMEM(NULL), LY_EMEM);
134 e->prev = (*err) ? (*err)->prev : e;
135 e->next = NULL;
136 if (*err) {
137 (*err)->prev->next = e;
138 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200139
140 /* fill in the information */
Radek Krejcidb0ee022021-03-15 16:53:44 +0100141 e->level = LY_LLERR;
142 e->no = ecode;
143 e->vecode = vecode;
144 e->path = path;
145 e->apptag = apptag;
Radek Krejcie7b95092019-05-15 11:03:07 +0200146
Radek Krejcidb0ee022021-03-15 16:53:44 +0100147 if (err_msg) {
148 va_list print_args;
149
150 va_start(print_args, err_msg);
151
152 if (vasprintf(&msg, err_msg, print_args) == -1) {
153 /* we don't have anything more to do, just set err_msg to NULL to avoid undefined content,
154 * still keep the information about the original error instead of LY_EMEM or other printf's error */
155 msg = NULL;
156 }
157
158 va_end(print_args);
159 }
160 e->msg = msg;
161
162 if (!(*err)) {
163 *err = e;
164 }
165
166 return e->no;
Radek Krejcie7b95092019-05-15 11:03:07 +0200167}
168
169API struct ly_err_item *
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200170ly_err_first(const struct ly_ctx *ctx)
171{
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200172 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200173
174 return pthread_getspecific(ctx->errlist_key);
175}
176
Radek Krejci572ee602020-09-16 14:35:08 +0200177API struct ly_err_item *
178ly_err_last(const struct ly_ctx *ctx)
179{
180 const struct ly_err_item *e;
181
182 LY_CHECK_ARG_RET(NULL, ctx, NULL);
183
184 e = pthread_getspecific(ctx->errlist_key);
185 return e ? e->prev : NULL;
186}
187
Radek Krejcie7b95092019-05-15 11:03:07 +0200188API void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200189ly_err_free(void *ptr)
190{
191 struct ly_err_item *i, *next;
192
193 /* clean the error list */
194 for (i = (struct ly_err_item *)ptr; i; i = next) {
195 next = i->next;
Radek Krejcidb0ee022021-03-15 16:53:44 +0100196 free(i->msg);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200197 free(i->path);
198 free(i->apptag);
199 free(i);
200 }
201}
202
203API void
204ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
205{
206 struct ly_err_item *i, *first;
207
208 first = ly_err_first(ctx);
209 if (first == eitem) {
210 eitem = NULL;
211 }
212 if (eitem) {
213 /* disconnect the error */
Radek Krejci1e008d22020-08-17 11:37:37 +0200214 for (i = first; i && (i->next != eitem); i = i->next) {}
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200215 assert(i);
216 i->next = NULL;
217 first->prev = i;
218 /* free this err and newer */
219 ly_err_free(eitem);
220 } else {
221 /* free all err */
222 ly_err_free(first);
223 pthread_setspecific(ctx->errlist_key, NULL);
224 }
225}
226
227API LY_LOG_LEVEL
Radek Krejci52b6d512020-10-12 12:33:17 +0200228ly_log_level(LY_LOG_LEVEL level)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200229{
Radek Krejci52b6d512020-10-12 12:33:17 +0200230 LY_LOG_LEVEL prev = ly_ll;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200231
Radek Krejci52b6d512020-10-12 12:33:17 +0200232 ly_ll = level;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200233 return prev;
234}
235
Radek Krejci1deb5be2020-08-26 16:43:36 +0200236API uint32_t
237ly_log_options(uint32_t opts)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200238{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200239 uint32_t prev = ly_log_opts;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200240
241 ly_log_opts = opts;
242 return prev;
243}
244
Radek Krejciebdaed02020-11-09 13:05:06 +0100245API uint32_t
Radek Krejci68433c92020-10-12 17:03:55 +0200246ly_log_dbg_groups(uint32_t dbg_groups)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200247{
248#ifndef NDEBUG
Radek Krejciebdaed02020-11-09 13:05:06 +0100249 uint32_t prev = ly_ldbg_groups;
250
Radek Krejci68433c92020-10-12 17:03:55 +0200251 ly_ldbg_groups = dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100252 return prev;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200253#else
254 (void)dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100255 return 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200256#endif
257}
258
259API void
Radek Krejci857189e2020-09-01 13:26:36 +0200260ly_set_log_clb(ly_log_clb clb, ly_bool path)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200261{
Michal Vaskod8085612020-08-21 12:55:23 +0200262 log_clb = clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200263 path_flag = path;
264}
265
Michal Vaskod8085612020-08-21 12:55:23 +0200266API ly_log_clb
267ly_get_log_clb(void)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200268{
Michal Vaskod8085612020-08-21 12:55:23 +0200269 return log_clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200270}
271
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100272void
Radek Krejciddace2c2021-01-08 11:30:56 +0100273ly_log_location(const struct lysc_node *scnode, const struct lyd_node *dnode,
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100274 const char *path, const struct ly_in *in, uint64_t line, ly_bool reset)
275{
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100276 if (scnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100277 ly_set_add(&log_location.scnodes, (void *)scnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100278 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100279 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100280 }
281
282 if (dnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100283 ly_set_add(&log_location.dnodes, (void *)dnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100284 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100285 ly_set_erase(&log_location.dnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100286 }
287
288 if (path) {
289 char *s = strdup(path);
Radek Krejciddace2c2021-01-08 11:30:56 +0100290 LY_CHECK_ERR_RET(!s, LOGMEM(NULL), );
291 ly_set_add(&log_location.paths, s, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100292 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100293 ly_set_erase(&log_location.paths, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100294 }
295
296 if (in) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100297 ly_set_add(&log_location.inputs, (void *)in, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100298 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100299 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100300 }
301
302 if (line) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100303 log_location.line = line;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100304 }
305}
306
307void
Radek Krejciddace2c2021-01-08 11:30:56 +0100308ly_log_location_revert(uint32_t scnode_steps, uint32_t dnode_steps,
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100309 uint32_t path_steps, uint32_t in_steps)
310{
Radek Krejciddace2c2021-01-08 11:30:56 +0100311 for (uint32_t i = scnode_steps; i && log_location.scnodes.count; i--) {
312 log_location.scnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100313 }
314
Radek Krejciddace2c2021-01-08 11:30:56 +0100315 for (uint32_t i = dnode_steps; i && log_location.dnodes.count; i--) {
316 log_location.dnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100317 }
318
Radek Krejciddace2c2021-01-08 11:30:56 +0100319 for (uint32_t i = path_steps; i && log_location.paths.count; i--) {
320 ly_set_rm_index(&log_location.paths, log_location.paths.count - 1, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100321 }
322
Radek Krejciddace2c2021-01-08 11:30:56 +0100323 for (uint32_t i = in_steps; i && log_location.inputs.count; i--) {
324 log_location.inputs.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100325 }
326
Radek Krejciddace2c2021-01-08 11:30:56 +0100327 /* deallocate the empty sets */
328 if (scnode_steps && !log_location.scnodes.count) {
329 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100330 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100331 if (dnode_steps && !log_location.dnodes.count) {
332 ly_set_erase(&log_location.dnodes, NULL);
333 }
334 if (path_steps && !log_location.paths.count) {
335 ly_set_erase(&log_location.paths, free);
336 }
337 if (in_steps && !log_location.inputs.count) {
338 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100339 }
340}
341
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200342static LY_ERR
343log_store(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
344{
345 struct ly_err_item *eitem, *last;
346
347 assert(ctx && (level < LY_LLVRB));
348
349 eitem = pthread_getspecific(ctx->errlist_key);
350 if (!eitem) {
351 /* if we are only to fill in path, there must have been an error stored */
352 assert(msg);
353 eitem = malloc(sizeof *eitem);
354 LY_CHECK_GOTO(!eitem, mem_fail);
355 eitem->prev = eitem;
356 eitem->next = NULL;
357
358 pthread_setspecific(ctx->errlist_key, eitem);
359 } else if (!msg) {
360 /* only filling the path */
361 assert(path);
362
363 /* find last error */
364 eitem = eitem->prev;
365 do {
366 if (eitem->level == LY_LLERR) {
367 /* fill the path */
368 free(eitem->path);
369 eitem->path = path;
370 return LY_SUCCESS;
371 }
372 eitem = eitem->prev;
373 } while (eitem->prev->next);
374 /* last error was not found */
375 assert(0);
Michal Vaskoed94a292019-11-06 15:43:41 +0100376 } else if ((ly_log_opts & LY_LOSTORE_LAST) == LY_LOSTORE_LAST) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200377 /* overwrite last message */
378 free(eitem->msg);
379 free(eitem->path);
380 free(eitem->apptag);
381 } else {
382 /* store new message */
383 last = eitem->prev;
384 eitem->prev = malloc(sizeof *eitem);
385 LY_CHECK_GOTO(!eitem->prev, mem_fail);
386 eitem = eitem->prev;
387 eitem->prev = last;
388 eitem->next = NULL;
389 last->next = eitem;
390 }
391
392 /* fill in the information */
393 eitem->level = level;
394 eitem->no = no;
395 eitem->vecode = vecode;
396 eitem->msg = msg;
397 eitem->path = path;
398 eitem->apptag = apptag;
399 return LY_SUCCESS;
400
401mem_fail:
402 LOGMEM(NULL);
403 free(msg);
404 free(path);
405 free(apptag);
406 return LY_EMEM;
407}
408
409static void
410log_vprintf(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *path,
Radek Krejci0f969882020-08-21 16:56:47 +0200411 const char *format, va_list args)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200412{
413 char *msg = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200414 ly_bool free_strs;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200415
Radek Krejci52b6d512020-10-12 12:33:17 +0200416 if (level > ly_ll) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200417 /* do not print or store the message */
418 free(path);
419 return;
420 }
421
Michal Vasko5a016922021-05-07 08:19:15 +0200422 if (no == LY_EMEM) {
423 /* just print it, anything else would most likely fail anyway */
424 if (ly_log_opts & LY_LOLOG) {
425 if (log_clb) {
426 log_clb(level, LY_EMEM_MSG, path);
427 } else {
428 fprintf(stderr, "libyang[%d]: ", level);
429 vfprintf(stderr, format, args);
430 if (path) {
431 fprintf(stderr, " (path: %s)\n", path);
432 } else {
433 fprintf(stderr, "\n");
434 }
435 }
436 }
437 free(path);
438 return;
439 }
440
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200441 /* store the error/warning (if we need to store errors internally, it does not matter what are the user log options) */
Michal Vaskoed94a292019-11-06 15:43:41 +0100442 if ((level < LY_LLVRB) && ctx && (ly_log_opts & LY_LOSTORE)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200443 assert(format);
444 if (vasprintf(&msg, format, args) == -1) {
445 LOGMEM(ctx);
446 free(path);
447 return;
448 }
Radek Krejcic9e64a62020-09-18 20:08:12 +0200449 if (((no & ~LY_EPLUGIN) == LY_EVALID) && (vecode == LYVE_SUCCESS)) {
450 /* assume we are inheriting the error, so inherit vecode as well */
451 vecode = ly_vecode(ctx);
452 }
Michal Vasko004d3152020-06-11 19:59:22 +0200453 if (log_store(ctx, level, no, vecode, msg, path, NULL)) {
454 return;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200455 }
456 free_strs = 0;
457 } else {
458 if (vasprintf(&msg, format, args) == -1) {
459 LOGMEM(ctx);
460 free(path);
461 return;
462 }
463 free_strs = 1;
464 }
465
466 /* if we are only storing errors internally, never print the message (yet) */
Michal Vaskoed94a292019-11-06 15:43:41 +0100467 if (ly_log_opts & LY_LOLOG) {
Michal Vaskod8085612020-08-21 12:55:23 +0200468 if (log_clb) {
469 log_clb(level, msg, path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200470 } else {
471 fprintf(stderr, "libyang[%d]: %s%s", level, msg, path ? " " : "\n");
472 if (path) {
473 fprintf(stderr, "(path: %s)\n", path);
474 }
475 }
476 }
477
478 if (free_strs) {
479 free(path);
480 free(msg);
481 }
482}
483
Radek Krejci4ab61562018-09-05 15:00:37 +0200484#ifndef NDEBUG
485
486void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200487ly_log_dbg(uint32_t group, const char *format, ...)
Radek Krejci4ab61562018-09-05 15:00:37 +0200488{
489 char *dbg_format;
490 const char *str_group;
491 va_list ap;
492
Radek Krejci68433c92020-10-12 17:03:55 +0200493 if (!(ly_ldbg_groups & group)) {
Radek Krejci4ab61562018-09-05 15:00:37 +0200494 return;
495 }
496
497 switch (group) {
498 case LY_LDGDICT:
499 str_group = "DICT";
500 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200501 case LY_LDGXPATH:
502 str_group = "XPATH";
503 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200504 default:
505 LOGINT(NULL);
506 return;
507 }
508
509 if (asprintf(&dbg_format, "%s: %s", str_group, format) == -1) {
510 LOGMEM(NULL);
511 return;
512 }
513
514 va_start(ap, format);
515 log_vprintf(NULL, LY_LLDBG, 0, 0, NULL, dbg_format, ap);
516 va_end(ap);
517}
518
519#endif
520
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200521void
522ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...)
523{
524 va_list ap;
525
526 va_start(ap, format);
527 log_vprintf(ctx, level, no, 0, NULL, format, ap);
528 va_end(ap);
529}
530
Radek Krejci94aa9942018-09-07 17:12:17 +0200531static LY_ERR
Radek Krejciddace2c2021-01-08 11:30:56 +0100532ly_vlog_build_path(const struct ly_ctx *ctx, char **path)
Radek Krejci94aa9942018-09-07 17:12:17 +0200533{
Radek Krejcic04f0a22018-09-21 15:49:45 +0200534 int rc;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100535 char *str = NULL, *prev = NULL;
Radek Krejcicb3e6472021-01-06 08:19:01 +0100536
Radek Krejci2efc45b2020-12-22 16:25:44 +0100537 *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200538
Radek Krejciddace2c2021-01-08 11:30:56 +0100539 if (log_location.paths.count && ((const char *)(log_location.paths.objs[log_location.paths.count - 1]))[0]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100540 /* simply get what is in the provided path string */
Radek Krejciddace2c2021-01-08 11:30:56 +0100541 *path = strdup((const char *)log_location.paths.objs[log_location.paths.count - 1]);
Radek Krejcic04f0a22018-09-21 15:49:45 +0200542 LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100543 } else {
544 /* generate location string */
Radek Krejciddace2c2021-01-08 11:30:56 +0100545 if (log_location.scnodes.count) {
546 str = lysc_path(log_location.scnodes.objs[log_location.scnodes.count - 1], LYSC_PATH_LOG, NULL, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100547 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
548
549 rc = asprintf(path, "Schema location %s", str);
550 free(str);
551 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
552 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100553 if (log_location.dnodes.count) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100554 prev = *path;
Radek Krejciddace2c2021-01-08 11:30:56 +0100555 str = lyd_path(log_location.dnodes.objs[log_location.dnodes.count - 1], LYD_PATH_STD, NULL, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100556 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
557
558 rc = asprintf(path, "%s%sata location %s", prev ? prev : "", prev ? ", d" : "D", str);
559 free(str);
560 free(prev);
561 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
562 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100563 if (log_location.line) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100564 prev = *path;
Radek Krejciddace2c2021-01-08 11:30:56 +0100565 rc = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L", log_location.line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100566 free(prev);
567 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
568
Radek Krejciddace2c2021-01-08 11:30:56 +0100569 log_location.line = 0;
570 } else if (log_location.inputs.count) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100571 prev = *path;
572 rc = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L",
Radek Krejciddace2c2021-01-08 11:30:56 +0100573 ((struct ly_in *)log_location.inputs.objs[log_location.inputs.count - 1])->line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100574 free(prev);
575 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
576 }
577
578 if (*path) {
579 prev = *path;
580 rc = asprintf(path, "%s.", prev);
581 free(prev);
582 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
583 }
Radek Krejci94aa9942018-09-07 17:12:17 +0200584 }
585
Radek Krejci94aa9942018-09-07 17:12:17 +0200586 return LY_SUCCESS;
587}
588
589void
Radek Krejci2efc45b2020-12-22 16:25:44 +0100590ly_vlog(const struct ly_ctx *ctx, LY_VECODE code, const char *format, ...)
Radek Krejci94aa9942018-09-07 17:12:17 +0200591{
592 va_list ap;
Michal Vasko22df3f02020-08-24 13:29:22 +0200593 char *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200594
Radek Krejci2efc45b2020-12-22 16:25:44 +0100595 if (path_flag && ctx) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100596 ly_vlog_build_path(ctx, &path);
Radek Krejci94aa9942018-09-07 17:12:17 +0200597 }
598
599 va_start(ap, format);
600 log_vprintf(ctx, LY_LLERR, LY_EVALID, code, path, format, ap);
601 /* path is spent and should not be freed! */
602 va_end(ap);
603}
604
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200605API void
Radek Krejci0b013302021-03-29 15:22:32 +0200606lyplg_ext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path, const char *format, ...)
Radek Krejci0935f412019-08-20 16:15:18 +0200607{
608 va_list ap;
609 char *plugin_msg;
610 int ret;
611
Radek Krejci52b6d512020-10-12 12:33:17 +0200612 if (ly_ll < level) {
Radek Krejci0935f412019-08-20 16:15:18 +0200613 return;
614 }
Radek Krejci932d3bb2021-02-09 16:29:38 +0100615 ret = asprintf(&plugin_msg, "Extension plugin \"%s\": %s", ext->def->plugin->id, format);
Radek Krejci0935f412019-08-20 16:15:18 +0200616 if (ret == -1) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200617 LOGMEM(ext->module->ctx);
Radek Krejci0935f412019-08-20 16:15:18 +0200618 return;
619 }
620
621 va_start(ap, format);
Radek Krejcia4614e62020-05-15 14:19:28 +0200622 log_vprintf(ext->module->ctx, level, (level == LY_LLERR ? LY_EPLUGIN : 0) | err_no, LYVE_OTHER, path ? strdup(path) : NULL, plugin_msg, ap);
Radek Krejci0935f412019-08-20 16:15:18 +0200623 va_end(ap);
624
625 free(plugin_msg);
626}
627
Michal Vasko177d0ed2020-11-23 16:43:03 +0100628/**
629 * @brief Exact same functionality as ::ly_err_print() but has variable arguments so va_start() can
630 * be used and an empty va_list created.
631 */
632static void
633_ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem, ...)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200634{
Michal Vasko177d0ed2020-11-23 16:43:03 +0100635 va_list ap;
636 char *path_dup = NULL;
637
638 LY_CHECK_ARG_RET(ctx, eitem, );
639
640 if (eitem->path) {
641 /* duplicate path because it will be freed */
642 path_dup = strdup(eitem->path);
643 LY_CHECK_ERR_RET(!path_dup, LOGMEM(ctx), );
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200644 }
Michal Vasko177d0ed2020-11-23 16:43:03 +0100645
646 va_start(ap, eitem);
647 log_vprintf(ctx, eitem->level, eitem->no, eitem->vecode, eitem->path, eitem->msg, ap);
648 va_end(ap);
649
650 if (path_dup) {
651 eitem->path = path_dup;
652 }
653}
654
655API void
656ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem)
657{
658 _ly_err_print(ctx, eitem);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200659}