blob: c654771ddc167194be3d5a9007d062f004c7d814 [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
Christian Hopps32874e12021-05-01 09:43:54 -040015#define _GNU_SOURCE /* asprintf, strdup */
Radek Krejci535ea9f2020-05-29 16:01:05 +020016
17#include "log.h"
Radek Krejcib7db73a2018-10-24 14:18:40 +020018
Radek Krejci5aeea3a2018-09-05 13:29:36 +020019#include <assert.h>
Radek Krejcic04f0a22018-09-21 15:49:45 +020020#include <inttypes.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include <pthread.h>
Radek Krejci5aeea3a2018-09-05 13:29:36 +020022#include <stdarg.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include <stdint.h>
Radek Krejci5aeea3a2018-09-05 13:29:36 +020024#include <stdio.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include <stdlib.h>
26#include <string.h>
Radek Krejci5aeea3a2018-09-05 13:29:36 +020027
Radek Krejci535ea9f2020-05-29 16:01:05 +020028#include "common.h"
Radek Krejciaa45bda2020-07-20 07:43:38 +020029#include "compat.h"
Radek Krejciaddfc9a2020-12-17 20:46:35 +010030#include "in_internal.h"
Radek Krejci0935f412019-08-20 16:15:18 +020031#include "plugins_exts.h"
Radek Krejci77114102021-03-10 15:21:57 +010032#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020033#include "tree_data.h"
Michal Vaskodbf3e652022-10-21 08:46:25 +020034#include "tree_data_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020035#include "tree_schema.h"
Radek Krejci5aeea3a2018-09-05 13:29:36 +020036
Václav Kubernátd367ad92021-11-29 09:28:56 +010037ATOMIC_T ly_ll = (uint_fast32_t)LY_LLWRN;
38ATOMIC_T ly_log_opts = (uint_fast32_t)(LY_LOLOG | LY_LOSTORE_LAST);
Michal Vaskod8085612020-08-21 12:55:23 +020039static ly_log_clb log_clb;
Václav Kubernátd367ad92021-11-29 09:28:56 +010040static ATOMIC_T path_flag = 1;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020041#ifndef NDEBUG
Václav Kubernátd367ad92021-11-29 09:28:56 +010042ATOMIC_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
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010050LIBYANG_API_DEF LY_ERR
Radek Krejcid33273d2018-10-25 14:55:52 +020051ly_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
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010063LIBYANG_API_DEF LY_VECODE
Radek Krejci5aeea3a2018-09-05 13:29:36 +020064ly_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
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010076LIBYANG_API_DEF const char *
Radek Krejci5aeea3a2018-09-05 13:29:36 +020077ly_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
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010091LIBYANG_API_DEF const char *
Radek Krejci5aeea3a2018-09-05 13:29:36 +020092ly_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
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100106LIBYANG_API_DEF const char *
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200107ly_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
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100121LIBYANG_API_DEF LY_ERR
aPiecek6d618552021-06-18 10:02:59 +0200122ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag, const char *err_format, ...)
Radek Krejcie7b95092019-05-15 11:03:07 +0200123{
Radek Krejcidb0ee022021-03-15 16:53:44 +0100124 char *msg = NULL;
125 struct ly_err_item *e;
Radek Krejcie7b95092019-05-15 11:03:07 +0200126
Radek Krejcid43298b2021-03-25 16:17:15 +0100127 if (!err || (ecode == LY_SUCCESS)) {
Radek Krejcidb0ee022021-03-15 16:53:44 +0100128 /* nothing to do */
129 return ecode;
130 }
131
132 e = malloc(sizeof *e);
133 LY_CHECK_ERR_RET(!e, LOGMEM(NULL), LY_EMEM);
134 e->prev = (*err) ? (*err)->prev : e;
135 e->next = NULL;
136 if (*err) {
137 (*err)->prev->next = e;
138 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200139
140 /* fill in the information */
Radek Krejcidb0ee022021-03-15 16:53:44 +0100141 e->level = LY_LLERR;
142 e->no = ecode;
143 e->vecode = vecode;
144 e->path = path;
145 e->apptag = apptag;
Radek Krejcie7b95092019-05-15 11:03:07 +0200146
aPiecek6d618552021-06-18 10:02:59 +0200147 if (err_format) {
Radek Krejcidb0ee022021-03-15 16:53:44 +0100148 va_list print_args;
149
aPiecek6d618552021-06-18 10:02:59 +0200150 va_start(print_args, err_format);
Radek Krejcidb0ee022021-03-15 16:53:44 +0100151
aPiecek6d618552021-06-18 10:02:59 +0200152 if (vasprintf(&msg, err_format, print_args) == -1) {
153 /* we don't have anything more to do, just set msg to NULL to avoid undefined content,
Radek Krejcidb0ee022021-03-15 16:53:44 +0100154 * still keep the information about the original error instead of LY_EMEM or other printf's error */
155 msg = NULL;
156 }
157
158 va_end(print_args);
159 }
160 e->msg = msg;
161
162 if (!(*err)) {
163 *err = e;
164 }
165
166 return e->no;
Radek Krejcie7b95092019-05-15 11:03:07 +0200167}
168
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100169LIBYANG_API_DEF struct ly_err_item *
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200170ly_err_first(const struct ly_ctx *ctx)
171{
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200172 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200173
174 return pthread_getspecific(ctx->errlist_key);
175}
176
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100177LIBYANG_API_DEF struct ly_err_item *
Radek Krejci572ee602020-09-16 14:35:08 +0200178ly_err_last(const struct ly_ctx *ctx)
179{
180 const struct ly_err_item *e;
181
182 LY_CHECK_ARG_RET(NULL, ctx, NULL);
183
184 e = pthread_getspecific(ctx->errlist_key);
185 return e ? e->prev : NULL;
186}
187
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100188LIBYANG_API_DEF void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200189ly_err_free(void *ptr)
190{
191 struct ly_err_item *i, *next;
192
193 /* clean the error list */
194 for (i = (struct ly_err_item *)ptr; i; i = next) {
195 next = i->next;
Radek Krejcidb0ee022021-03-15 16:53:44 +0100196 free(i->msg);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200197 free(i->path);
198 free(i->apptag);
199 free(i);
200 }
201}
202
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100203LIBYANG_API_DEF void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200204ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
205{
206 struct ly_err_item *i, *first;
207
208 first = ly_err_first(ctx);
209 if (first == eitem) {
210 eitem = NULL;
211 }
212 if (eitem) {
213 /* disconnect the error */
Radek Krejci1e008d22020-08-17 11:37:37 +0200214 for (i = first; i && (i->next != eitem); i = i->next) {}
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200215 assert(i);
216 i->next = NULL;
217 first->prev = i;
218 /* free this err and newer */
219 ly_err_free(eitem);
220 } else {
221 /* free all err */
222 ly_err_free(first);
223 pthread_setspecific(ctx->errlist_key, NULL);
224 }
225}
226
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100227LIBYANG_API_DEF LY_LOG_LEVEL
Radek Krejci52b6d512020-10-12 12:33:17 +0200228ly_log_level(LY_LOG_LEVEL level)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200229{
Václav Kubernátd367ad92021-11-29 09:28:56 +0100230 LY_LOG_LEVEL prev = ATOMIC_LOAD_RELAXED(ly_ll);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200231
Václav Kubernátd367ad92021-11-29 09:28:56 +0100232 ATOMIC_STORE_RELAXED(ly_ll, level);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200233 return prev;
234}
235
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100236LIBYANG_API_DEF uint32_t
Radek Krejci1deb5be2020-08-26 16:43:36 +0200237ly_log_options(uint32_t opts)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200238{
Václav Kubernátd367ad92021-11-29 09:28:56 +0100239 uint32_t prev = ATOMIC_LOAD_RELAXED(ly_log_opts);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200240
Václav Kubernátd367ad92021-11-29 09:28:56 +0100241 ATOMIC_STORE_RELAXED(ly_log_opts, opts);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200242 return prev;
243}
244
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100245LIBYANG_API_DEF uint32_t
Radek Krejci68433c92020-10-12 17:03:55 +0200246ly_log_dbg_groups(uint32_t dbg_groups)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200247{
248#ifndef NDEBUG
Václav Kubernátd367ad92021-11-29 09:28:56 +0100249 uint32_t prev = ATOMIC_LOAD_RELAXED(ly_ldbg_groups);
Radek Krejciebdaed02020-11-09 13:05:06 +0100250
Václav Kubernátd367ad92021-11-29 09:28:56 +0100251 ATOMIC_STORE_RELAXED(ly_ldbg_groups, dbg_groups);
Radek Krejciebdaed02020-11-09 13:05:06 +0100252 return prev;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200253#else
254 (void)dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100255 return 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200256#endif
257}
258
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100259LIBYANG_API_DEF void
Radek Krejci857189e2020-09-01 13:26:36 +0200260ly_set_log_clb(ly_log_clb clb, ly_bool path)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200261{
Michal Vaskod8085612020-08-21 12:55:23 +0200262 log_clb = clb;
Václav Kubernátd367ad92021-11-29 09:28:56 +0100263 ATOMIC_STORE_RELAXED(path_flag, path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200264}
265
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100266LIBYANG_API_DEF ly_log_clb
Michal Vaskod8085612020-08-21 12:55:23 +0200267ly_get_log_clb(void)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200268{
Michal Vaskod8085612020-08-21 12:55:23 +0200269 return log_clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200270}
271
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100272void
Michal Vasko59e69e72022-02-18 09:18:21 +0100273ly_log_location(const struct lysc_node *scnode, const struct lyd_node *dnode, const char *path, const struct ly_in *in,
274 uint64_t line, ly_bool reset)
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100275{
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100276 if (scnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100277 ly_set_add(&log_location.scnodes, (void *)scnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100278 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100279 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100280 }
281
282 if (dnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100283 ly_set_add(&log_location.dnodes, (void *)dnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100284 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100285 ly_set_erase(&log_location.dnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100286 }
287
288 if (path) {
289 char *s = strdup(path);
Michal Vasko26bbb272022-08-02 14:54:33 +0200290
Radek Krejciddace2c2021-01-08 11:30:56 +0100291 LY_CHECK_ERR_RET(!s, LOGMEM(NULL), );
292 ly_set_add(&log_location.paths, s, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100293 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100294 ly_set_erase(&log_location.paths, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100295 }
296
297 if (in) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100298 ly_set_add(&log_location.inputs, (void *)in, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100299 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100300 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100301 }
302
303 if (line) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100304 log_location.line = line;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100305 }
306}
307
308void
Michal Vasko59e69e72022-02-18 09:18:21 +0100309ly_log_location_revert(uint32_t scnode_steps, uint32_t dnode_steps, uint32_t path_steps, uint32_t in_steps)
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100310{
Radek Krejciddace2c2021-01-08 11:30:56 +0100311 for (uint32_t i = scnode_steps; i && log_location.scnodes.count; i--) {
312 log_location.scnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100313 }
314
Radek Krejciddace2c2021-01-08 11:30:56 +0100315 for (uint32_t i = dnode_steps; i && log_location.dnodes.count; i--) {
316 log_location.dnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100317 }
318
Radek Krejciddace2c2021-01-08 11:30:56 +0100319 for (uint32_t i = path_steps; i && log_location.paths.count; i--) {
320 ly_set_rm_index(&log_location.paths, log_location.paths.count - 1, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100321 }
322
Radek Krejciddace2c2021-01-08 11:30:56 +0100323 for (uint32_t i = in_steps; i && log_location.inputs.count; i--) {
324 log_location.inputs.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100325 }
326
Radek Krejciddace2c2021-01-08 11:30:56 +0100327 /* deallocate the empty sets */
328 if (scnode_steps && !log_location.scnodes.count) {
329 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100330 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100331 if (dnode_steps && !log_location.dnodes.count) {
332 ly_set_erase(&log_location.dnodes, NULL);
333 }
334 if (path_steps && !log_location.paths.count) {
335 ly_set_erase(&log_location.paths, free);
336 }
337 if (in_steps && !log_location.inputs.count) {
338 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100339 }
340}
341
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200342static LY_ERR
343log_store(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
344{
345 struct ly_err_item *eitem, *last;
346
347 assert(ctx && (level < LY_LLVRB));
348
349 eitem = pthread_getspecific(ctx->errlist_key);
350 if (!eitem) {
351 /* if we are only to fill in path, there must have been an error stored */
352 assert(msg);
353 eitem = malloc(sizeof *eitem);
354 LY_CHECK_GOTO(!eitem, mem_fail);
355 eitem->prev = eitem;
356 eitem->next = NULL;
357
358 pthread_setspecific(ctx->errlist_key, eitem);
359 } else if (!msg) {
360 /* only filling the path */
361 assert(path);
362
363 /* find last error */
364 eitem = eitem->prev;
365 do {
366 if (eitem->level == LY_LLERR) {
367 /* fill the path */
368 free(eitem->path);
369 eitem->path = path;
370 return LY_SUCCESS;
371 }
372 eitem = eitem->prev;
373 } while (eitem->prev->next);
374 /* last error was not found */
375 assert(0);
Václav Kubernátd367ad92021-11-29 09:28:56 +0100376 } else if ((ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE_LAST) == LY_LOSTORE_LAST) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200377 /* overwrite last message */
378 free(eitem->msg);
379 free(eitem->path);
380 free(eitem->apptag);
381 } else {
382 /* store new message */
383 last = eitem->prev;
384 eitem->prev = malloc(sizeof *eitem);
385 LY_CHECK_GOTO(!eitem->prev, mem_fail);
386 eitem = eitem->prev;
387 eitem->prev = last;
388 eitem->next = NULL;
389 last->next = eitem;
390 }
391
392 /* fill in the information */
393 eitem->level = level;
394 eitem->no = no;
395 eitem->vecode = vecode;
396 eitem->msg = msg;
397 eitem->path = path;
398 eitem->apptag = apptag;
399 return LY_SUCCESS;
400
401mem_fail:
402 LOGMEM(NULL);
403 free(msg);
404 free(path);
405 free(apptag);
406 return LY_EMEM;
407}
408
409static void
Michal Vaskoe9391c72021-10-05 10:04:56 +0200410log_vprintf(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *path, const char *apptag,
Radek Krejci0f969882020-08-21 16:56:47 +0200411 const char *format, va_list args)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200412{
413 char *msg = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200414 ly_bool free_strs;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200415
Václav Kubernátd367ad92021-11-29 09:28:56 +0100416 if (level > ATOMIC_LOAD_RELAXED(ly_ll)) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200417 /* do not print or store the message */
418 free(path);
419 return;
420 }
421
Michal Vasko5a016922021-05-07 08:19:15 +0200422 if (no == LY_EMEM) {
423 /* just print it, anything else would most likely fail anyway */
Václav Kubernátd367ad92021-11-29 09:28:56 +0100424 if (ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOLOG) {
Michal Vasko5a016922021-05-07 08:19:15 +0200425 if (log_clb) {
426 log_clb(level, LY_EMEM_MSG, path);
427 } else {
428 fprintf(stderr, "libyang[%d]: ", level);
429 vfprintf(stderr, format, args);
430 if (path) {
431 fprintf(stderr, " (path: %s)\n", path);
432 } else {
433 fprintf(stderr, "\n");
434 }
435 }
436 }
437 free(path);
438 return;
439 }
440
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200441 /* store the error/warning (if we need to store errors internally, it does not matter what are the user log options) */
Václav Kubernátd367ad92021-11-29 09:28:56 +0100442 if ((level < LY_LLVRB) && ctx && (ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200443 assert(format);
444 if (vasprintf(&msg, format, args) == -1) {
445 LOGMEM(ctx);
446 free(path);
447 return;
448 }
Radek Krejcic9e64a62020-09-18 20:08:12 +0200449 if (((no & ~LY_EPLUGIN) == LY_EVALID) && (vecode == LYVE_SUCCESS)) {
450 /* assume we are inheriting the error, so inherit vecode as well */
451 vecode = ly_vecode(ctx);
452 }
Michal Vaskoe9391c72021-10-05 10:04:56 +0200453 if (log_store(ctx, level, no, vecode, msg, path, apptag ? strdup(apptag) : NULL)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200454 return;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200455 }
456 free_strs = 0;
457 } else {
458 if (vasprintf(&msg, format, args) == -1) {
459 LOGMEM(ctx);
460 free(path);
461 return;
462 }
463 free_strs = 1;
464 }
465
466 /* if we are only storing errors internally, never print the message (yet) */
Václav Kubernátd367ad92021-11-29 09:28:56 +0100467 if (ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOLOG) {
Michal Vaskod8085612020-08-21 12:55:23 +0200468 if (log_clb) {
469 log_clb(level, msg, path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200470 } else {
471 fprintf(stderr, "libyang[%d]: %s%s", level, msg, path ? " " : "\n");
472 if (path) {
473 fprintf(stderr, "(path: %s)\n", path);
474 }
475 }
476 }
477
478 if (free_strs) {
479 free(path);
480 free(msg);
481 }
482}
483
Radek Krejci4ab61562018-09-05 15:00:37 +0200484#ifndef NDEBUG
485
486void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200487ly_log_dbg(uint32_t group, const char *format, ...)
Radek Krejci4ab61562018-09-05 15:00:37 +0200488{
489 char *dbg_format;
490 const char *str_group;
491 va_list ap;
492
Václav Kubernátd367ad92021-11-29 09:28:56 +0100493 if (!(ATOMIC_LOAD_RELAXED(ly_ldbg_groups) & group)) {
Radek Krejci4ab61562018-09-05 15:00:37 +0200494 return;
495 }
496
497 switch (group) {
498 case LY_LDGDICT:
499 str_group = "DICT";
500 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200501 case LY_LDGXPATH:
502 str_group = "XPATH";
503 break;
Michal Vaskoe558f792021-07-28 08:20:15 +0200504 case LY_LDGDEPSETS:
505 str_group = "DEPSETS";
506 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200507 default:
508 LOGINT(NULL);
509 return;
510 }
511
512 if (asprintf(&dbg_format, "%s: %s", str_group, format) == -1) {
513 LOGMEM(NULL);
514 return;
515 }
516
517 va_start(ap, format);
Michal Vaskoe9391c72021-10-05 10:04:56 +0200518 log_vprintf(NULL, LY_LLDBG, 0, 0, NULL, NULL, dbg_format, ap);
Radek Krejci4ab61562018-09-05 15:00:37 +0200519 va_end(ap);
520}
521
522#endif
523
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200524void
525ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...)
526{
527 va_list ap;
528
529 va_start(ap, format);
Michal Vaskoe9391c72021-10-05 10:04:56 +0200530 log_vprintf(ctx, level, no, 0, NULL, NULL, format, ap);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200531 va_end(ap);
532}
533
Michal Vaskodbf3e652022-10-21 08:46:25 +0200534/**
535 * @brief Append a schema node name to a generated data path, only if it fits.
536 *
537 * @param[in,out] str Generated path to update.
538 * @param[in] snode Schema node to append.
539 * @param[in] parent Last printed data node.
540 * @return LY_ERR value.
541 */
542static LY_ERR
543ly_vlog_build_path_append(char **str, const struct lysc_node *snode, const struct lyd_node *parent)
544{
545 const struct lys_module *mod, *prev_mod;
546 uint32_t len, new_len;
547 void *mem;
548
549 if (snode->nodetype & (LYS_CHOICE | LYS_CASE)) {
550 /* schema-only node */
551 return LY_SUCCESS;
552 } else if (lysc_data_parent(snode) != parent->schema) {
553 /* not a direct descendant node */
554 return LY_SUCCESS;
555 }
556
557 /* get module to print, if any */
558 mod = snode->module;
559 prev_mod = (parent->schema) ? parent->schema->module : lyd_owner_module(parent);
560 if (prev_mod == mod) {
561 mod = NULL;
562 }
563
564 /* realloc string */
565 len = strlen(*str);
566 new_len = len + 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(snode->name);
567 mem = realloc(*str, new_len + 1);
568 LY_CHECK_ERR_RET(!mem, LOGMEM(LYD_CTX(parent)), LY_EMEM);
569 *str = mem;
570
571 /* print the last schema node */
572 sprintf(*str + len, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", snode->name);
573 return LY_SUCCESS;
574}
575
576/**
577 * @brief Build log path from the stored log location information.
578 *
579 * @param[in] ctx Context to use.
580 * @param[out] path Generated log path.
581 * @return LY_ERR value.
582 */
Radek Krejci94aa9942018-09-07 17:12:17 +0200583static LY_ERR
Radek Krejciddace2c2021-01-08 11:30:56 +0100584ly_vlog_build_path(const struct ly_ctx *ctx, char **path)
Radek Krejci94aa9942018-09-07 17:12:17 +0200585{
Michal Vaskodbf3e652022-10-21 08:46:25 +0200586 int r;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100587 char *str = NULL, *prev = NULL;
Michal Vaskodbf3e652022-10-21 08:46:25 +0200588 const struct lyd_node *dnode;
Radek Krejcicb3e6472021-01-06 08:19:01 +0100589
Radek Krejci2efc45b2020-12-22 16:25:44 +0100590 *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200591
Radek Krejciddace2c2021-01-08 11:30:56 +0100592 if (log_location.paths.count && ((const char *)(log_location.paths.objs[log_location.paths.count - 1]))[0]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100593 /* simply get what is in the provided path string */
Radek Krejciddace2c2021-01-08 11:30:56 +0100594 *path = strdup((const char *)log_location.paths.objs[log_location.paths.count - 1]);
Radek Krejcic04f0a22018-09-21 15:49:45 +0200595 LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100596 } else {
Michal Vaskodbf3e652022-10-21 08:46:25 +0200597 /* data/schema node */
598 if (log_location.dnodes.count) {
599 dnode = log_location.dnodes.objs[log_location.dnodes.count - 1];
600 if (!dnode->parent && lysc_data_parent(dnode->schema) && (log_location.dnodes.count > 1)) {
601 /* data parsers put all the parent nodes in the set, but they are not connected */
602 str = lyd_path_set(&log_location.dnodes, LYD_PATH_STD);
603
604 /* sometimes the last node is not created yet and we only have the schema node */
605 if (log_location.scnodes.count) {
606 ly_vlog_build_path_append(&str, log_location.scnodes.objs[log_location.scnodes.count - 1], dnode);
607 }
608 } else {
609 str = lyd_path(log_location.dnodes.objs[log_location.dnodes.count - 1], LYD_PATH_STD, NULL, 0);
610 }
611 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
612
613 r = asprintf(path, "Data location \"%s\"", str);
614 free(str);
615 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
616 } else if (log_location.scnodes.count) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100617 str = lysc_path(log_location.scnodes.objs[log_location.scnodes.count - 1], LYSC_PATH_LOG, NULL, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100618 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
619
Michal Vaskodbf3e652022-10-21 08:46:25 +0200620 r = asprintf(path, "Schema location \"%s\"", str);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100621 free(str);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200622 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100623 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100624
Michal Vaskodbf3e652022-10-21 08:46:25 +0200625 /* line */
626 prev = *path;
Radek Krejciddace2c2021-01-08 11:30:56 +0100627 if (log_location.line) {
Michal Vaskodbf3e652022-10-21 08:46:25 +0200628 r = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L", log_location.line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100629 free(prev);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200630 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100631
Radek Krejciddace2c2021-01-08 11:30:56 +0100632 log_location.line = 0;
633 } else if (log_location.inputs.count) {
Michal Vaskodbf3e652022-10-21 08:46:25 +0200634 r = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L",
Radek Krejciddace2c2021-01-08 11:30:56 +0100635 ((struct ly_in *)log_location.inputs.objs[log_location.inputs.count - 1])->line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100636 free(prev);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200637 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100638 }
639
640 if (*path) {
641 prev = *path;
Michal Vaskodbf3e652022-10-21 08:46:25 +0200642 r = asprintf(path, "%s.", prev);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100643 free(prev);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200644 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100645 }
Radek Krejci94aa9942018-09-07 17:12:17 +0200646 }
647
Radek Krejci94aa9942018-09-07 17:12:17 +0200648 return LY_SUCCESS;
649}
650
651void
Michal Vaskoe9391c72021-10-05 10:04:56 +0200652ly_vlog(const struct ly_ctx *ctx, const char *apptag, LY_VECODE code, const char *format, ...)
Radek Krejci94aa9942018-09-07 17:12:17 +0200653{
654 va_list ap;
Michal Vasko22df3f02020-08-24 13:29:22 +0200655 char *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200656
Václav Kubernátd367ad92021-11-29 09:28:56 +0100657 if (ATOMIC_LOAD_RELAXED(path_flag) && ctx) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100658 ly_vlog_build_path(ctx, &path);
Radek Krejci94aa9942018-09-07 17:12:17 +0200659 }
660
661 va_start(ap, format);
Michal Vaskoe9391c72021-10-05 10:04:56 +0200662 log_vprintf(ctx, LY_LLERR, LY_EVALID, code, path, apptag, format, ap);
Radek Krejci94aa9942018-09-07 17:12:17 +0200663 /* path is spent and should not be freed! */
664 va_end(ap);
665}
666
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100667LIBYANG_API_DEF void
Radek Krejci0b013302021-03-29 15:22:32 +0200668lyplg_ext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path, const char *format, ...)
Radek Krejci0935f412019-08-20 16:15:18 +0200669{
670 va_list ap;
671 char *plugin_msg;
672 int ret;
673
Václav Kubernátd367ad92021-11-29 09:28:56 +0100674 if (ATOMIC_LOAD_RELAXED(ly_ll) < level) {
Radek Krejci0935f412019-08-20 16:15:18 +0200675 return;
676 }
Radek Krejci932d3bb2021-02-09 16:29:38 +0100677 ret = asprintf(&plugin_msg, "Extension plugin \"%s\": %s", ext->def->plugin->id, format);
Radek Krejci0935f412019-08-20 16:15:18 +0200678 if (ret == -1) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200679 LOGMEM(ext->module->ctx);
Radek Krejci0935f412019-08-20 16:15:18 +0200680 return;
681 }
682
683 va_start(ap, format);
Michal Vaskoe9391c72021-10-05 10:04:56 +0200684 log_vprintf(ext->module->ctx, level, (level == LY_LLERR ? LY_EPLUGIN : 0) | err_no, LYVE_OTHER,
685 path ? strdup(path) : NULL, NULL, plugin_msg, ap);
Radek Krejci0935f412019-08-20 16:15:18 +0200686 va_end(ap);
687
688 free(plugin_msg);
689}
690
Michal Vasko177d0ed2020-11-23 16:43:03 +0100691/**
Michal Vaskoc78a6092021-05-07 15:27:35 +0200692 * @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 +0100693 */
694static void
Michal Vaskoc78a6092021-05-07 15:27:35 +0200695_ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem, const char *format, ...)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200696{
Michal Vasko177d0ed2020-11-23 16:43:03 +0100697 va_list ap;
698 char *path_dup = NULL;
699
700 LY_CHECK_ARG_RET(ctx, eitem, );
701
702 if (eitem->path) {
703 /* duplicate path because it will be freed */
704 path_dup = strdup(eitem->path);
705 LY_CHECK_ERR_RET(!path_dup, LOGMEM(ctx), );
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200706 }
Michal Vasko177d0ed2020-11-23 16:43:03 +0100707
Michal Vaskoc78a6092021-05-07 15:27:35 +0200708 va_start(ap, format);
Michal Vaskoe9391c72021-10-05 10:04:56 +0200709 log_vprintf(ctx, eitem->level, eitem->no, eitem->vecode, path_dup, eitem->apptag, format, ap);
Michal Vasko177d0ed2020-11-23 16:43:03 +0100710 va_end(ap);
Michal Vasko177d0ed2020-11-23 16:43:03 +0100711}
712
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100713LIBYANG_API_DEF void
Michal Vasko177d0ed2020-11-23 16:43:03 +0100714ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem)
715{
Michal Vaskoc78a6092021-05-07 15:27:35 +0200716 /* String ::ly_err_item.msg cannot be used directly because it may contain the % character */
717 _ly_err_print(ctx, eitem, "%s", eitem->msg);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200718}