blob: 9cb60b3efbeb340c4a5025abece6539e37143409 [file] [log] [blame]
Radek Krejci5aeea3a2018-09-05 13:29:36 +02001/**
2 * @file log.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko193dacd2022-10-13 08:43:05 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
Radek Krejci5aeea3a2018-09-05 13:29:36 +02005 * @brief Logger routines implementations
6 *
Michal Vaskob5b883c2023-07-10 10:36:18 +02007 * Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
Radek Krejci5aeea3a2018-09-05 13:29:36 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
Christian Hopps32874e12021-05-01 09:43:54 -040016#define _GNU_SOURCE /* asprintf, 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 Krejciaa45bda2020-07-20 07:43:38 +020029#include "compat.h"
Radek Krejciaddfc9a2020-12-17 20:46:35 +010030#include "in_internal.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010031#include "ly_common.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"
Michal Vaskodbf3e652022-10-21 08:46:25 +020035#include "tree_data_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "tree_schema.h"
Michal Vasko193dacd2022-10-13 08:43:05 +020037#include "tree_schema_internal.h"
Radek Krejci5aeea3a2018-09-05 13:29:36 +020038
Václav Kubernátd367ad92021-11-29 09:28:56 +010039ATOMIC_T ly_ll = (uint_fast32_t)LY_LLWRN;
40ATOMIC_T ly_log_opts = (uint_fast32_t)(LY_LOLOG | LY_LOSTORE_LAST);
Michal Vaskod4a6d042022-12-08 08:34:29 +010041THREAD_LOCAL uint32_t *temp_ly_log_opts;
Michal Vaskod8085612020-08-21 12:55:23 +020042static ly_log_clb log_clb;
Michal Vasko236cbac2023-02-10 15:45:37 +010043THREAD_LOCAL char last_msg[LY_LAST_MSG_SIZE];
Radek Krejci5aeea3a2018-09-05 13:29:36 +020044#ifndef NDEBUG
Václav Kubernátd367ad92021-11-29 09:28:56 +010045ATOMIC_T ly_ldbg_groups = 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020046#endif
47
Radek Krejciddace2c2021-01-08 11:30:56 +010048THREAD_LOCAL struct ly_log_location_s log_location = {0};
49
Michal Vaskob5b883c2023-07-10 10:36:18 +020050LIBYANG_API_DEF const char *
Michal Vasko7a266772024-01-23 11:02:38 +010051ly_strerr(LY_ERR err)
Michal Vaskob5b883c2023-07-10 10:36:18 +020052{
53 /* ignore plugin flag */
54 err &= ~LY_EPLUGIN;
55
56 switch (err) {
57 case LY_SUCCESS:
Michal Vaskoe4207652023-07-10 14:57:32 +020058 return "Success";
Michal Vaskob5b883c2023-07-10 10:36:18 +020059 case LY_EMEM:
60 return "Out of memory";
61 case LY_ESYS:
62 return "System call failed";
63 case LY_EINVAL:
64 return "Invalid value";
65 case LY_EEXIST:
66 return "Already exists";
67 case LY_ENOTFOUND:
68 return "Not found";
69 case LY_EINT:
70 return "Internal error";
71 case LY_EVALID:
72 return "Validation failed";
73 case LY_EDENIED:
74 return "Operation denied";
75 case LY_EINCOMPLETE:
76 return "Operation incomplete";
77 case LY_ERECOMPILE:
78 return "Recompilation required";
79 case LY_ENOT:
80 return "Negative result";
81 case LY_EOTHER:
82 return "Another failure reason";
83 case LY_EPLUGIN:
84 break;
85 }
86
87 /* unreachable */
Michal Vaskob87e9a12023-07-10 15:10:58 +020088 return "Unknown";
Michal Vaskob5b883c2023-07-10 10:36:18 +020089}
90
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010091LIBYANG_API_DEF const char *
Michal Vaskob5b883c2023-07-10 10:36:18 +020092ly_strvecode(LY_VECODE vecode)
93{
94 switch (vecode) {
95 case LYVE_SUCCESS:
Michal Vaskoe4207652023-07-10 14:57:32 +020096 return "Success";
Michal Vaskob5b883c2023-07-10 10:36:18 +020097 case LYVE_SYNTAX:
98 return "General syntax error";
99 case LYVE_SYNTAX_YANG:
100 return "YANG syntax error";
101 case LYVE_SYNTAX_YIN:
102 return "YIN syntax error";
103 case LYVE_REFERENCE:
104 return "Reference error";
105 case LYVE_XPATH:
106 return "XPath error";
107 case LYVE_SEMANTICS:
108 return "Semantic error";
109 case LYVE_SYNTAX_XML:
110 return "XML syntax error";
111 case LYVE_SYNTAX_JSON:
112 return "JSON syntax error";
113 case LYVE_DATA:
114 return "YANG data error";
115 case LYVE_OTHER:
116 return "Another error";
117 }
118
119 /* unreachable */
Michal Vaskob87e9a12023-07-10 15:10:58 +0200120 return "Unknown";
Michal Vaskob5b883c2023-07-10 10:36:18 +0200121}
122
123LIBYANG_API_DEF const char *
Michal Vasko7a266772024-01-23 11:02:38 +0100124ly_last_logmsg(void)
Michal Vaskob5b883c2023-07-10 10:36:18 +0200125{
126 return last_msg;
127}
128
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100129LIBYANG_API_DEF LY_ERR
Michal Vasko7a266772024-01-23 11:02:38 +0100130ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *data_path, char *apptag,
131 const char *err_format, ...)
Radek Krejcie7b95092019-05-15 11:03:07 +0200132{
Radek Krejcidb0ee022021-03-15 16:53:44 +0100133 char *msg = NULL;
134 struct ly_err_item *e;
Radek Krejcie7b95092019-05-15 11:03:07 +0200135
Radek Krejcid43298b2021-03-25 16:17:15 +0100136 if (!err || (ecode == LY_SUCCESS)) {
Radek Krejcidb0ee022021-03-15 16:53:44 +0100137 /* nothing to do */
138 return ecode;
139 }
140
Michal Vasko7a266772024-01-23 11:02:38 +0100141 e = calloc(1, sizeof *e);
Radek Krejcidb0ee022021-03-15 16:53:44 +0100142 LY_CHECK_ERR_RET(!e, LOGMEM(NULL), LY_EMEM);
Michal Vasko7a266772024-01-23 11:02:38 +0100143
Radek Krejcidb0ee022021-03-15 16:53:44 +0100144 e->prev = (*err) ? (*err)->prev : e;
Radek Krejcidb0ee022021-03-15 16:53:44 +0100145 if (*err) {
146 (*err)->prev->next = e;
147 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200148
149 /* fill in the information */
Radek Krejcidb0ee022021-03-15 16:53:44 +0100150 e->level = LY_LLERR;
Michal Vasko7a266772024-01-23 11:02:38 +0100151 e->err = ecode;
Radek Krejcidb0ee022021-03-15 16:53:44 +0100152 e->vecode = vecode;
Michal Vasko7a266772024-01-23 11:02:38 +0100153 e->data_path = data_path;
Radek Krejcidb0ee022021-03-15 16:53:44 +0100154 e->apptag = apptag;
Radek Krejcie7b95092019-05-15 11:03:07 +0200155
aPiecek6d618552021-06-18 10:02:59 +0200156 if (err_format) {
Radek Krejcidb0ee022021-03-15 16:53:44 +0100157 va_list print_args;
158
aPiecek6d618552021-06-18 10:02:59 +0200159 va_start(print_args, err_format);
Radek Krejcidb0ee022021-03-15 16:53:44 +0100160
aPiecek6d618552021-06-18 10:02:59 +0200161 if (vasprintf(&msg, err_format, print_args) == -1) {
162 /* we don't have anything more to do, just set msg to NULL to avoid undefined content,
Radek Krejcidb0ee022021-03-15 16:53:44 +0100163 * still keep the information about the original error instead of LY_EMEM or other printf's error */
164 msg = NULL;
165 }
166
167 va_end(print_args);
168 }
169 e->msg = msg;
170
171 if (!(*err)) {
172 *err = e;
173 }
174
Michal Vasko7a266772024-01-23 11:02:38 +0100175 return e->err;
Radek Krejcie7b95092019-05-15 11:03:07 +0200176}
177
Michal Vasko88ccd582023-03-30 11:50:57 +0200178/**
179 * @brief Get error record from error hash table of a context for the current thread.
180 *
181 * @param[in] ctx Context to use.
182 * @return Thread error record, if any.
183 */
184static struct ly_ctx_err_rec *
185ly_err_get_rec(const struct ly_ctx *ctx)
186{
Michal Vasko4cca0092023-03-30 13:20:53 +0200187 struct ly_ctx_err_rec rec, *match;
Michal Vasko88ccd582023-03-30 11:50:57 +0200188
189 /* prepare record */
190 rec.tid = pthread_self();
191
Michal Vasko2addf212024-08-16 15:48:36 +0200192 /* reuse lock */
193 /* LOCK */
194 pthread_mutex_lock((pthread_mutex_t *)&ctx->lyb_hash_lock);
195
Michal Vasko88ccd582023-03-30 11:50:57 +0200196 /* get the pointer to the matching record */
Michal Vasko2addf212024-08-16 15:48:36 +0200197 lyht_find(ctx->err_ht, &rec, lyht_hash((void *)&rec.tid, sizeof rec.tid), (void **)&match);
198
199 /* UNLOCK */
200 pthread_mutex_unlock((pthread_mutex_t *)&ctx->lyb_hash_lock);
Michal Vasko88ccd582023-03-30 11:50:57 +0200201
202 return match;
203}
204
Michal Vaskoe0be7452023-03-30 13:35:35 +0200205/**
206 * @brief Insert new error record to error hash table of a context for the current thread.
207 *
208 * @param[in] ctx Context to use.
209 * @return Thread error record.
210 */
211static struct ly_ctx_err_rec *
212ly_err_new_rec(const struct ly_ctx *ctx)
213{
214 struct ly_ctx_err_rec new, *rec;
215 LY_ERR r;
216
217 /* insert a new record */
218 new.err = NULL;
219 new.tid = pthread_self();
220
221 /* reuse lock */
222 /* LOCK */
223 pthread_mutex_lock((pthread_mutex_t *)&ctx->lyb_hash_lock);
224
Michal Vaskoae130f52023-04-20 14:25:16 +0200225 r = lyht_insert(ctx->err_ht, &new, lyht_hash((void *)&new.tid, sizeof new.tid), (void **)&rec);
Michal Vaskoe0be7452023-03-30 13:35:35 +0200226
227 /* UNLOCK */
228 pthread_mutex_unlock((pthread_mutex_t *)&ctx->lyb_hash_lock);
229
230 return r ? NULL : rec;
231}
232
Michal Vasko7a266772024-01-23 11:02:38 +0100233LIBYANG_API_DEF const struct ly_err_item *
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200234ly_err_first(const struct ly_ctx *ctx)
235{
Michal Vasko88ccd582023-03-30 11:50:57 +0200236 struct ly_ctx_err_rec *rec;
237
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200238 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200239
Michal Vasko88ccd582023-03-30 11:50:57 +0200240 /* get the pointer to the matching record */
241 rec = ly_err_get_rec(ctx);
242
243 return rec ? rec->err : NULL;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200244}
245
Michal Vasko7a266772024-01-23 11:02:38 +0100246LIBYANG_API_DEF const struct ly_err_item *
Radek Krejci572ee602020-09-16 14:35:08 +0200247ly_err_last(const struct ly_ctx *ctx)
248{
Michal Vasko88ccd582023-03-30 11:50:57 +0200249 struct ly_ctx_err_rec *rec;
Radek Krejci572ee602020-09-16 14:35:08 +0200250
251 LY_CHECK_ARG_RET(NULL, ctx, NULL);
252
Michal Vasko88ccd582023-03-30 11:50:57 +0200253 /* get the pointer to the matching record */
254 if (!(rec = ly_err_get_rec(ctx))) {
255 return NULL;
256 }
257
258 return rec->err ? rec->err->prev : NULL;
Radek Krejci572ee602020-09-16 14:35:08 +0200259}
260
Michal Vasko9dbb91d2023-01-30 13:59:22 +0100261void
262ly_err_move(struct ly_ctx *src_ctx, struct ly_ctx *trg_ctx)
263{
Michal Vasko88ccd582023-03-30 11:50:57 +0200264 struct ly_ctx_err_rec *rec;
265 struct ly_err_item *err = NULL;
Michal Vasko9dbb91d2023-01-30 13:59:22 +0100266
Michal Vasko88ccd582023-03-30 11:50:57 +0200267 /* get and remove the errors from src */
268 rec = ly_err_get_rec(src_ctx);
269 if (rec) {
270 err = rec->err;
271 rec->err = NULL;
272 }
Michal Vasko9dbb91d2023-01-30 13:59:22 +0100273
274 /* set them for trg */
Michal Vaskoe0be7452023-03-30 13:35:35 +0200275 if (!(rec = ly_err_get_rec(trg_ctx))) {
276 if (!(rec = ly_err_new_rec(trg_ctx))) {
277 LOGINT(NULL);
278 ly_err_free(err);
279 return;
280 }
281 }
Michal Vasko88ccd582023-03-30 11:50:57 +0200282 ly_err_free(rec->err);
283 rec->err = err;
Michal Vasko9dbb91d2023-01-30 13:59:22 +0100284}
285
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100286LIBYANG_API_DEF void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200287ly_err_free(void *ptr)
288{
Michal Vasko88ccd582023-03-30 11:50:57 +0200289 struct ly_err_item *e, *next;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200290
291 /* clean the error list */
Michal Vasko88ccd582023-03-30 11:50:57 +0200292 LY_LIST_FOR_SAFE(ptr, next, e) {
293 free(e->msg);
Michal Vasko7a266772024-01-23 11:02:38 +0100294 free(e->data_path);
295 free(e->schema_path);
Michal Vasko88ccd582023-03-30 11:50:57 +0200296 free(e->apptag);
297 free(e);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200298 }
299}
300
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100301LIBYANG_API_DEF void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200302ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
303{
Michal Vasko88ccd582023-03-30 11:50:57 +0200304 struct ly_ctx_err_rec *rec;
305 struct ly_err_item *e;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200306
Michal Vasko88ccd582023-03-30 11:50:57 +0200307 if (!(rec = ly_err_get_rec(ctx))) {
308 return;
309 }
310 if (rec->err == eitem) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200311 eitem = NULL;
312 }
Michal Vasko88ccd582023-03-30 11:50:57 +0200313
314 if (!eitem) {
315 /* free all err */
316 ly_err_free(rec->err);
317 rec->err = NULL;
318 } else {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200319 /* disconnect the error */
Michal Vasko88ccd582023-03-30 11:50:57 +0200320 for (e = rec->err; e && (e->next != eitem); e = e->next) {}
321 assert(e);
322 e->next = NULL;
323 rec->err->prev = e;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200324 /* free this err and newer */
325 ly_err_free(eitem);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200326 }
327}
328
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100329LIBYANG_API_DEF LY_LOG_LEVEL
Radek Krejci52b6d512020-10-12 12:33:17 +0200330ly_log_level(LY_LOG_LEVEL level)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200331{
Václav Kubernátd367ad92021-11-29 09:28:56 +0100332 LY_LOG_LEVEL prev = ATOMIC_LOAD_RELAXED(ly_ll);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200333
Václav Kubernátd367ad92021-11-29 09:28:56 +0100334 ATOMIC_STORE_RELAXED(ly_ll, level);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200335 return prev;
336}
337
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100338LIBYANG_API_DEF uint32_t
Radek Krejci1deb5be2020-08-26 16:43:36 +0200339ly_log_options(uint32_t opts)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200340{
Václav Kubernátd367ad92021-11-29 09:28:56 +0100341 uint32_t prev = ATOMIC_LOAD_RELAXED(ly_log_opts);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200342
Václav Kubernátd367ad92021-11-29 09:28:56 +0100343 ATOMIC_STORE_RELAXED(ly_log_opts, opts);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200344 return prev;
345}
346
Michal Vasko52da51d2024-01-30 16:09:19 +0100347LIBYANG_API_DEF uint32_t *
Michal Vaskod4a6d042022-12-08 08:34:29 +0100348ly_temp_log_options(uint32_t *opts)
349{
Michal Vasko52da51d2024-01-30 16:09:19 +0100350 uint32_t *prev_lo = temp_ly_log_opts;
351
Michal Vaskod4a6d042022-12-08 08:34:29 +0100352 temp_ly_log_opts = opts;
Michal Vasko52da51d2024-01-30 16:09:19 +0100353
354 return prev_lo;
Michal Vaskod4a6d042022-12-08 08:34:29 +0100355}
356
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100357LIBYANG_API_DEF uint32_t
Radek Krejci68433c92020-10-12 17:03:55 +0200358ly_log_dbg_groups(uint32_t dbg_groups)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200359{
360#ifndef NDEBUG
Václav Kubernátd367ad92021-11-29 09:28:56 +0100361 uint32_t prev = ATOMIC_LOAD_RELAXED(ly_ldbg_groups);
Radek Krejciebdaed02020-11-09 13:05:06 +0100362
Václav Kubernátd367ad92021-11-29 09:28:56 +0100363 ATOMIC_STORE_RELAXED(ly_ldbg_groups, dbg_groups);
Radek Krejciebdaed02020-11-09 13:05:06 +0100364 return prev;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200365#else
366 (void)dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100367 return 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200368#endif
369}
370
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100371LIBYANG_API_DEF void
Michal Vasko7a266772024-01-23 11:02:38 +0100372ly_set_log_clb(ly_log_clb clb)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200373{
Michal Vaskod8085612020-08-21 12:55:23 +0200374 log_clb = clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200375}
376
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100377LIBYANG_API_DEF ly_log_clb
Michal Vaskod8085612020-08-21 12:55:23 +0200378ly_get_log_clb(void)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200379{
Michal Vaskod8085612020-08-21 12:55:23 +0200380 return log_clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200381}
382
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100383void
Michal Vasko7a266772024-01-23 11:02:38 +0100384ly_log_location(const struct lysc_node *scnode, const struct lyd_node *dnode, const char *spath, const struct ly_in *in)
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100385{
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100386 if (scnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100387 ly_set_add(&log_location.scnodes, (void *)scnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100388 }
Michal Vasko7a266772024-01-23 11:02:38 +0100389 if (dnode || (!scnode && !spath && !in)) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100390 ly_set_add(&log_location.dnodes, (void *)dnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100391 }
Michal Vasko7a266772024-01-23 11:02:38 +0100392 if (spath) {
393 char *s = strdup(spath);
Michal Vasko26bbb272022-08-02 14:54:33 +0200394
Radek Krejciddace2c2021-01-08 11:30:56 +0100395 LY_CHECK_ERR_RET(!s, LOGMEM(NULL), );
Michal Vasko7a266772024-01-23 11:02:38 +0100396 ly_set_add(&log_location.spaths, s, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100397 }
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100398 if (in) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100399 ly_set_add(&log_location.inputs, (void *)in, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100400 }
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100401}
402
403void
Michal Vasko7a266772024-01-23 11:02:38 +0100404ly_log_location_revert(uint32_t scnode_steps, uint32_t dnode_steps, uint32_t spath_steps, uint32_t in_steps)
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100405{
Radek Krejciddace2c2021-01-08 11:30:56 +0100406 for (uint32_t i = scnode_steps; i && log_location.scnodes.count; i--) {
407 log_location.scnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100408 }
409
Radek Krejciddace2c2021-01-08 11:30:56 +0100410 for (uint32_t i = dnode_steps; i && log_location.dnodes.count; i--) {
411 log_location.dnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100412 }
413
Michal Vasko7a266772024-01-23 11:02:38 +0100414 for (uint32_t i = spath_steps; i && log_location.spaths.count; i--) {
415 ly_set_rm_index(&log_location.spaths, log_location.spaths.count - 1, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100416 }
417
Radek Krejciddace2c2021-01-08 11:30:56 +0100418 for (uint32_t i = in_steps; i && log_location.inputs.count; i--) {
419 log_location.inputs.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100420 }
421
Radek Krejciddace2c2021-01-08 11:30:56 +0100422 /* deallocate the empty sets */
423 if (scnode_steps && !log_location.scnodes.count) {
424 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100425 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100426 if (dnode_steps && !log_location.dnodes.count) {
427 ly_set_erase(&log_location.dnodes, NULL);
428 }
Michal Vasko7a266772024-01-23 11:02:38 +0100429 if (spath_steps && !log_location.spaths.count) {
430 ly_set_erase(&log_location.spaths, free);
Radek Krejciddace2c2021-01-08 11:30:56 +0100431 }
432 if (in_steps && !log_location.inputs.count) {
433 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100434 }
435}
436
Michal Vaskoa878a892023-08-18 12:22:07 +0200437const struct lyd_node *
438ly_log_location_dnode(uint32_t idx)
439{
440 if (idx < log_location.dnodes.count) {
441 return log_location.dnodes.dnodes[idx];
442 }
443
444 return NULL;
445}
446
447uint32_t
448ly_log_location_dnode_count(void)
449{
450 return log_location.dnodes.count;
451}
452
Michal Vasko88ccd582023-03-30 11:50:57 +0200453/**
454 * @brief Store generated error in a context.
455 *
456 * @param[in] ctx Context to use.
457 * @param[in] level Message log level.
Michal Vasko7a266772024-01-23 11:02:38 +0100458 * @param[in] err Error number.
Michal Vasko88ccd582023-03-30 11:50:57 +0200459 * @param[in] vecode Error validation error code.
460 * @param[in] msg Error message, always spent.
Michal Vasko7a266772024-01-23 11:02:38 +0100461 * @param[in] data_path Error data path, always spent.
462 * @param[in] schema_path Error schema path, always spent.
463 * @param[in] line Error input line, if any.
Michal Vasko88ccd582023-03-30 11:50:57 +0200464 * @param[in] apptag Error app tag, always spent.
465 * @return LY_ERR value.
466 */
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200467static LY_ERR
Michal Vasko7a266772024-01-23 11:02:38 +0100468log_store(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR err, LY_VECODE vecode, char *msg, char *data_path,
469 char *schema_path, uint64_t line, char *apptag)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200470{
Michal Vaskoe0be7452023-03-30 13:35:35 +0200471 struct ly_ctx_err_rec *rec;
Michal Vasko88ccd582023-03-30 11:50:57 +0200472 struct ly_err_item *e, *last;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200473
474 assert(ctx && (level < LY_LLVRB));
475
Michal Vasko88ccd582023-03-30 11:50:57 +0200476 if (!(rec = ly_err_get_rec(ctx))) {
Michal Vaskoe0be7452023-03-30 13:35:35 +0200477 if (!(rec = ly_err_new_rec(ctx))) {
478 goto mem_fail;
Michal Vasko88ccd582023-03-30 11:50:57 +0200479 }
480 }
481
482 e = rec->err;
483 if (!e) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200484 /* if we are only to fill in path, there must have been an error stored */
485 assert(msg);
Michal Vasko7a266772024-01-23 11:02:38 +0100486 e = calloc(1, sizeof *e);
Michal Vasko88ccd582023-03-30 11:50:57 +0200487 LY_CHECK_GOTO(!e, mem_fail);
488 e->prev = e;
489 e->next = NULL;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200490
Michal Vasko88ccd582023-03-30 11:50:57 +0200491 rec->err = e;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200492 } else if (!msg) {
493 /* only filling the path */
Michal Vasko7a266772024-01-23 11:02:38 +0100494 assert(data_path || schema_path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200495
496 /* find last error */
Michal Vasko88ccd582023-03-30 11:50:57 +0200497 e = e->prev;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200498 do {
Michal Vasko88ccd582023-03-30 11:50:57 +0200499 if (e->level == LY_LLERR) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200500 /* fill the path */
Michal Vasko7a266772024-01-23 11:02:38 +0100501 if (data_path) {
502 free(e->data_path);
503 e->data_path = data_path;
504 } else {
505 free(e->schema_path);
506 e->schema_path = schema_path;
507 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200508 return LY_SUCCESS;
509 }
Michal Vasko88ccd582023-03-30 11:50:57 +0200510 e = e->prev;
511 } while (e->prev->next);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200512 /* last error was not found */
513 assert(0);
Michal Vaskod4a6d042022-12-08 08:34:29 +0100514 } else if ((temp_ly_log_opts && ((*temp_ly_log_opts & LY_LOSTORE_LAST) == LY_LOSTORE_LAST)) ||
515 (!temp_ly_log_opts && ((ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE_LAST) == LY_LOSTORE_LAST))) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200516 /* overwrite last message */
Michal Vasko88ccd582023-03-30 11:50:57 +0200517 free(e->msg);
Michal Vasko7a266772024-01-23 11:02:38 +0100518 free(e->data_path);
519 free(e->schema_path);
Michal Vasko88ccd582023-03-30 11:50:57 +0200520 free(e->apptag);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200521 } else {
522 /* store new message */
Michal Vasko88ccd582023-03-30 11:50:57 +0200523 last = e->prev;
Michal Vasko7a266772024-01-23 11:02:38 +0100524 e->prev = calloc(1, sizeof *e);
Michal Vasko88ccd582023-03-30 11:50:57 +0200525 LY_CHECK_GOTO(!e->prev, mem_fail);
526 e = e->prev;
527 e->prev = last;
528 e->next = NULL;
529 last->next = e;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200530 }
531
532 /* fill in the information */
Michal Vasko88ccd582023-03-30 11:50:57 +0200533 e->level = level;
Michal Vasko7a266772024-01-23 11:02:38 +0100534 e->err = err;
Michal Vasko88ccd582023-03-30 11:50:57 +0200535 e->vecode = vecode;
536 e->msg = msg;
Michal Vasko7a266772024-01-23 11:02:38 +0100537 e->data_path = data_path;
538 e->schema_path = schema_path;
539 e->line = line;
Michal Vasko88ccd582023-03-30 11:50:57 +0200540 e->apptag = apptag;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200541 return LY_SUCCESS;
542
543mem_fail:
544 LOGMEM(NULL);
545 free(msg);
Michal Vasko7a266772024-01-23 11:02:38 +0100546 free(data_path);
547 free(schema_path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200548 free(apptag);
549 return LY_EMEM;
550}
551
Michal Vasko7a266772024-01-23 11:02:38 +0100552/**
553 * @brief Log data path/schema path/line to stderr after the message has been printed.
554 *
555 * @param[in] data_path Error data path.
556 * @param[in] schema_path Error schema path.
557 * @param[in] line Error input line.
558 */
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200559static void
Michal Vasko7a266772024-01-23 11:02:38 +0100560log_stderr_path_line(const char *data_path, const char *schema_path, uint64_t line)
561{
562 ly_bool par = 0;
563
564 if (data_path) {
565 fprintf(stderr, "%sdata path: %s", " (", data_path);
566 par = 1;
567 }
568
569 if (schema_path) {
570 fprintf(stderr, "%sschemadata path: %s", par ? ", " : " (", schema_path);
571 par = 1;
572 }
573
574 if (line) {
575 fprintf(stderr, "%sline: %" PRIu64, par ? ", " : " (", line);
576 par = 1;
577 }
578
579 fprintf(stderr, par ? ")\n" : "\n");
580}
581
582/**
583 * @brief Log a message.
584 *
585 * @param[in] ctx Context to use.
586 * @param[in] level Message log level.
587 * @param[in] err Error number.
588 * @param[in] vecode Error validation error code.
589 * @param[in] data_path Error data path, always spent.
590 * @param[in] schema_path Error schema path, always spent.
591 * @param[in] line Error input line, if any.
592 * @param[in] apptag Error app tag.
593 * @param[in] format Error message format.
594 * @param[in] args Error message format arguments.
595 */
596static void
597log_vprintf(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR err, LY_VECODE vecode, char *data_path,
598 char *schema_path, uint64_t line, const char *apptag, const char *format, va_list args)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200599{
Michal Vasko74cc1262024-04-12 11:10:53 +0200600 char *dyn_msg = NULL;
601 const char *msg;
Michal Vasko7a266772024-01-23 11:02:38 +0100602 ly_bool free_strs = 1, lolog, lostore;
Michal Vaskod4a6d042022-12-08 08:34:29 +0100603
604 /* learn effective logger options */
605 if (temp_ly_log_opts) {
606 lolog = *temp_ly_log_opts & LY_LOLOG;
607 lostore = *temp_ly_log_opts & LY_LOSTORE;
608 } else {
609 lolog = ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOLOG;
610 lostore = ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE;
611 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200612
Václav Kubernátd367ad92021-11-29 09:28:56 +0100613 if (level > ATOMIC_LOAD_RELAXED(ly_ll)) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200614 /* do not print or store the message */
Michal Vasko7a266772024-01-23 11:02:38 +0100615 goto cleanup;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200616 }
617
Michal Vasko7a266772024-01-23 11:02:38 +0100618 if (err == LY_EMEM) {
Michal Vasko74cc1262024-04-12 11:10:53 +0200619 /* no not use more dynamic memory */
620 vsnprintf(last_msg, LY_LAST_MSG_SIZE, format, args);
621 msg = last_msg;
622 } else {
623 /* print into a single message */
624 if (vasprintf(&dyn_msg, format, args) == -1) {
625 LOGMEM(ctx);
626 goto cleanup;
Michal Vasko5a016922021-05-07 08:19:15 +0200627 }
Michal Vasko74cc1262024-04-12 11:10:53 +0200628 msg = dyn_msg;
Michal Vasko5a016922021-05-07 08:19:15 +0200629
Michal Vasko74cc1262024-04-12 11:10:53 +0200630 /* store as the last message */
631 strncpy(last_msg, msg, LY_LAST_MSG_SIZE - 1);
Michal Vasko236cbac2023-02-10 15:45:37 +0100632 }
633
Michal Vasko236cbac2023-02-10 15:45:37 +0100634 /* store the error/warning in the context (if we need to store errors internally, it does not matter what are
Michal Vasko74cc1262024-04-12 11:10:53 +0200635 * the user log options), if the message is not dynamic, it would most likely fail to store (no memory) */
636 if ((level < LY_LLVRB) && ctx && lostore && dyn_msg) {
Michal Vaskofcd168e2024-02-27 09:16:21 +0100637 free_strs = 0;
Michal Vasko74cc1262024-04-12 11:10:53 +0200638 if (log_store(ctx, level, err, vecode, dyn_msg, data_path, schema_path, line, apptag ? strdup(apptag) : NULL)) {
Michal Vasko7a266772024-01-23 11:02:38 +0100639 goto cleanup;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200640 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200641 }
642
643 /* if we are only storing errors internally, never print the message (yet) */
Michal Vaskod4a6d042022-12-08 08:34:29 +0100644 if (lolog) {
Michal Vaskod8085612020-08-21 12:55:23 +0200645 if (log_clb) {
Michal Vasko7a266772024-01-23 11:02:38 +0100646 log_clb(level, msg, data_path, schema_path, line);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200647 } else {
Michal Vasko7a266772024-01-23 11:02:38 +0100648 fprintf(stderr, "libyang[%d]: ", level);
649 fprintf(stderr, "%s", msg);
650 log_stderr_path_line(data_path, schema_path, line);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200651 }
652 }
653
Michal Vasko7a266772024-01-23 11:02:38 +0100654cleanup:
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200655 if (free_strs) {
Michal Vasko7a266772024-01-23 11:02:38 +0100656 free(data_path);
657 free(schema_path);
Michal Vasko74cc1262024-04-12 11:10:53 +0200658 free(dyn_msg);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200659 }
660}
661
Radek Krejci4ab61562018-09-05 15:00:37 +0200662#ifndef NDEBUG
663
664void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200665ly_log_dbg(uint32_t group, const char *format, ...)
Radek Krejci4ab61562018-09-05 15:00:37 +0200666{
667 char *dbg_format;
668 const char *str_group;
669 va_list ap;
670
Václav Kubernátd367ad92021-11-29 09:28:56 +0100671 if (!(ATOMIC_LOAD_RELAXED(ly_ldbg_groups) & group)) {
Radek Krejci4ab61562018-09-05 15:00:37 +0200672 return;
673 }
674
675 switch (group) {
676 case LY_LDGDICT:
677 str_group = "DICT";
678 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200679 case LY_LDGXPATH:
680 str_group = "XPATH";
681 break;
Michal Vaskoe558f792021-07-28 08:20:15 +0200682 case LY_LDGDEPSETS:
683 str_group = "DEPSETS";
684 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200685 default:
686 LOGINT(NULL);
687 return;
688 }
689
690 if (asprintf(&dbg_format, "%s: %s", str_group, format) == -1) {
691 LOGMEM(NULL);
692 return;
693 }
694
695 va_start(ap, format);
Michal Vasko7a266772024-01-23 11:02:38 +0100696 log_vprintf(NULL, LY_LLDBG, 0, 0, NULL, NULL, 0, NULL, dbg_format, ap);
Radek Krejci4ab61562018-09-05 15:00:37 +0200697 va_end(ap);
aPiecekd6d2c042023-06-02 08:31:43 +0200698
699 free(dbg_format);
Radek Krejci4ab61562018-09-05 15:00:37 +0200700}
701
702#endif
703
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200704void
Michal Vasko7a266772024-01-23 11:02:38 +0100705ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR err, const char *format, ...)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200706{
707 va_list ap;
708
709 va_start(ap, format);
Michal Vasko7a266772024-01-23 11:02:38 +0100710 log_vprintf(ctx, level, err, 0, NULL, NULL, 0, NULL, format, ap);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200711 va_end(ap);
712}
713
Michal Vaskodbf3e652022-10-21 08:46:25 +0200714/**
715 * @brief Append a schema node name to a generated data path, only if it fits.
716 *
717 * @param[in,out] str Generated path to update.
718 * @param[in] snode Schema node to append.
719 * @param[in] parent Last printed data node.
720 * @return LY_ERR value.
721 */
722static LY_ERR
723ly_vlog_build_path_append(char **str, const struct lysc_node *snode, const struct lyd_node *parent)
724{
725 const struct lys_module *mod, *prev_mod;
726 uint32_t len, new_len;
727 void *mem;
728
729 if (snode->nodetype & (LYS_CHOICE | LYS_CASE)) {
730 /* schema-only node */
731 return LY_SUCCESS;
Michal Vaskoccd1fa62023-08-17 09:15:46 +0200732 } else if (lysc_data_parent(snode) != lyd_node_schema(parent)) {
Michal Vaskodbf3e652022-10-21 08:46:25 +0200733 /* not a direct descendant node */
734 return LY_SUCCESS;
735 }
736
737 /* get module to print, if any */
738 mod = snode->module;
Michal Vasko420cc252023-08-24 08:14:24 +0200739 prev_mod = lyd_node_module(parent);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200740 if (prev_mod == mod) {
741 mod = NULL;
742 }
743
744 /* realloc string */
Michal Vasko03205432023-09-11 10:29:49 +0200745 len = *str ? strlen(*str) : 0;
Michal Vaskodbf3e652022-10-21 08:46:25 +0200746 new_len = len + 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(snode->name);
747 mem = realloc(*str, new_len + 1);
748 LY_CHECK_ERR_RET(!mem, LOGMEM(LYD_CTX(parent)), LY_EMEM);
749 *str = mem;
750
751 /* print the last schema node */
752 sprintf(*str + len, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", snode->name);
753 return LY_SUCCESS;
754}
755
Michal Vaskocd9c00b2023-09-11 10:29:28 +0200756LY_ERR
757ly_vlog_build_data_path(const struct ly_ctx *ctx, char **path)
758{
759 LY_ERR rc = LY_SUCCESS;
760 const struct lyd_node *dnode = NULL;
761
762 *path = NULL;
763
764 if (log_location.dnodes.count) {
765 dnode = log_location.dnodes.objs[log_location.dnodes.count - 1];
Michal Vasko7a266772024-01-23 11:02:38 +0100766 if (!dnode) {
767 /* special root node */
768 assert(log_location.dnodes.count == 1);
769 *path = strdup("/");
770 LY_CHECK_ERR_GOTO(!*path, LOGMEM(ctx); rc = LY_EMEM, cleanup);
771 goto cleanup;
772 }
773
Michal Vaskocd9c00b2023-09-11 10:29:28 +0200774 if (dnode->parent || !lysc_data_parent(dnode->schema)) {
775 /* data node with all of its parents */
776 *path = lyd_path(log_location.dnodes.objs[log_location.dnodes.count - 1], LYD_PATH_STD, NULL, 0);
777 LY_CHECK_ERR_GOTO(!*path, LOGMEM(ctx); rc = LY_EMEM, cleanup);
778 } else {
779 /* data parsers put all the parent nodes in the set, but they are not connected */
780 *path = lyd_path_set(&log_location.dnodes, LYD_PATH_STD);
781 LY_CHECK_ERR_GOTO(!*path, LOGMEM(ctx); rc = LY_EMEM, cleanup);
782 }
783 }
784
785 /* sometimes the last node is not created yet and we only have the schema node */
786 if (log_location.scnodes.count) {
787 rc = ly_vlog_build_path_append(path, log_location.scnodes.objs[log_location.scnodes.count - 1], dnode);
788 LY_CHECK_GOTO(rc, cleanup);
789 }
790
791cleanup:
792 if (rc) {
793 free(*path);
794 *path = NULL;
795 }
796 return rc;
797}
798
Michal Vaskodbf3e652022-10-21 08:46:25 +0200799/**
Michal Vasko7a266772024-01-23 11:02:38 +0100800 * @brief Build log path/input line from the stored log location information.
Michal Vaskodbf3e652022-10-21 08:46:25 +0200801 *
802 * @param[in] ctx Context to use.
Michal Vasko7a266772024-01-23 11:02:38 +0100803 * @param[out] data_path Generated data path.
804 * @param[out] schema_path Generated data path.
805 * @param[out] line Input line.
Michal Vaskodbf3e652022-10-21 08:46:25 +0200806 * @return LY_ERR value.
807 */
Radek Krejci94aa9942018-09-07 17:12:17 +0200808static LY_ERR
Michal Vasko7a266772024-01-23 11:02:38 +0100809ly_vlog_build_path_line(const struct ly_ctx *ctx, char **data_path, char **schema_path, uint64_t *line)
Radek Krejci94aa9942018-09-07 17:12:17 +0200810{
Michal Vasko7a266772024-01-23 11:02:38 +0100811 *data_path = NULL;
812 *schema_path = NULL;
813 *line = 0;
Radek Krejcicb3e6472021-01-06 08:19:01 +0100814
Michal Vasko7a266772024-01-23 11:02:38 +0100815 if (log_location.spaths.count && ((const char *)(log_location.spaths.objs[log_location.spaths.count - 1]))[0]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100816 /* simply get what is in the provided path string */
Michal Vasko7a266772024-01-23 11:02:38 +0100817 *schema_path = strdup(log_location.spaths.objs[log_location.spaths.count - 1]);
818 LY_CHECK_ERR_RET(!*schema_path, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100819 } else {
Michal Vaskodbf3e652022-10-21 08:46:25 +0200820 /* data/schema node */
821 if (log_location.dnodes.count) {
Michal Vasko7a266772024-01-23 11:02:38 +0100822 LY_CHECK_RET(ly_vlog_build_data_path(ctx, data_path));
Michal Vaskodbf3e652022-10-21 08:46:25 +0200823 } else if (log_location.scnodes.count) {
Michal Vasko7a266772024-01-23 11:02:38 +0100824 *schema_path = lysc_path(log_location.scnodes.objs[log_location.scnodes.count - 1], LYSC_PATH_LOG, NULL, 0);
825 LY_CHECK_ERR_RET(!*schema_path, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100826 }
Michal Vasko273727c2023-09-11 10:30:08 +0200827 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100828
Michal Vasko273727c2023-09-11 10:30:08 +0200829 /* line */
Michal Vasko7a266772024-01-23 11:02:38 +0100830 if (log_location.inputs.count) {
831 *line = ((struct ly_in *)log_location.inputs.objs[log_location.inputs.count - 1])->line;
Radek Krejci94aa9942018-09-07 17:12:17 +0200832 }
833
Radek Krejci94aa9942018-09-07 17:12:17 +0200834 return LY_SUCCESS;
835}
836
837void
Michal Vaskoe9391c72021-10-05 10:04:56 +0200838ly_vlog(const struct ly_ctx *ctx, const char *apptag, LY_VECODE code, const char *format, ...)
Radek Krejci94aa9942018-09-07 17:12:17 +0200839{
840 va_list ap;
Michal Vasko7a266772024-01-23 11:02:38 +0100841 char *data_path = NULL, *schema_path = NULL;
842 uint64_t line = 0;
Radek Krejci94aa9942018-09-07 17:12:17 +0200843
Michal Vasko7a266772024-01-23 11:02:38 +0100844 if (ctx) {
845 ly_vlog_build_path_line(ctx, &data_path, &schema_path, &line);
Radek Krejci94aa9942018-09-07 17:12:17 +0200846 }
847
848 va_start(ap, format);
Michal Vasko7a266772024-01-23 11:02:38 +0100849 log_vprintf(ctx, LY_LLERR, LY_EVALID, code, data_path, schema_path, line, apptag, format, ap);
Radek Krejci94aa9942018-09-07 17:12:17 +0200850 /* path is spent and should not be freed! */
851 va_end(ap);
852}
853
Michal Vasko193dacd2022-10-13 08:43:05 +0200854/**
855 * @brief Print a log message from an extension plugin callback.
856 *
857 * @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
858 * @param[in] plugin_name Name of the plugin generating the message.
859 * @param[in] level Log message level (error, warning, etc.)
Michal Vasko7a266772024-01-23 11:02:38 +0100860 * @param[in] err Error type code.
861 * @param[in] data_path Error data path, always spent.
862 * @param[in] schema_path Error schema path, always spent.
863 * @param[in] line Error input line, if any.
Michal Vasko193dacd2022-10-13 08:43:05 +0200864 * @param[in] format Format string to print.
865 * @param[in] ap Var arg list for @p format.
866 */
867static void
Michal Vasko7a266772024-01-23 11:02:38 +0100868ly_ext_log(const struct ly_ctx *ctx, const char *plugin_name, LY_LOG_LEVEL level, LY_ERR err, char *data_path,
869 char *schema_path, uint64_t line, const char *format, va_list ap)
Radek Krejci0935f412019-08-20 16:15:18 +0200870{
Radek Krejci0935f412019-08-20 16:15:18 +0200871 char *plugin_msg;
Radek Krejci0935f412019-08-20 16:15:18 +0200872
Václav Kubernátd367ad92021-11-29 09:28:56 +0100873 if (ATOMIC_LOAD_RELAXED(ly_ll) < level) {
Radek Krejci0935f412019-08-20 16:15:18 +0200874 return;
875 }
Michal Vasko193dacd2022-10-13 08:43:05 +0200876 if (asprintf(&plugin_msg, "Ext plugin \"%s\": %s", plugin_name, format) == -1) {
877 LOGMEM(ctx);
Radek Krejci0935f412019-08-20 16:15:18 +0200878 return;
879 }
880
Michal Vasko7a266772024-01-23 11:02:38 +0100881 log_vprintf(ctx, level, (level == LY_LLERR ? LY_EPLUGIN : 0) | err, LYVE_OTHER, data_path, schema_path, line, NULL,
882 plugin_msg, ap);
Michal Vasko193dacd2022-10-13 08:43:05 +0200883 free(plugin_msg);
884}
885
886LIBYANG_API_DEF void
Michal Vasko7a266772024-01-23 11:02:38 +0100887lyplg_ext_parse_log(const struct lysp_ctx *pctx, const struct lysp_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err,
Michal Vasko193dacd2022-10-13 08:43:05 +0200888 const char *format, ...)
889{
890 va_list ap;
Michal Vasko7a266772024-01-23 11:02:38 +0100891 char *data_path, *schema_path;
892 uint64_t line;
Michal Vasko193dacd2022-10-13 08:43:05 +0200893
Michal Vasko7a266772024-01-23 11:02:38 +0100894 ly_vlog_build_path_line(PARSER_CTX(pctx), &data_path, &schema_path, &line);
Michal Vasko193dacd2022-10-13 08:43:05 +0200895
Radek Krejci0935f412019-08-20 16:15:18 +0200896 va_start(ap, format);
Michal Vasko7a266772024-01-23 11:02:38 +0100897 ly_ext_log(PARSER_CTX(pctx), ext->record->plugin.id, level, err, data_path, schema_path, line, format, ap);
Radek Krejci0935f412019-08-20 16:15:18 +0200898 va_end(ap);
Michal Vasko193dacd2022-10-13 08:43:05 +0200899}
900
901LIBYANG_API_DEF void
Michal Vasko7a266772024-01-23 11:02:38 +0100902lyplg_ext_compile_log(const struct lysc_ctx *cctx, const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err,
Michal Vasko193dacd2022-10-13 08:43:05 +0200903 const char *format, ...)
904{
905 va_list ap;
Michal Vasko7a266772024-01-23 11:02:38 +0100906 char *schema_path = NULL;
Michal Vasko6727c682023-02-17 10:40:26 +0100907
Michal Vasko7a266772024-01-23 11:02:38 +0100908 if (cctx && !(schema_path = strdup(cctx->path))) {
Michal Vasko6727c682023-02-17 10:40:26 +0100909 LOGMEM(cctx->ctx);
910 return;
911 }
Michal Vasko193dacd2022-10-13 08:43:05 +0200912
913 va_start(ap, format);
Michal Vasko7a266772024-01-23 11:02:38 +0100914 ly_ext_log(ext->module->ctx, ext->def->plugin->id, level, err, NULL, schema_path, 0, format, ap);
Michal Vasko193dacd2022-10-13 08:43:05 +0200915 va_end(ap);
916}
917
918LIBYANG_API_DEF void
Michal Vasko7a266772024-01-23 11:02:38 +0100919lyplg_ext_compile_log_path(const char *path, const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err,
Michal Vasko193dacd2022-10-13 08:43:05 +0200920 const char *format, ...)
921{
922 va_list ap;
Michal Vasko7a266772024-01-23 11:02:38 +0100923 char *schema_path = NULL;
Michal Vasko6727c682023-02-17 10:40:26 +0100924
Michal Vasko7a266772024-01-23 11:02:38 +0100925 if (path && !(schema_path = strdup(path))) {
Michal Vasko6727c682023-02-17 10:40:26 +0100926 LOGMEM(ext->module->ctx);
927 return;
928 }
Michal Vasko193dacd2022-10-13 08:43:05 +0200929
930 va_start(ap, format);
Michal Vasko7a266772024-01-23 11:02:38 +0100931 ly_ext_log(ext->module->ctx, ext->def->plugin->id, level, err, NULL, schema_path, 0, format, ap);
Michal Vasko193dacd2022-10-13 08:43:05 +0200932 va_end(ap);
Radek Krejci0935f412019-08-20 16:15:18 +0200933}
934
Michal Vasko177d0ed2020-11-23 16:43:03 +0100935/**
Michal Vasko6727c682023-02-17 10:40:26 +0100936 * @brief Serves only for creating ap.
937 */
938static void
Michal Vasko7a266772024-01-23 11:02:38 +0100939_lyplg_ext_compile_log_err(const struct ly_err_item *eitem, const struct lysc_ext_instance *ext, ...)
Michal Vasko6727c682023-02-17 10:40:26 +0100940{
941 va_list ap;
Michal Vasko7a266772024-01-23 11:02:38 +0100942 char *data_path = NULL, *schema_path = NULL;
943
944 if (eitem->data_path) {
945 data_path = strdup(eitem->data_path);
946 }
947 if (eitem->schema_path) {
948 schema_path = strdup(eitem->schema_path);
949 }
Michal Vasko6727c682023-02-17 10:40:26 +0100950
951 va_start(ap, ext);
Michal Vasko7a266772024-01-23 11:02:38 +0100952 ly_ext_log(ext->module->ctx, ext->def->plugin->id, eitem->level, eitem->err, data_path, schema_path, eitem->line, "%s", ap);
Michal Vasko6727c682023-02-17 10:40:26 +0100953 va_end(ap);
954}
955
956LIBYANG_API_DEF void
Michal Vasko7a266772024-01-23 11:02:38 +0100957lyplg_ext_compile_log_err(const struct ly_err_item *eitem, const struct lysc_ext_instance *ext)
Michal Vasko6727c682023-02-17 10:40:26 +0100958{
Michal Vasko7a266772024-01-23 11:02:38 +0100959 _lyplg_ext_compile_log_err(eitem, ext, eitem->msg);
Michal Vasko6727c682023-02-17 10:40:26 +0100960}
961
962/**
Michal Vaskoc78a6092021-05-07 15:27:35 +0200963 * @brief Exact same functionality as ::ly_err_print() but has variable arguments so log_vprintf() can be called.
Michal Vasko177d0ed2020-11-23 16:43:03 +0100964 */
965static void
Michal Vasko7a266772024-01-23 11:02:38 +0100966_ly_err_print(const struct ly_ctx *ctx, const struct ly_err_item *eitem, const char *format, ...)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200967{
Michal Vasko177d0ed2020-11-23 16:43:03 +0100968 va_list ap;
Michal Vasko7a266772024-01-23 11:02:38 +0100969 char *data_path = NULL, *schema_path = NULL;
Michal Vasko177d0ed2020-11-23 16:43:03 +0100970
971 LY_CHECK_ARG_RET(ctx, eitem, );
972
Michal Vasko7a266772024-01-23 11:02:38 +0100973 if (eitem->data_path) {
974 data_path = strdup(eitem->data_path);
975 }
976 if (eitem->schema_path) {
977 schema_path = strdup(eitem->schema_path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200978 }
Michal Vasko177d0ed2020-11-23 16:43:03 +0100979
Michal Vaskoc78a6092021-05-07 15:27:35 +0200980 va_start(ap, format);
Michal Vasko7a266772024-01-23 11:02:38 +0100981 log_vprintf(ctx, eitem->level, eitem->err, eitem->vecode, data_path, schema_path, eitem->line, eitem->apptag, format, ap);
Michal Vasko177d0ed2020-11-23 16:43:03 +0100982 va_end(ap);
Michal Vasko177d0ed2020-11-23 16:43:03 +0100983}
984
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100985LIBYANG_API_DEF void
Michal Vasko7a266772024-01-23 11:02:38 +0100986ly_err_print(const struct ly_ctx *ctx, const struct ly_err_item *eitem)
Michal Vasko177d0ed2020-11-23 16:43:03 +0100987{
Michal Vaskoc78a6092021-05-07 15:27:35 +0200988 /* String ::ly_err_item.msg cannot be used directly because it may contain the % character */
989 _ly_err_print(ctx, eitem, "%s", eitem->msg);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200990}