blob: 7498c741e23166cc493f6eca4f1677dcf7f2e611 [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 Krejci2efc45b2020-12-22 16:25:44 +0100502ly_vlog_build_path(const struct ly_ctx *ctx, struct ly_log_location_s *location, char **path)
Radek Krejci94aa9942018-09-07 17:12:17 +0200503{
Radek Krejcic04f0a22018-09-21 15:49:45 +0200504 int rc;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100505 char *str = NULL, *prev = NULL;
506 *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200507
Radek Krejci2efc45b2020-12-22 16:25:44 +0100508 if (location->paths.count && ((const char *)(location->paths.objs[location->paths.count - 1]))[0]) {
509 /* simply get what is in the provided path string */
510 *path = strdup((const char *)location->paths.objs[location->paths.count - 1]);
Radek Krejcic04f0a22018-09-21 15:49:45 +0200511 LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100512 } else {
513 /* generate location string */
514 if (location->scnodes.count) {
515 str = lysc_path(location->scnodes.objs[location->scnodes.count - 1], LYSC_PATH_LOG, NULL, 0);
516 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
517
518 rc = asprintf(path, "Schema location %s", str);
519 free(str);
520 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
521 }
522 if (location->dnodes.count) {
523 prev = *path;
524 str = lyd_path(location->dnodes.objs[location->dnodes.count - 1], LYD_PATH_STD, NULL, 0);
525 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
526
527 rc = asprintf(path, "%s%sata location %s", prev ? prev : "", prev ? ", d" : "D", str);
528 free(str);
529 free(prev);
530 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
531 }
532 if (location->line) {
533 prev = *path;
534 rc = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L", location->line);
535 free(prev);
536 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
537
538 location->line = 0;
539 } else if (location->inputs.count) {
540 prev = *path;
541 rc = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L",
542 ((struct ly_in *)location->inputs.objs[location->inputs.count - 1])->line);
543 free(prev);
544 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
545 }
546
547 if (*path) {
548 prev = *path;
549 rc = asprintf(path, "%s.", prev);
550 free(prev);
551 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
552 }
Radek Krejci94aa9942018-09-07 17:12:17 +0200553 }
554
Radek Krejci94aa9942018-09-07 17:12:17 +0200555 return LY_SUCCESS;
556}
557
558void
Radek Krejci2efc45b2020-12-22 16:25:44 +0100559ly_vlog(const struct ly_ctx *ctx, LY_VECODE code, const char *format, ...)
Radek Krejci94aa9942018-09-07 17:12:17 +0200560{
561 va_list ap;
Michal Vasko22df3f02020-08-24 13:29:22 +0200562 char *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200563
Radek Krejci2efc45b2020-12-22 16:25:44 +0100564 if (path_flag && ctx) {
565 /* get the location information */
566 struct ly_log_location_s *location = pthread_getspecific(ctx->log_location_key);
567 if (location) {
568 ly_vlog_build_path(ctx, location, &path);
Radek Krejci94aa9942018-09-07 17:12:17 +0200569 }
570 }
571
572 va_start(ap, format);
573 log_vprintf(ctx, LY_LLERR, LY_EVALID, code, path, format, ap);
574 /* path is spent and should not be freed! */
575 va_end(ap);
576}
577
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200578API void
Radek Krejci0935f412019-08-20 16:15:18 +0200579lyext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path, const char *format, ...)
580{
581 va_list ap;
582 char *plugin_msg;
583 int ret;
584
Radek Krejci52b6d512020-10-12 12:33:17 +0200585 if (ly_ll < level) {
Radek Krejci0935f412019-08-20 16:15:18 +0200586 return;
587 }
588 ret = asprintf(&plugin_msg, "Extension plugin \"%s\": %s)", ext->def->plugin->id, format);
589 if (ret == -1) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200590 LOGMEM(ext->module->ctx);
Radek Krejci0935f412019-08-20 16:15:18 +0200591 return;
592 }
593
594 va_start(ap, format);
Radek Krejcia4614e62020-05-15 14:19:28 +0200595 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 +0200596 va_end(ap);
597
598 free(plugin_msg);
599}
600
Michal Vasko177d0ed2020-11-23 16:43:03 +0100601/**
602 * @brief Exact same functionality as ::ly_err_print() but has variable arguments so va_start() can
603 * be used and an empty va_list created.
604 */
605static void
606_ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem, ...)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200607{
Michal Vasko177d0ed2020-11-23 16:43:03 +0100608 va_list ap;
609 char *path_dup = NULL;
610
611 LY_CHECK_ARG_RET(ctx, eitem, );
612
613 if (eitem->path) {
614 /* duplicate path because it will be freed */
615 path_dup = strdup(eitem->path);
616 LY_CHECK_ERR_RET(!path_dup, LOGMEM(ctx), );
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200617 }
Michal Vasko177d0ed2020-11-23 16:43:03 +0100618
619 va_start(ap, eitem);
620 log_vprintf(ctx, eitem->level, eitem->no, eitem->vecode, eitem->path, eitem->msg, ap);
621 va_end(ap);
622
623 if (path_dup) {
624 eitem->path = path_dup;
625 }
626}
627
628API void
629ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem)
630{
631 _ly_err_print(ctx, eitem);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200632}