blob: 640c8ffe482bc72c51831873ee284951520e6b99 [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
Radek Krejci535ea9f2020-05-29 16:01:05 +020015#define _GNU_SOURCE
Radek Krejcif8dc59a2020-11-25 13:47:44 +010016#define _POSIX_C_SOURCE 200809L /* strdup */
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 Krejci535ea9f2020-05-29 16:01:05 +020033#include "tree_data.h"
34#include "tree_schema.h"
Radek Krejci5aeea3a2018-09-05 13:29:36 +020035
Radek Krejci52b6d512020-10-12 12:33:17 +020036volatile LY_LOG_LEVEL ly_ll = LY_LLWRN;
Radek Krejci1deb5be2020-08-26 16:43:36 +020037volatile uint32_t ly_log_opts = LY_LOLOG | LY_LOSTORE_LAST;
Michal Vaskod8085612020-08-21 12:55:23 +020038static ly_log_clb log_clb;
Radek Krejci857189e2020-09-01 13:26:36 +020039static volatile ly_bool path_flag = 1;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020040#ifndef NDEBUG
Radek Krejci68433c92020-10-12 17:03:55 +020041volatile uint32_t ly_ldbg_groups = 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020042#endif
43
Radek Krejci94aa9942018-09-07 17:12:17 +020044/* how many bytes add when enlarging buffers */
45#define LY_BUF_STEP 128
46
Radek Krejcid33273d2018-10-25 14:55:52 +020047API LY_ERR
48ly_errcode(const struct ly_ctx *ctx)
49{
50 struct ly_err_item *i;
51
Radek Krejci572ee602020-09-16 14:35:08 +020052 i = ly_err_last(ctx);
Radek Krejcid33273d2018-10-25 14:55:52 +020053 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020054 return i->no;
Radek Krejcid33273d2018-10-25 14:55:52 +020055 }
56
57 return LY_SUCCESS;
58}
59
Radek Krejci5aeea3a2018-09-05 13:29:36 +020060API LY_VECODE
61ly_vecode(const struct ly_ctx *ctx)
62{
63 struct ly_err_item *i;
64
Radek Krejci572ee602020-09-16 14:35:08 +020065 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020066 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020067 return i->vecode;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020068 }
69
70 return LYVE_SUCCESS;
71}
72
73API const char *
74ly_errmsg(const struct ly_ctx *ctx)
75{
76 struct ly_err_item *i;
77
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020078 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020079
Radek Krejci572ee602020-09-16 14:35:08 +020080 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020081 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020082 return i->msg;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020083 }
84
85 return NULL;
86}
87
88API const char *
89ly_errpath(const struct ly_ctx *ctx)
90{
91 struct ly_err_item *i;
92
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020093 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020094
Radek Krejci572ee602020-09-16 14:35:08 +020095 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020096 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020097 return i->path;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020098 }
99
100 return NULL;
101}
102
103API const char *
104ly_errapptag(const struct ly_ctx *ctx)
105{
106 struct ly_err_item *i;
107
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200108 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200109
Radek Krejci572ee602020-09-16 14:35:08 +0200110 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200111 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +0200112 return i->apptag;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200113 }
114
115 return NULL;
116}
117
118API struct ly_err_item *
Radek Krejcie7b95092019-05-15 11:03:07 +0200119ly_err_new(LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
120{
121 struct ly_err_item *eitem;
122
123 eitem = malloc(sizeof *eitem);
124 LY_CHECK_ERR_RET(!eitem, LOGMEM(NULL), NULL);
125 eitem->prev = eitem;
126 eitem->next = NULL;
127
128 /* fill in the information */
129 eitem->level = level;
130 eitem->no = no;
131 eitem->vecode = vecode;
132 eitem->msg = msg;
133 eitem->path = path;
134 eitem->apptag = apptag;
135
136 return eitem;
137}
138
139API struct ly_err_item *
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200140ly_err_first(const struct ly_ctx *ctx)
141{
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200142 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200143
144 return pthread_getspecific(ctx->errlist_key);
145}
146
Radek Krejci572ee602020-09-16 14:35:08 +0200147API struct ly_err_item *
148ly_err_last(const struct ly_ctx *ctx)
149{
150 const struct ly_err_item *e;
151
152 LY_CHECK_ARG_RET(NULL, ctx, NULL);
153
154 e = pthread_getspecific(ctx->errlist_key);
155 return e ? e->prev : NULL;
156}
157
Radek Krejcie7b95092019-05-15 11:03:07 +0200158API void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200159ly_err_free(void *ptr)
160{
161 struct ly_err_item *i, *next;
162
163 /* clean the error list */
164 for (i = (struct ly_err_item *)ptr; i; i = next) {
165 next = i->next;
Radek Krejcie2692202020-12-01 14:21:12 +0100166 if (i->msg && strcmp(i->msg, LY_EMEM_MSG)) {
167 free(i->msg);
168 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200169 free(i->path);
170 free(i->apptag);
171 free(i);
172 }
173}
174
175API void
176ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
177{
178 struct ly_err_item *i, *first;
179
180 first = ly_err_first(ctx);
181 if (first == eitem) {
182 eitem = NULL;
183 }
184 if (eitem) {
185 /* disconnect the error */
Radek Krejci1e008d22020-08-17 11:37:37 +0200186 for (i = first; i && (i->next != eitem); i = i->next) {}
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200187 assert(i);
188 i->next = NULL;
189 first->prev = i;
190 /* free this err and newer */
191 ly_err_free(eitem);
192 } else {
193 /* free all err */
194 ly_err_free(first);
195 pthread_setspecific(ctx->errlist_key, NULL);
196 }
197}
198
199API LY_LOG_LEVEL
Radek Krejci52b6d512020-10-12 12:33:17 +0200200ly_log_level(LY_LOG_LEVEL level)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200201{
Radek Krejci52b6d512020-10-12 12:33:17 +0200202 LY_LOG_LEVEL prev = ly_ll;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200203
Radek Krejci52b6d512020-10-12 12:33:17 +0200204 ly_ll = level;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200205 return prev;
206}
207
Radek Krejci1deb5be2020-08-26 16:43:36 +0200208API uint32_t
209ly_log_options(uint32_t opts)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200210{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200211 uint32_t prev = ly_log_opts;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200212
213 ly_log_opts = opts;
214 return prev;
215}
216
Radek Krejciebdaed02020-11-09 13:05:06 +0100217API uint32_t
Radek Krejci68433c92020-10-12 17:03:55 +0200218ly_log_dbg_groups(uint32_t dbg_groups)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200219{
220#ifndef NDEBUG
Radek Krejciebdaed02020-11-09 13:05:06 +0100221 uint32_t prev = ly_ldbg_groups;
222
Radek Krejci68433c92020-10-12 17:03:55 +0200223 ly_ldbg_groups = dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100224 return prev;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200225#else
226 (void)dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100227 return 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200228#endif
229}
230
231API void
Radek Krejci857189e2020-09-01 13:26:36 +0200232ly_set_log_clb(ly_log_clb clb, ly_bool path)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200233{
Michal Vaskod8085612020-08-21 12:55:23 +0200234 log_clb = clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200235 path_flag = path;
236}
237
Michal Vaskod8085612020-08-21 12:55:23 +0200238API ly_log_clb
239ly_get_log_clb(void)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200240{
Michal Vaskod8085612020-08-21 12:55:23 +0200241 return log_clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200242}
243
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100244void
245ly_log_location(const struct ly_ctx *ctx, const struct lysc_node *scnode, const struct lyd_node *dnode,
246 const char *path, const struct ly_in *in, uint64_t line, ly_bool reset)
247{
248 struct ly_log_location_s *loc = pthread_getspecific(ctx->log_location_key);
249
250 if (!loc) {
251 reset = 0; /* no needed */
252 loc = calloc(1, sizeof *loc);
253 LY_CHECK_ERR_RET(!loc, LOGMEM(ctx), );
254
255 pthread_setspecific(ctx->log_location_key, loc);
256 }
257
258 if (scnode) {
259 ly_set_add(&loc->scnodes, (void *)scnode, 1, NULL);
260 } else if (reset) {
261 ly_set_erase(&loc->scnodes, NULL);
262 }
263
264 if (dnode) {
265 ly_set_add(&loc->dnodes, (void *)dnode, 1, NULL);
266 } else if (reset) {
267 ly_set_erase(&loc->dnodes, NULL);
268 }
269
270 if (path) {
271 char *s = strdup(path);
272 LY_CHECK_ERR_RET(!s, LOGMEM(ctx), );
273 ly_set_add(&loc->paths, s, 1, NULL);
274 } else if (reset) {
275 ly_set_erase(&loc->paths, free);
276 }
277
278 if (in) {
279 ly_set_add(&loc->inputs, (void *)in, 1, NULL);
280 } else if (reset) {
281 ly_set_erase(&loc->inputs, NULL);
282 }
283
284 if (line) {
285 loc->line = line;
286 }
287}
288
289void
290ly_log_location_revert(const struct ly_ctx *ctx, uint32_t scnode_steps, uint32_t dnode_steps,
291 uint32_t path_steps, uint32_t in_steps)
292{
293
294 struct ly_log_location_s *loc = pthread_getspecific(ctx->log_location_key);
295
296 if (!loc) {
297 return;
298 }
299
300 for (uint32_t i = scnode_steps; i && loc->scnodes.count; i--) {
301 loc->scnodes.count--;
302 }
303
304 for (uint32_t i = dnode_steps; i && loc->dnodes.count; i--) {
305 loc->dnodes.count--;
306 }
307
308 for (uint32_t i = path_steps; i && loc->paths.count; i--) {
309 ly_set_rm_index(&loc->paths, loc->paths.count - 1, free);
310 }
311
312 for (uint32_t i = in_steps; i && loc->inputs.count; i--) {
313 loc->inputs.count--;
314 }
315}
316
317void
318ly_log_location_free(void *ptr)
319{
320 struct ly_log_location_s *loc = (struct ly_log_location_s *)ptr;
321
322 if (loc) {
323 ly_set_erase(&loc->scnodes, NULL);
324 ly_set_erase(&loc->dnodes, NULL);
325 ly_set_erase(&loc->paths, free);
326 ly_set_erase(&loc->inputs, NULL);
327 free(loc);
328 }
329}
330
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200331static LY_ERR
332log_store(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
333{
334 struct ly_err_item *eitem, *last;
335
336 assert(ctx && (level < LY_LLVRB));
337
338 eitem = pthread_getspecific(ctx->errlist_key);
339 if (!eitem) {
340 /* if we are only to fill in path, there must have been an error stored */
341 assert(msg);
342 eitem = malloc(sizeof *eitem);
343 LY_CHECK_GOTO(!eitem, mem_fail);
344 eitem->prev = eitem;
345 eitem->next = NULL;
346
347 pthread_setspecific(ctx->errlist_key, eitem);
348 } else if (!msg) {
349 /* only filling the path */
350 assert(path);
351
352 /* find last error */
353 eitem = eitem->prev;
354 do {
355 if (eitem->level == LY_LLERR) {
356 /* fill the path */
357 free(eitem->path);
358 eitem->path = path;
359 return LY_SUCCESS;
360 }
361 eitem = eitem->prev;
362 } while (eitem->prev->next);
363 /* last error was not found */
364 assert(0);
Michal Vaskoed94a292019-11-06 15:43:41 +0100365 } else if ((ly_log_opts & LY_LOSTORE_LAST) == LY_LOSTORE_LAST) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200366 /* overwrite last message */
367 free(eitem->msg);
368 free(eitem->path);
369 free(eitem->apptag);
370 } else {
371 /* store new message */
372 last = eitem->prev;
373 eitem->prev = malloc(sizeof *eitem);
374 LY_CHECK_GOTO(!eitem->prev, mem_fail);
375 eitem = eitem->prev;
376 eitem->prev = last;
377 eitem->next = NULL;
378 last->next = eitem;
379 }
380
381 /* fill in the information */
382 eitem->level = level;
383 eitem->no = no;
384 eitem->vecode = vecode;
385 eitem->msg = msg;
386 eitem->path = path;
387 eitem->apptag = apptag;
388 return LY_SUCCESS;
389
390mem_fail:
391 LOGMEM(NULL);
392 free(msg);
393 free(path);
394 free(apptag);
395 return LY_EMEM;
396}
397
398static void
399log_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 +0200400 const char *format, va_list args)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200401{
402 char *msg = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200403 ly_bool free_strs;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200404
Radek Krejci52b6d512020-10-12 12:33:17 +0200405 if (level > ly_ll) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200406 /* do not print or store the message */
407 free(path);
408 return;
409 }
410
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200411 /* 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 +0100412 if ((level < LY_LLVRB) && ctx && (ly_log_opts & LY_LOSTORE)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200413 assert(format);
414 if (vasprintf(&msg, format, args) == -1) {
415 LOGMEM(ctx);
416 free(path);
417 return;
418 }
Radek Krejcic9e64a62020-09-18 20:08:12 +0200419 if (((no & ~LY_EPLUGIN) == LY_EVALID) && (vecode == LYVE_SUCCESS)) {
420 /* assume we are inheriting the error, so inherit vecode as well */
421 vecode = ly_vecode(ctx);
422 }
Michal Vasko004d3152020-06-11 19:59:22 +0200423 if (log_store(ctx, level, no, vecode, msg, path, NULL)) {
424 return;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200425 }
426 free_strs = 0;
427 } else {
428 if (vasprintf(&msg, format, args) == -1) {
429 LOGMEM(ctx);
430 free(path);
431 return;
432 }
433 free_strs = 1;
434 }
435
436 /* if we are only storing errors internally, never print the message (yet) */
Michal Vaskoed94a292019-11-06 15:43:41 +0100437 if (ly_log_opts & LY_LOLOG) {
Michal Vaskod8085612020-08-21 12:55:23 +0200438 if (log_clb) {
439 log_clb(level, msg, path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200440 } else {
441 fprintf(stderr, "libyang[%d]: %s%s", level, msg, path ? " " : "\n");
442 if (path) {
443 fprintf(stderr, "(path: %s)\n", path);
444 }
445 }
446 }
447
448 if (free_strs) {
449 free(path);
450 free(msg);
451 }
452}
453
Radek Krejci4ab61562018-09-05 15:00:37 +0200454#ifndef NDEBUG
455
456void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200457ly_log_dbg(uint32_t group, const char *format, ...)
Radek Krejci4ab61562018-09-05 15:00:37 +0200458{
459 char *dbg_format;
460 const char *str_group;
461 va_list ap;
462
Radek Krejci68433c92020-10-12 17:03:55 +0200463 if (!(ly_ldbg_groups & group)) {
Radek Krejci4ab61562018-09-05 15:00:37 +0200464 return;
465 }
466
467 switch (group) {
468 case LY_LDGDICT:
469 str_group = "DICT";
470 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200471 case LY_LDGXPATH:
472 str_group = "XPATH";
473 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200474 default:
475 LOGINT(NULL);
476 return;
477 }
478
479 if (asprintf(&dbg_format, "%s: %s", str_group, format) == -1) {
480 LOGMEM(NULL);
481 return;
482 }
483
484 va_start(ap, format);
485 log_vprintf(NULL, LY_LLDBG, 0, 0, NULL, dbg_format, ap);
486 va_end(ap);
487}
488
489#endif
490
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200491void
492ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...)
493{
494 va_list ap;
495
496 va_start(ap, format);
497 log_vprintf(ctx, level, no, 0, NULL, format, ap);
498 va_end(ap);
499}
500
Radek Krejci94aa9942018-09-07 17:12:17 +0200501static LY_ERR
Radek Krejcic04f0a22018-09-21 15:49:45 +0200502ly_vlog_build_path(const struct ly_ctx *ctx, enum LY_VLOG_ELEM elem_type, const void *elem, char **path)
Radek Krejci94aa9942018-09-07 17:12:17 +0200503{
Radek Krejcic04f0a22018-09-21 15:49:45 +0200504 int rc;
Radek Krejci94aa9942018-09-07 17:12:17 +0200505
Radek Krejcic04f0a22018-09-21 15:49:45 +0200506 switch (elem_type) {
507 case LY_VLOG_STR:
Michal Vaskof6e51882019-12-16 09:59:45 +0100508 *path = strdup(elem);
Radek Krejcic04f0a22018-09-21 15:49:45 +0200509 LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
510 break;
511 case LY_VLOG_LINE:
Michal Vasko22df3f02020-08-24 13:29:22 +0200512 rc = asprintf(path, "Line number %" PRIu64 ".", *((uint64_t *)elem));
Radek Krejcic04f0a22018-09-21 15:49:45 +0200513 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
514 break;
Michal Vaskof6e51882019-12-16 09:59:45 +0100515 case LY_VLOG_LYSC:
516 *path = lysc_path(elem, LYSC_PATH_LOG, NULL, 0);
517 LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
518 break;
Michal Vasko9b368d32020-02-14 13:53:31 +0100519 case LY_VLOG_LYD:
Radek Krejci635d2b82021-01-04 11:26:51 +0100520 *path = lyd_path(elem, LYD_PATH_STD, NULL, 0);
Michal Vasko9b368d32020-02-14 13:53:31 +0100521 LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
522 break;
Radek Krejcic04f0a22018-09-21 15:49:45 +0200523 default:
524 /* shouldn't be here */
525 LOGINT_RET(ctx);
Radek Krejci94aa9942018-09-07 17:12:17 +0200526 }
527
Radek Krejci94aa9942018-09-07 17:12:17 +0200528 return LY_SUCCESS;
529}
530
531void
532ly_vlog(const struct ly_ctx *ctx, enum LY_VLOG_ELEM elem_type, const void *elem, LY_VECODE code, const char *format, ...)
533{
534 va_list ap;
Michal Vasko22df3f02020-08-24 13:29:22 +0200535 char *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200536 const struct ly_err_item *first;
537
538 if (path_flag && (elem_type != LY_VLOG_NONE)) {
539 if (elem_type == LY_VLOG_PREV) {
540 /* use previous path */
541 first = ly_err_first(ctx);
542 if (first && first->prev->path) {
543 path = strdup(first->prev->path);
544 }
545 } else {
546 /* print path */
547 if (!elem) {
548 /* top-level */
549 path = strdup("/");
550 } else {
Radek Krejcic04f0a22018-09-21 15:49:45 +0200551 ly_vlog_build_path(ctx, elem_type, elem, &path);
Radek Krejci94aa9942018-09-07 17:12:17 +0200552 }
553 }
554 }
555
556 va_start(ap, format);
557 log_vprintf(ctx, LY_LLERR, LY_EVALID, code, path, format, ap);
558 /* path is spent and should not be freed! */
559 va_end(ap);
560}
561
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200562API void
Radek Krejci0935f412019-08-20 16:15:18 +0200563lyext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path, const char *format, ...)
564{
565 va_list ap;
566 char *plugin_msg;
567 int ret;
568
Radek Krejci52b6d512020-10-12 12:33:17 +0200569 if (ly_ll < level) {
Radek Krejci0935f412019-08-20 16:15:18 +0200570 return;
571 }
572 ret = asprintf(&plugin_msg, "Extension plugin \"%s\": %s)", ext->def->plugin->id, format);
573 if (ret == -1) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200574 LOGMEM(ext->module->ctx);
Radek Krejci0935f412019-08-20 16:15:18 +0200575 return;
576 }
577
578 va_start(ap, format);
Radek Krejcia4614e62020-05-15 14:19:28 +0200579 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 +0200580 va_end(ap);
581
582 free(plugin_msg);
583}
584
Michal Vasko177d0ed2020-11-23 16:43:03 +0100585/**
586 * @brief Exact same functionality as ::ly_err_print() but has variable arguments so va_start() can
587 * be used and an empty va_list created.
588 */
589static void
590_ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem, ...)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200591{
Michal Vasko177d0ed2020-11-23 16:43:03 +0100592 va_list ap;
593 char *path_dup = NULL;
594
595 LY_CHECK_ARG_RET(ctx, eitem, );
596
597 if (eitem->path) {
598 /* duplicate path because it will be freed */
599 path_dup = strdup(eitem->path);
600 LY_CHECK_ERR_RET(!path_dup, LOGMEM(ctx), );
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200601 }
Michal Vasko177d0ed2020-11-23 16:43:03 +0100602
603 va_start(ap, eitem);
604 log_vprintf(ctx, eitem->level, eitem->no, eitem->vecode, eitem->path, eitem->msg, ap);
605 va_end(ap);
606
607 if (path_dup) {
608 eitem->path = path_dup;
609 }
610}
611
612API void
613ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem)
614{
615 _ly_err_print(ctx, eitem);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200616}