blob: d1e981344fb80b246ebc20e4966dec935db225a8 [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 Krejciddace2c2021-01-08 11:30:56 +010044THREAD_LOCAL struct ly_log_location_s log_location = {0};
45
Radek Krejci94aa9942018-09-07 17:12:17 +020046/* how many bytes add when enlarging buffers */
47#define LY_BUF_STEP 128
48
Radek Krejcid33273d2018-10-25 14:55:52 +020049API LY_ERR
50ly_errcode(const struct ly_ctx *ctx)
51{
52 struct ly_err_item *i;
53
Radek Krejci572ee602020-09-16 14:35:08 +020054 i = ly_err_last(ctx);
Radek Krejcid33273d2018-10-25 14:55:52 +020055 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020056 return i->no;
Radek Krejcid33273d2018-10-25 14:55:52 +020057 }
58
59 return LY_SUCCESS;
60}
61
Radek Krejci5aeea3a2018-09-05 13:29:36 +020062API LY_VECODE
63ly_vecode(const struct ly_ctx *ctx)
64{
65 struct ly_err_item *i;
66
Radek Krejci572ee602020-09-16 14:35:08 +020067 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020068 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020069 return i->vecode;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020070 }
71
72 return LYVE_SUCCESS;
73}
74
75API const char *
76ly_errmsg(const struct ly_ctx *ctx)
77{
78 struct ly_err_item *i;
79
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020080 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020081
Radek Krejci572ee602020-09-16 14:35:08 +020082 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020083 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020084 return i->msg;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020085 }
86
87 return NULL;
88}
89
90API const char *
91ly_errpath(const struct ly_ctx *ctx)
92{
93 struct ly_err_item *i;
94
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020095 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020096
Radek Krejci572ee602020-09-16 14:35:08 +020097 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020098 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020099 return i->path;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200100 }
101
102 return NULL;
103}
104
105API const char *
106ly_errapptag(const struct ly_ctx *ctx)
107{
108 struct ly_err_item *i;
109
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200110 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200111
Radek Krejci572ee602020-09-16 14:35:08 +0200112 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200113 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +0200114 return i->apptag;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200115 }
116
117 return NULL;
118}
119
120API struct ly_err_item *
Radek Krejcie7b95092019-05-15 11:03:07 +0200121ly_err_new(LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
122{
123 struct ly_err_item *eitem;
124
125 eitem = malloc(sizeof *eitem);
126 LY_CHECK_ERR_RET(!eitem, LOGMEM(NULL), NULL);
127 eitem->prev = eitem;
128 eitem->next = NULL;
129
130 /* fill in the information */
131 eitem->level = level;
132 eitem->no = no;
133 eitem->vecode = vecode;
134 eitem->msg = msg;
135 eitem->path = path;
136 eitem->apptag = apptag;
137
138 return eitem;
139}
140
141API struct ly_err_item *
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200142ly_err_first(const struct ly_ctx *ctx)
143{
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200144 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200145
146 return pthread_getspecific(ctx->errlist_key);
147}
148
Radek Krejci572ee602020-09-16 14:35:08 +0200149API struct ly_err_item *
150ly_err_last(const struct ly_ctx *ctx)
151{
152 const struct ly_err_item *e;
153
154 LY_CHECK_ARG_RET(NULL, ctx, NULL);
155
156 e = pthread_getspecific(ctx->errlist_key);
157 return e ? e->prev : NULL;
158}
159
Radek Krejcie7b95092019-05-15 11:03:07 +0200160API void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200161ly_err_free(void *ptr)
162{
163 struct ly_err_item *i, *next;
164
165 /* clean the error list */
166 for (i = (struct ly_err_item *)ptr; i; i = next) {
167 next = i->next;
Radek Krejcie2692202020-12-01 14:21:12 +0100168 if (i->msg && strcmp(i->msg, LY_EMEM_MSG)) {
169 free(i->msg);
170 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200171 free(i->path);
172 free(i->apptag);
173 free(i);
174 }
175}
176
177API void
178ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
179{
180 struct ly_err_item *i, *first;
181
182 first = ly_err_first(ctx);
183 if (first == eitem) {
184 eitem = NULL;
185 }
186 if (eitem) {
187 /* disconnect the error */
Radek Krejci1e008d22020-08-17 11:37:37 +0200188 for (i = first; i && (i->next != eitem); i = i->next) {}
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200189 assert(i);
190 i->next = NULL;
191 first->prev = i;
192 /* free this err and newer */
193 ly_err_free(eitem);
194 } else {
195 /* free all err */
196 ly_err_free(first);
197 pthread_setspecific(ctx->errlist_key, NULL);
198 }
199}
200
201API LY_LOG_LEVEL
Radek Krejci52b6d512020-10-12 12:33:17 +0200202ly_log_level(LY_LOG_LEVEL level)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200203{
Radek Krejci52b6d512020-10-12 12:33:17 +0200204 LY_LOG_LEVEL prev = ly_ll;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200205
Radek Krejci52b6d512020-10-12 12:33:17 +0200206 ly_ll = level;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200207 return prev;
208}
209
Radek Krejci1deb5be2020-08-26 16:43:36 +0200210API uint32_t
211ly_log_options(uint32_t opts)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200212{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200213 uint32_t prev = ly_log_opts;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200214
215 ly_log_opts = opts;
216 return prev;
217}
218
Radek Krejciebdaed02020-11-09 13:05:06 +0100219API uint32_t
Radek Krejci68433c92020-10-12 17:03:55 +0200220ly_log_dbg_groups(uint32_t dbg_groups)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200221{
222#ifndef NDEBUG
Radek Krejciebdaed02020-11-09 13:05:06 +0100223 uint32_t prev = ly_ldbg_groups;
224
Radek Krejci68433c92020-10-12 17:03:55 +0200225 ly_ldbg_groups = dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100226 return prev;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200227#else
228 (void)dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100229 return 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200230#endif
231}
232
233API void
Radek Krejci857189e2020-09-01 13:26:36 +0200234ly_set_log_clb(ly_log_clb clb, ly_bool path)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200235{
Michal Vaskod8085612020-08-21 12:55:23 +0200236 log_clb = clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200237 path_flag = path;
238}
239
Michal Vaskod8085612020-08-21 12:55:23 +0200240API ly_log_clb
241ly_get_log_clb(void)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200242{
Michal Vaskod8085612020-08-21 12:55:23 +0200243 return log_clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200244}
245
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100246void
Radek Krejciddace2c2021-01-08 11:30:56 +0100247ly_log_location(const struct lysc_node *scnode, const struct lyd_node *dnode,
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100248 const char *path, const struct ly_in *in, uint64_t line, ly_bool reset)
249{
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100250 if (scnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100251 ly_set_add(&log_location.scnodes, (void *)scnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100252 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100253 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100254 }
255
256 if (dnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100257 ly_set_add(&log_location.dnodes, (void *)dnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100258 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100259 ly_set_erase(&log_location.dnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100260 }
261
262 if (path) {
263 char *s = strdup(path);
Radek Krejciddace2c2021-01-08 11:30:56 +0100264 LY_CHECK_ERR_RET(!s, LOGMEM(NULL), );
265 ly_set_add(&log_location.paths, s, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100266 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100267 ly_set_erase(&log_location.paths, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100268 }
269
270 if (in) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100271 ly_set_add(&log_location.inputs, (void *)in, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100272 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100273 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100274 }
275
276 if (line) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100277 log_location.line = line;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100278 }
279}
280
281void
Radek Krejciddace2c2021-01-08 11:30:56 +0100282ly_log_location_revert(uint32_t scnode_steps, uint32_t dnode_steps,
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100283 uint32_t path_steps, uint32_t in_steps)
284{
Radek Krejciddace2c2021-01-08 11:30:56 +0100285 for (uint32_t i = scnode_steps; i && log_location.scnodes.count; i--) {
286 log_location.scnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100287 }
288
Radek Krejciddace2c2021-01-08 11:30:56 +0100289 for (uint32_t i = dnode_steps; i && log_location.dnodes.count; i--) {
290 log_location.dnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100291 }
292
Radek Krejciddace2c2021-01-08 11:30:56 +0100293 for (uint32_t i = path_steps; i && log_location.paths.count; i--) {
294 ly_set_rm_index(&log_location.paths, log_location.paths.count - 1, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100295 }
296
Radek Krejciddace2c2021-01-08 11:30:56 +0100297 for (uint32_t i = in_steps; i && log_location.inputs.count; i--) {
298 log_location.inputs.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100299 }
300
Radek Krejciddace2c2021-01-08 11:30:56 +0100301 /* deallocate the empty sets */
302 if (scnode_steps && !log_location.scnodes.count) {
303 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100304 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100305 if (dnode_steps && !log_location.dnodes.count) {
306 ly_set_erase(&log_location.dnodes, NULL);
307 }
308 if (path_steps && !log_location.paths.count) {
309 ly_set_erase(&log_location.paths, free);
310 }
311 if (in_steps && !log_location.inputs.count) {
312 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100313 }
314}
315
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200316static LY_ERR
317log_store(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
318{
319 struct ly_err_item *eitem, *last;
320
321 assert(ctx && (level < LY_LLVRB));
322
323 eitem = pthread_getspecific(ctx->errlist_key);
324 if (!eitem) {
325 /* if we are only to fill in path, there must have been an error stored */
326 assert(msg);
327 eitem = malloc(sizeof *eitem);
328 LY_CHECK_GOTO(!eitem, mem_fail);
329 eitem->prev = eitem;
330 eitem->next = NULL;
331
332 pthread_setspecific(ctx->errlist_key, eitem);
333 } else if (!msg) {
334 /* only filling the path */
335 assert(path);
336
337 /* find last error */
338 eitem = eitem->prev;
339 do {
340 if (eitem->level == LY_LLERR) {
341 /* fill the path */
342 free(eitem->path);
343 eitem->path = path;
344 return LY_SUCCESS;
345 }
346 eitem = eitem->prev;
347 } while (eitem->prev->next);
348 /* last error was not found */
349 assert(0);
Michal Vaskoed94a292019-11-06 15:43:41 +0100350 } else if ((ly_log_opts & LY_LOSTORE_LAST) == LY_LOSTORE_LAST) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200351 /* overwrite last message */
352 free(eitem->msg);
353 free(eitem->path);
354 free(eitem->apptag);
355 } else {
356 /* store new message */
357 last = eitem->prev;
358 eitem->prev = malloc(sizeof *eitem);
359 LY_CHECK_GOTO(!eitem->prev, mem_fail);
360 eitem = eitem->prev;
361 eitem->prev = last;
362 eitem->next = NULL;
363 last->next = eitem;
364 }
365
366 /* fill in the information */
367 eitem->level = level;
368 eitem->no = no;
369 eitem->vecode = vecode;
370 eitem->msg = msg;
371 eitem->path = path;
372 eitem->apptag = apptag;
373 return LY_SUCCESS;
374
375mem_fail:
376 LOGMEM(NULL);
377 free(msg);
378 free(path);
379 free(apptag);
380 return LY_EMEM;
381}
382
383static void
384log_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 +0200385 const char *format, va_list args)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200386{
387 char *msg = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200388 ly_bool free_strs;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200389
Radek Krejci52b6d512020-10-12 12:33:17 +0200390 if (level > ly_ll) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200391 /* do not print or store the message */
392 free(path);
393 return;
394 }
395
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200396 /* 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 +0100397 if ((level < LY_LLVRB) && ctx && (ly_log_opts & LY_LOSTORE)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200398 assert(format);
399 if (vasprintf(&msg, format, args) == -1) {
400 LOGMEM(ctx);
401 free(path);
402 return;
403 }
Radek Krejcic9e64a62020-09-18 20:08:12 +0200404 if (((no & ~LY_EPLUGIN) == LY_EVALID) && (vecode == LYVE_SUCCESS)) {
405 /* assume we are inheriting the error, so inherit vecode as well */
406 vecode = ly_vecode(ctx);
407 }
Michal Vasko004d3152020-06-11 19:59:22 +0200408 if (log_store(ctx, level, no, vecode, msg, path, NULL)) {
409 return;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200410 }
411 free_strs = 0;
412 } else {
413 if (vasprintf(&msg, format, args) == -1) {
414 LOGMEM(ctx);
415 free(path);
416 return;
417 }
418 free_strs = 1;
419 }
420
421 /* if we are only storing errors internally, never print the message (yet) */
Michal Vaskoed94a292019-11-06 15:43:41 +0100422 if (ly_log_opts & LY_LOLOG) {
Michal Vaskod8085612020-08-21 12:55:23 +0200423 if (log_clb) {
424 log_clb(level, msg, path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200425 } else {
426 fprintf(stderr, "libyang[%d]: %s%s", level, msg, path ? " " : "\n");
427 if (path) {
428 fprintf(stderr, "(path: %s)\n", path);
429 }
430 }
431 }
432
433 if (free_strs) {
434 free(path);
435 free(msg);
436 }
437}
438
Radek Krejci4ab61562018-09-05 15:00:37 +0200439#ifndef NDEBUG
440
441void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200442ly_log_dbg(uint32_t group, const char *format, ...)
Radek Krejci4ab61562018-09-05 15:00:37 +0200443{
444 char *dbg_format;
445 const char *str_group;
446 va_list ap;
447
Radek Krejci68433c92020-10-12 17:03:55 +0200448 if (!(ly_ldbg_groups & group)) {
Radek Krejci4ab61562018-09-05 15:00:37 +0200449 return;
450 }
451
452 switch (group) {
453 case LY_LDGDICT:
454 str_group = "DICT";
455 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200456 case LY_LDGXPATH:
457 str_group = "XPATH";
458 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200459 default:
460 LOGINT(NULL);
461 return;
462 }
463
464 if (asprintf(&dbg_format, "%s: %s", str_group, format) == -1) {
465 LOGMEM(NULL);
466 return;
467 }
468
469 va_start(ap, format);
470 log_vprintf(NULL, LY_LLDBG, 0, 0, NULL, dbg_format, ap);
471 va_end(ap);
472}
473
474#endif
475
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200476void
477ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...)
478{
479 va_list ap;
480
481 va_start(ap, format);
482 log_vprintf(ctx, level, no, 0, NULL, format, ap);
483 va_end(ap);
484}
485
Radek Krejci94aa9942018-09-07 17:12:17 +0200486static LY_ERR
Radek Krejciddace2c2021-01-08 11:30:56 +0100487ly_vlog_build_path(const struct ly_ctx *ctx, char **path)
Radek Krejci94aa9942018-09-07 17:12:17 +0200488{
Radek Krejcic04f0a22018-09-21 15:49:45 +0200489 int rc;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100490 char *str = NULL, *prev = NULL;
Radek Krejcicb3e6472021-01-06 08:19:01 +0100491
Radek Krejci2efc45b2020-12-22 16:25:44 +0100492 *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200493
Radek Krejciddace2c2021-01-08 11:30:56 +0100494 if (log_location.paths.count && ((const char *)(log_location.paths.objs[log_location.paths.count - 1]))[0]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100495 /* simply get what is in the provided path string */
Radek Krejciddace2c2021-01-08 11:30:56 +0100496 *path = strdup((const char *)log_location.paths.objs[log_location.paths.count - 1]);
Radek Krejcic04f0a22018-09-21 15:49:45 +0200497 LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100498 } else {
499 /* generate location string */
Radek Krejciddace2c2021-01-08 11:30:56 +0100500 if (log_location.scnodes.count) {
501 str = lysc_path(log_location.scnodes.objs[log_location.scnodes.count - 1], LYSC_PATH_LOG, NULL, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100502 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
503
504 rc = asprintf(path, "Schema location %s", str);
505 free(str);
506 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
507 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100508 if (log_location.dnodes.count) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100509 prev = *path;
Radek Krejciddace2c2021-01-08 11:30:56 +0100510 str = lyd_path(log_location.dnodes.objs[log_location.dnodes.count - 1], LYD_PATH_STD, NULL, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100511 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
512
513 rc = asprintf(path, "%s%sata location %s", prev ? prev : "", prev ? ", d" : "D", str);
514 free(str);
515 free(prev);
516 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
517 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100518 if (log_location.line) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100519 prev = *path;
Radek Krejciddace2c2021-01-08 11:30:56 +0100520 rc = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L", log_location.line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100521 free(prev);
522 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
523
Radek Krejciddace2c2021-01-08 11:30:56 +0100524 log_location.line = 0;
525 } else if (log_location.inputs.count) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100526 prev = *path;
527 rc = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L",
Radek Krejciddace2c2021-01-08 11:30:56 +0100528 ((struct ly_in *)log_location.inputs.objs[log_location.inputs.count - 1])->line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100529 free(prev);
530 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
531 }
532
533 if (*path) {
534 prev = *path;
535 rc = asprintf(path, "%s.", prev);
536 free(prev);
537 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
538 }
Radek Krejci94aa9942018-09-07 17:12:17 +0200539 }
540
Radek Krejci94aa9942018-09-07 17:12:17 +0200541 return LY_SUCCESS;
542}
543
544void
Radek Krejci2efc45b2020-12-22 16:25:44 +0100545ly_vlog(const struct ly_ctx *ctx, LY_VECODE code, const char *format, ...)
Radek Krejci94aa9942018-09-07 17:12:17 +0200546{
547 va_list ap;
Michal Vasko22df3f02020-08-24 13:29:22 +0200548 char *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200549
Radek Krejci2efc45b2020-12-22 16:25:44 +0100550 if (path_flag && ctx) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100551 ly_vlog_build_path(ctx, &path);
Radek Krejci94aa9942018-09-07 17:12:17 +0200552 }
553
554 va_start(ap, format);
555 log_vprintf(ctx, LY_LLERR, LY_EVALID, code, path, format, ap);
556 /* path is spent and should not be freed! */
557 va_end(ap);
558}
559
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200560API void
Radek Krejci0935f412019-08-20 16:15:18 +0200561lyext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path, const char *format, ...)
562{
563 va_list ap;
564 char *plugin_msg;
565 int ret;
566
Radek Krejci52b6d512020-10-12 12:33:17 +0200567 if (ly_ll < level) {
Radek Krejci0935f412019-08-20 16:15:18 +0200568 return;
569 }
570 ret = asprintf(&plugin_msg, "Extension plugin \"%s\": %s)", ext->def->plugin->id, format);
571 if (ret == -1) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200572 LOGMEM(ext->module->ctx);
Radek Krejci0935f412019-08-20 16:15:18 +0200573 return;
574 }
575
576 va_start(ap, format);
Radek Krejcia4614e62020-05-15 14:19:28 +0200577 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 +0200578 va_end(ap);
579
580 free(plugin_msg);
581}
582
Michal Vasko177d0ed2020-11-23 16:43:03 +0100583/**
584 * @brief Exact same functionality as ::ly_err_print() but has variable arguments so va_start() can
585 * be used and an empty va_list created.
586 */
587static void
588_ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem, ...)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200589{
Michal Vasko177d0ed2020-11-23 16:43:03 +0100590 va_list ap;
591 char *path_dup = NULL;
592
593 LY_CHECK_ARG_RET(ctx, eitem, );
594
595 if (eitem->path) {
596 /* duplicate path because it will be freed */
597 path_dup = strdup(eitem->path);
598 LY_CHECK_ERR_RET(!path_dup, LOGMEM(ctx), );
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200599 }
Michal Vasko177d0ed2020-11-23 16:43:03 +0100600
601 va_start(ap, eitem);
602 log_vprintf(ctx, eitem->level, eitem->no, eitem->vecode, eitem->path, eitem->msg, ap);
603 va_end(ap);
604
605 if (path_dup) {
606 eitem->path = path_dup;
607 }
608}
609
610API void
611ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem)
612{
613 _ly_err_print(ctx, eitem);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200614}