blob: af28cdff2982728a60c1f3e3319fdc66d6928547 [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 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
121API struct ly_err_item *
Radek Krejcie7b95092019-05-15 11:03:07 +0200122ly_err_new(LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
123{
124 struct ly_err_item *eitem;
125
126 eitem = malloc(sizeof *eitem);
127 LY_CHECK_ERR_RET(!eitem, LOGMEM(NULL), NULL);
128 eitem->prev = eitem;
129 eitem->next = NULL;
130
131 /* fill in the information */
132 eitem->level = level;
133 eitem->no = no;
134 eitem->vecode = vecode;
135 eitem->msg = msg;
136 eitem->path = path;
137 eitem->apptag = apptag;
138
139 return eitem;
140}
141
142API struct ly_err_item *
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200143ly_err_first(const struct ly_ctx *ctx)
144{
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200145 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200146
147 return pthread_getspecific(ctx->errlist_key);
148}
149
Radek Krejci572ee602020-09-16 14:35:08 +0200150API struct ly_err_item *
151ly_err_last(const struct ly_ctx *ctx)
152{
153 const struct ly_err_item *e;
154
155 LY_CHECK_ARG_RET(NULL, ctx, NULL);
156
157 e = pthread_getspecific(ctx->errlist_key);
158 return e ? e->prev : NULL;
159}
160
Radek Krejcie7b95092019-05-15 11:03:07 +0200161API void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200162ly_err_free(void *ptr)
163{
164 struct ly_err_item *i, *next;
165
166 /* clean the error list */
167 for (i = (struct ly_err_item *)ptr; i; i = next) {
168 next = i->next;
Radek Krejcie2692202020-12-01 14:21:12 +0100169 if (i->msg && strcmp(i->msg, LY_EMEM_MSG)) {
170 free(i->msg);
171 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200172 free(i->path);
173 free(i->apptag);
174 free(i);
175 }
176}
177
178API void
179ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
180{
181 struct ly_err_item *i, *first;
182
183 first = ly_err_first(ctx);
184 if (first == eitem) {
185 eitem = NULL;
186 }
187 if (eitem) {
188 /* disconnect the error */
Radek Krejci1e008d22020-08-17 11:37:37 +0200189 for (i = first; i && (i->next != eitem); i = i->next) {}
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200190 assert(i);
191 i->next = NULL;
192 first->prev = i;
193 /* free this err and newer */
194 ly_err_free(eitem);
195 } else {
196 /* free all err */
197 ly_err_free(first);
198 pthread_setspecific(ctx->errlist_key, NULL);
199 }
200}
201
202API LY_LOG_LEVEL
Radek Krejci52b6d512020-10-12 12:33:17 +0200203ly_log_level(LY_LOG_LEVEL level)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200204{
Radek Krejci52b6d512020-10-12 12:33:17 +0200205 LY_LOG_LEVEL prev = ly_ll;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200206
Radek Krejci52b6d512020-10-12 12:33:17 +0200207 ly_ll = level;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200208 return prev;
209}
210
Radek Krejci1deb5be2020-08-26 16:43:36 +0200211API uint32_t
212ly_log_options(uint32_t opts)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200213{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200214 uint32_t prev = ly_log_opts;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200215
216 ly_log_opts = opts;
217 return prev;
218}
219
Radek Krejciebdaed02020-11-09 13:05:06 +0100220API uint32_t
Radek Krejci68433c92020-10-12 17:03:55 +0200221ly_log_dbg_groups(uint32_t dbg_groups)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200222{
223#ifndef NDEBUG
Radek Krejciebdaed02020-11-09 13:05:06 +0100224 uint32_t prev = ly_ldbg_groups;
225
Radek Krejci68433c92020-10-12 17:03:55 +0200226 ly_ldbg_groups = dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100227 return prev;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200228#else
229 (void)dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100230 return 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200231#endif
232}
233
234API void
Radek Krejci857189e2020-09-01 13:26:36 +0200235ly_set_log_clb(ly_log_clb clb, ly_bool path)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200236{
Michal Vaskod8085612020-08-21 12:55:23 +0200237 log_clb = clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200238 path_flag = path;
239}
240
Michal Vaskod8085612020-08-21 12:55:23 +0200241API ly_log_clb
242ly_get_log_clb(void)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200243{
Michal Vaskod8085612020-08-21 12:55:23 +0200244 return log_clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200245}
246
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100247void
Radek Krejciddace2c2021-01-08 11:30:56 +0100248ly_log_location(const struct lysc_node *scnode, const struct lyd_node *dnode,
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100249 const char *path, const struct ly_in *in, uint64_t line, ly_bool reset)
250{
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100251 if (scnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100252 ly_set_add(&log_location.scnodes, (void *)scnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100253 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100254 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100255 }
256
257 if (dnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100258 ly_set_add(&log_location.dnodes, (void *)dnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100259 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100260 ly_set_erase(&log_location.dnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100261 }
262
263 if (path) {
264 char *s = strdup(path);
Radek Krejciddace2c2021-01-08 11:30:56 +0100265 LY_CHECK_ERR_RET(!s, LOGMEM(NULL), );
266 ly_set_add(&log_location.paths, s, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100267 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100268 ly_set_erase(&log_location.paths, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100269 }
270
271 if (in) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100272 ly_set_add(&log_location.inputs, (void *)in, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100273 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100274 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100275 }
276
277 if (line) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100278 log_location.line = line;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100279 }
280}
281
282void
Radek Krejciddace2c2021-01-08 11:30:56 +0100283ly_log_location_revert(uint32_t scnode_steps, uint32_t dnode_steps,
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100284 uint32_t path_steps, uint32_t in_steps)
285{
Radek Krejciddace2c2021-01-08 11:30:56 +0100286 for (uint32_t i = scnode_steps; i && log_location.scnodes.count; i--) {
287 log_location.scnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100288 }
289
Radek Krejciddace2c2021-01-08 11:30:56 +0100290 for (uint32_t i = dnode_steps; i && log_location.dnodes.count; i--) {
291 log_location.dnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100292 }
293
Radek Krejciddace2c2021-01-08 11:30:56 +0100294 for (uint32_t i = path_steps; i && log_location.paths.count; i--) {
295 ly_set_rm_index(&log_location.paths, log_location.paths.count - 1, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100296 }
297
Radek Krejciddace2c2021-01-08 11:30:56 +0100298 for (uint32_t i = in_steps; i && log_location.inputs.count; i--) {
299 log_location.inputs.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100300 }
301
Radek Krejciddace2c2021-01-08 11:30:56 +0100302 /* deallocate the empty sets */
303 if (scnode_steps && !log_location.scnodes.count) {
304 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100305 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100306 if (dnode_steps && !log_location.dnodes.count) {
307 ly_set_erase(&log_location.dnodes, NULL);
308 }
309 if (path_steps && !log_location.paths.count) {
310 ly_set_erase(&log_location.paths, free);
311 }
312 if (in_steps && !log_location.inputs.count) {
313 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100314 }
315}
316
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200317static LY_ERR
318log_store(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
319{
320 struct ly_err_item *eitem, *last;
321
322 assert(ctx && (level < LY_LLVRB));
323
324 eitem = pthread_getspecific(ctx->errlist_key);
325 if (!eitem) {
326 /* if we are only to fill in path, there must have been an error stored */
327 assert(msg);
328 eitem = malloc(sizeof *eitem);
329 LY_CHECK_GOTO(!eitem, mem_fail);
330 eitem->prev = eitem;
331 eitem->next = NULL;
332
333 pthread_setspecific(ctx->errlist_key, eitem);
334 } else if (!msg) {
335 /* only filling the path */
336 assert(path);
337
338 /* find last error */
339 eitem = eitem->prev;
340 do {
341 if (eitem->level == LY_LLERR) {
342 /* fill the path */
343 free(eitem->path);
344 eitem->path = path;
345 return LY_SUCCESS;
346 }
347 eitem = eitem->prev;
348 } while (eitem->prev->next);
349 /* last error was not found */
350 assert(0);
Michal Vaskoed94a292019-11-06 15:43:41 +0100351 } else if ((ly_log_opts & LY_LOSTORE_LAST) == LY_LOSTORE_LAST) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200352 /* overwrite last message */
353 free(eitem->msg);
354 free(eitem->path);
355 free(eitem->apptag);
356 } else {
357 /* store new message */
358 last = eitem->prev;
359 eitem->prev = malloc(sizeof *eitem);
360 LY_CHECK_GOTO(!eitem->prev, mem_fail);
361 eitem = eitem->prev;
362 eitem->prev = last;
363 eitem->next = NULL;
364 last->next = eitem;
365 }
366
367 /* fill in the information */
368 eitem->level = level;
369 eitem->no = no;
370 eitem->vecode = vecode;
371 eitem->msg = msg;
372 eitem->path = path;
373 eitem->apptag = apptag;
374 return LY_SUCCESS;
375
376mem_fail:
377 LOGMEM(NULL);
378 free(msg);
379 free(path);
380 free(apptag);
381 return LY_EMEM;
382}
383
384static void
385log_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 +0200386 const char *format, va_list args)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200387{
388 char *msg = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200389 ly_bool free_strs;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200390
Radek Krejci52b6d512020-10-12 12:33:17 +0200391 if (level > ly_ll) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200392 /* do not print or store the message */
393 free(path);
394 return;
395 }
396
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200397 /* 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 +0100398 if ((level < LY_LLVRB) && ctx && (ly_log_opts & LY_LOSTORE)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200399 assert(format);
400 if (vasprintf(&msg, format, args) == -1) {
401 LOGMEM(ctx);
402 free(path);
403 return;
404 }
Radek Krejcic9e64a62020-09-18 20:08:12 +0200405 if (((no & ~LY_EPLUGIN) == LY_EVALID) && (vecode == LYVE_SUCCESS)) {
406 /* assume we are inheriting the error, so inherit vecode as well */
407 vecode = ly_vecode(ctx);
408 }
Michal Vasko004d3152020-06-11 19:59:22 +0200409 if (log_store(ctx, level, no, vecode, msg, path, NULL)) {
410 return;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200411 }
412 free_strs = 0;
413 } else {
414 if (vasprintf(&msg, format, args) == -1) {
415 LOGMEM(ctx);
416 free(path);
417 return;
418 }
419 free_strs = 1;
420 }
421
422 /* if we are only storing errors internally, never print the message (yet) */
Michal Vaskoed94a292019-11-06 15:43:41 +0100423 if (ly_log_opts & LY_LOLOG) {
Michal Vaskod8085612020-08-21 12:55:23 +0200424 if (log_clb) {
425 log_clb(level, msg, path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200426 } else {
427 fprintf(stderr, "libyang[%d]: %s%s", level, msg, path ? " " : "\n");
428 if (path) {
429 fprintf(stderr, "(path: %s)\n", path);
430 }
431 }
432 }
433
434 if (free_strs) {
435 free(path);
436 free(msg);
437 }
438}
439
Radek Krejci4ab61562018-09-05 15:00:37 +0200440#ifndef NDEBUG
441
442void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200443ly_log_dbg(uint32_t group, const char *format, ...)
Radek Krejci4ab61562018-09-05 15:00:37 +0200444{
445 char *dbg_format;
446 const char *str_group;
447 va_list ap;
448
Radek Krejci68433c92020-10-12 17:03:55 +0200449 if (!(ly_ldbg_groups & group)) {
Radek Krejci4ab61562018-09-05 15:00:37 +0200450 return;
451 }
452
453 switch (group) {
454 case LY_LDGDICT:
455 str_group = "DICT";
456 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200457 case LY_LDGXPATH:
458 str_group = "XPATH";
459 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200460 default:
461 LOGINT(NULL);
462 return;
463 }
464
465 if (asprintf(&dbg_format, "%s: %s", str_group, format) == -1) {
466 LOGMEM(NULL);
467 return;
468 }
469
470 va_start(ap, format);
471 log_vprintf(NULL, LY_LLDBG, 0, 0, NULL, dbg_format, ap);
472 va_end(ap);
473}
474
475#endif
476
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200477void
478ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...)
479{
480 va_list ap;
481
482 va_start(ap, format);
483 log_vprintf(ctx, level, no, 0, NULL, format, ap);
484 va_end(ap);
485}
486
Radek Krejci94aa9942018-09-07 17:12:17 +0200487static LY_ERR
Radek Krejciddace2c2021-01-08 11:30:56 +0100488ly_vlog_build_path(const struct ly_ctx *ctx, char **path)
Radek Krejci94aa9942018-09-07 17:12:17 +0200489{
Radek Krejcic04f0a22018-09-21 15:49:45 +0200490 int rc;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100491 char *str = NULL, *prev = NULL;
Radek Krejcicb3e6472021-01-06 08:19:01 +0100492
Radek Krejci2efc45b2020-12-22 16:25:44 +0100493 *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200494
Radek Krejciddace2c2021-01-08 11:30:56 +0100495 if (log_location.paths.count && ((const char *)(log_location.paths.objs[log_location.paths.count - 1]))[0]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100496 /* simply get what is in the provided path string */
Radek Krejciddace2c2021-01-08 11:30:56 +0100497 *path = strdup((const char *)log_location.paths.objs[log_location.paths.count - 1]);
Radek Krejcic04f0a22018-09-21 15:49:45 +0200498 LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100499 } else {
500 /* generate location string */
Radek Krejciddace2c2021-01-08 11:30:56 +0100501 if (log_location.scnodes.count) {
502 str = lysc_path(log_location.scnodes.objs[log_location.scnodes.count - 1], LYSC_PATH_LOG, NULL, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100503 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
504
505 rc = asprintf(path, "Schema location %s", str);
506 free(str);
507 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
508 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100509 if (log_location.dnodes.count) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100510 prev = *path;
Radek Krejciddace2c2021-01-08 11:30:56 +0100511 str = lyd_path(log_location.dnodes.objs[log_location.dnodes.count - 1], LYD_PATH_STD, NULL, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100512 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
513
514 rc = asprintf(path, "%s%sata location %s", prev ? prev : "", prev ? ", d" : "D", str);
515 free(str);
516 free(prev);
517 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
518 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100519 if (log_location.line) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100520 prev = *path;
Radek Krejciddace2c2021-01-08 11:30:56 +0100521 rc = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L", log_location.line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100522 free(prev);
523 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
524
Radek Krejciddace2c2021-01-08 11:30:56 +0100525 log_location.line = 0;
526 } else if (log_location.inputs.count) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100527 prev = *path;
528 rc = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L",
Radek Krejciddace2c2021-01-08 11:30:56 +0100529 ((struct ly_in *)log_location.inputs.objs[log_location.inputs.count - 1])->line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100530 free(prev);
531 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
532 }
533
534 if (*path) {
535 prev = *path;
536 rc = asprintf(path, "%s.", prev);
537 free(prev);
538 LY_CHECK_ERR_RET(rc == -1, LOGMEM(ctx), LY_EMEM);
539 }
Radek Krejci94aa9942018-09-07 17:12:17 +0200540 }
541
Radek Krejci94aa9942018-09-07 17:12:17 +0200542 return LY_SUCCESS;
543}
544
545void
Radek Krejci2efc45b2020-12-22 16:25:44 +0100546ly_vlog(const struct ly_ctx *ctx, LY_VECODE code, const char *format, ...)
Radek Krejci94aa9942018-09-07 17:12:17 +0200547{
548 va_list ap;
Michal Vasko22df3f02020-08-24 13:29:22 +0200549 char *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200550
Radek Krejci2efc45b2020-12-22 16:25:44 +0100551 if (path_flag && ctx) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100552 ly_vlog_build_path(ctx, &path);
Radek Krejci94aa9942018-09-07 17:12:17 +0200553 }
554
555 va_start(ap, format);
556 log_vprintf(ctx, LY_LLERR, LY_EVALID, code, path, format, ap);
557 /* path is spent and should not be freed! */
558 va_end(ap);
559}
560
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200561API void
Radek Krejci0935f412019-08-20 16:15:18 +0200562lyext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path, const char *format, ...)
563{
564 va_list ap;
565 char *plugin_msg;
566 int ret;
567
Radek Krejci52b6d512020-10-12 12:33:17 +0200568 if (ly_ll < level) {
Radek Krejci0935f412019-08-20 16:15:18 +0200569 return;
570 }
Radek Krejci932d3bb2021-02-09 16:29:38 +0100571 ret = asprintf(&plugin_msg, "Extension plugin \"%s\": %s", ext->def->plugin->id, format);
Radek Krejci0935f412019-08-20 16:15:18 +0200572 if (ret == -1) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200573 LOGMEM(ext->module->ctx);
Radek Krejci0935f412019-08-20 16:15:18 +0200574 return;
575 }
576
577 va_start(ap, format);
Radek Krejcia4614e62020-05-15 14:19:28 +0200578 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 +0200579 va_end(ap);
580
581 free(plugin_msg);
582}
583
Michal Vasko177d0ed2020-11-23 16:43:03 +0100584/**
585 * @brief Exact same functionality as ::ly_err_print() but has variable arguments so va_start() can
586 * be used and an empty va_list created.
587 */
588static void
589_ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem, ...)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200590{
Michal Vasko177d0ed2020-11-23 16:43:03 +0100591 va_list ap;
592 char *path_dup = NULL;
593
594 LY_CHECK_ARG_RET(ctx, eitem, );
595
596 if (eitem->path) {
597 /* duplicate path because it will be freed */
598 path_dup = strdup(eitem->path);
599 LY_CHECK_ERR_RET(!path_dup, LOGMEM(ctx), );
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200600 }
Michal Vasko177d0ed2020-11-23 16:43:03 +0100601
602 va_start(ap, eitem);
603 log_vprintf(ctx, eitem->level, eitem->no, eitem->vecode, eitem->path, eitem->msg, ap);
604 va_end(ap);
605
606 if (path_dup) {
607 eitem->path = path_dup;
608 }
609}
610
611API void
612ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem)
613{
614 _ly_err_print(ctx, eitem);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200615}