blob: d13d327b2ea14665e7e11edf65de6b98d2009958 [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 Vasko193dacd2022-10-13 08:43:05 +02007 * Copyright (c) 2015 - 2022 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 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"
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 Vaskod8085612020-08-21 12:55:23 +020041static ly_log_clb log_clb;
Václav Kubernátd367ad92021-11-29 09:28:56 +010042static ATOMIC_T path_flag = 1;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020043#ifndef NDEBUG
Václav Kubernátd367ad92021-11-29 09:28:56 +010044ATOMIC_T ly_ldbg_groups = 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020045#endif
46
Radek Krejciddace2c2021-01-08 11:30:56 +010047THREAD_LOCAL struct ly_log_location_s log_location = {0};
48
Radek Krejci94aa9942018-09-07 17:12:17 +020049/* how many bytes add when enlarging buffers */
50#define LY_BUF_STEP 128
51
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010052LIBYANG_API_DEF LY_ERR
Radek Krejcid33273d2018-10-25 14:55:52 +020053ly_errcode(const struct ly_ctx *ctx)
54{
55 struct ly_err_item *i;
56
Radek Krejci572ee602020-09-16 14:35:08 +020057 i = ly_err_last(ctx);
Radek Krejcid33273d2018-10-25 14:55:52 +020058 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020059 return i->no;
Radek Krejcid33273d2018-10-25 14:55:52 +020060 }
61
62 return LY_SUCCESS;
63}
64
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010065LIBYANG_API_DEF LY_VECODE
Radek Krejci5aeea3a2018-09-05 13:29:36 +020066ly_vecode(const struct ly_ctx *ctx)
67{
68 struct ly_err_item *i;
69
Radek Krejci572ee602020-09-16 14:35:08 +020070 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020071 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020072 return i->vecode;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020073 }
74
75 return LYVE_SUCCESS;
76}
77
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010078LIBYANG_API_DEF const char *
Radek Krejci5aeea3a2018-09-05 13:29:36 +020079ly_errmsg(const struct ly_ctx *ctx)
80{
81 struct ly_err_item *i;
82
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020083 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020084
Radek Krejci572ee602020-09-16 14:35:08 +020085 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020086 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +020087 return i->msg;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020088 }
89
90 return NULL;
91}
92
Jan Kundrátc53a7ec2021-12-09 16:01:19 +010093LIBYANG_API_DEF const char *
Radek Krejci5aeea3a2018-09-05 13:29:36 +020094ly_errpath(const struct ly_ctx *ctx)
95{
96 struct ly_err_item *i;
97
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020098 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020099
Radek Krejci572ee602020-09-16 14:35:08 +0200100 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200101 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +0200102 return i->path;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200103 }
104
105 return NULL;
106}
107
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100108LIBYANG_API_DEF const char *
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200109ly_errapptag(const struct ly_ctx *ctx)
110{
111 struct ly_err_item *i;
112
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200113 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200114
Radek Krejci572ee602020-09-16 14:35:08 +0200115 i = ly_err_last(ctx);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200116 if (i) {
Radek Krejci572ee602020-09-16 14:35:08 +0200117 return i->apptag;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200118 }
119
120 return NULL;
121}
122
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100123LIBYANG_API_DEF LY_ERR
aPiecek6d618552021-06-18 10:02:59 +0200124ly_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 +0200125{
Radek Krejcidb0ee022021-03-15 16:53:44 +0100126 char *msg = NULL;
127 struct ly_err_item *e;
Radek Krejcie7b95092019-05-15 11:03:07 +0200128
Radek Krejcid43298b2021-03-25 16:17:15 +0100129 if (!err || (ecode == LY_SUCCESS)) {
Radek Krejcidb0ee022021-03-15 16:53:44 +0100130 /* nothing to do */
131 return ecode;
132 }
133
134 e = malloc(sizeof *e);
135 LY_CHECK_ERR_RET(!e, LOGMEM(NULL), LY_EMEM);
136 e->prev = (*err) ? (*err)->prev : e;
137 e->next = NULL;
138 if (*err) {
139 (*err)->prev->next = e;
140 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200141
142 /* fill in the information */
Radek Krejcidb0ee022021-03-15 16:53:44 +0100143 e->level = LY_LLERR;
144 e->no = ecode;
145 e->vecode = vecode;
146 e->path = path;
147 e->apptag = apptag;
Radek Krejcie7b95092019-05-15 11:03:07 +0200148
aPiecek6d618552021-06-18 10:02:59 +0200149 if (err_format) {
Radek Krejcidb0ee022021-03-15 16:53:44 +0100150 va_list print_args;
151
aPiecek6d618552021-06-18 10:02:59 +0200152 va_start(print_args, err_format);
Radek Krejcidb0ee022021-03-15 16:53:44 +0100153
aPiecek6d618552021-06-18 10:02:59 +0200154 if (vasprintf(&msg, err_format, print_args) == -1) {
155 /* we don't have anything more to do, just set msg to NULL to avoid undefined content,
Radek Krejcidb0ee022021-03-15 16:53:44 +0100156 * still keep the information about the original error instead of LY_EMEM or other printf's error */
157 msg = NULL;
158 }
159
160 va_end(print_args);
161 }
162 e->msg = msg;
163
164 if (!(*err)) {
165 *err = e;
166 }
167
168 return e->no;
Radek Krejcie7b95092019-05-15 11:03:07 +0200169}
170
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100171LIBYANG_API_DEF struct ly_err_item *
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200172ly_err_first(const struct ly_ctx *ctx)
173{
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200174 LY_CHECK_ARG_RET(NULL, ctx, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200175
176 return pthread_getspecific(ctx->errlist_key);
177}
178
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100179LIBYANG_API_DEF struct ly_err_item *
Radek Krejci572ee602020-09-16 14:35:08 +0200180ly_err_last(const struct ly_ctx *ctx)
181{
182 const struct ly_err_item *e;
183
184 LY_CHECK_ARG_RET(NULL, ctx, NULL);
185
186 e = pthread_getspecific(ctx->errlist_key);
187 return e ? e->prev : NULL;
188}
189
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100190LIBYANG_API_DEF void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200191ly_err_free(void *ptr)
192{
193 struct ly_err_item *i, *next;
194
195 /* clean the error list */
196 for (i = (struct ly_err_item *)ptr; i; i = next) {
197 next = i->next;
Radek Krejcidb0ee022021-03-15 16:53:44 +0100198 free(i->msg);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200199 free(i->path);
200 free(i->apptag);
201 free(i);
202 }
203}
204
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100205LIBYANG_API_DEF void
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200206ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
207{
208 struct ly_err_item *i, *first;
209
210 first = ly_err_first(ctx);
211 if (first == eitem) {
212 eitem = NULL;
213 }
214 if (eitem) {
215 /* disconnect the error */
Radek Krejci1e008d22020-08-17 11:37:37 +0200216 for (i = first; i && (i->next != eitem); i = i->next) {}
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200217 assert(i);
218 i->next = NULL;
219 first->prev = i;
220 /* free this err and newer */
221 ly_err_free(eitem);
222 } else {
223 /* free all err */
224 ly_err_free(first);
225 pthread_setspecific(ctx->errlist_key, NULL);
226 }
227}
228
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100229LIBYANG_API_DEF LY_LOG_LEVEL
Radek Krejci52b6d512020-10-12 12:33:17 +0200230ly_log_level(LY_LOG_LEVEL level)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200231{
Václav Kubernátd367ad92021-11-29 09:28:56 +0100232 LY_LOG_LEVEL prev = ATOMIC_LOAD_RELAXED(ly_ll);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200233
Václav Kubernátd367ad92021-11-29 09:28:56 +0100234 ATOMIC_STORE_RELAXED(ly_ll, level);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200235 return prev;
236}
237
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100238LIBYANG_API_DEF uint32_t
Radek Krejci1deb5be2020-08-26 16:43:36 +0200239ly_log_options(uint32_t opts)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200240{
Václav Kubernátd367ad92021-11-29 09:28:56 +0100241 uint32_t prev = ATOMIC_LOAD_RELAXED(ly_log_opts);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200242
Václav Kubernátd367ad92021-11-29 09:28:56 +0100243 ATOMIC_STORE_RELAXED(ly_log_opts, opts);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200244 return prev;
245}
246
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100247LIBYANG_API_DEF uint32_t
Radek Krejci68433c92020-10-12 17:03:55 +0200248ly_log_dbg_groups(uint32_t dbg_groups)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200249{
250#ifndef NDEBUG
Václav Kubernátd367ad92021-11-29 09:28:56 +0100251 uint32_t prev = ATOMIC_LOAD_RELAXED(ly_ldbg_groups);
Radek Krejciebdaed02020-11-09 13:05:06 +0100252
Václav Kubernátd367ad92021-11-29 09:28:56 +0100253 ATOMIC_STORE_RELAXED(ly_ldbg_groups, dbg_groups);
Radek Krejciebdaed02020-11-09 13:05:06 +0100254 return prev;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200255#else
256 (void)dbg_groups;
Radek Krejciebdaed02020-11-09 13:05:06 +0100257 return 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200258#endif
259}
260
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100261LIBYANG_API_DEF void
Radek Krejci857189e2020-09-01 13:26:36 +0200262ly_set_log_clb(ly_log_clb clb, ly_bool path)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200263{
Michal Vaskod8085612020-08-21 12:55:23 +0200264 log_clb = clb;
Václav Kubernátd367ad92021-11-29 09:28:56 +0100265 ATOMIC_STORE_RELAXED(path_flag, path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200266}
267
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100268LIBYANG_API_DEF ly_log_clb
Michal Vaskod8085612020-08-21 12:55:23 +0200269ly_get_log_clb(void)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200270{
Michal Vaskod8085612020-08-21 12:55:23 +0200271 return log_clb;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200272}
273
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100274void
Michal Vasko59e69e72022-02-18 09:18:21 +0100275ly_log_location(const struct lysc_node *scnode, const struct lyd_node *dnode, const char *path, const struct ly_in *in,
276 uint64_t line, ly_bool reset)
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100277{
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100278 if (scnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100279 ly_set_add(&log_location.scnodes, (void *)scnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100280 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100281 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100282 }
283
284 if (dnode) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100285 ly_set_add(&log_location.dnodes, (void *)dnode, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100286 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100287 ly_set_erase(&log_location.dnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100288 }
289
290 if (path) {
291 char *s = strdup(path);
Michal Vasko26bbb272022-08-02 14:54:33 +0200292
Radek Krejciddace2c2021-01-08 11:30:56 +0100293 LY_CHECK_ERR_RET(!s, LOGMEM(NULL), );
294 ly_set_add(&log_location.paths, s, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100295 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100296 ly_set_erase(&log_location.paths, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100297 }
298
299 if (in) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100300 ly_set_add(&log_location.inputs, (void *)in, 1, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100301 } else if (reset) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100302 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100303 }
304
305 if (line) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100306 log_location.line = line;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100307 }
308}
309
310void
Michal Vasko59e69e72022-02-18 09:18:21 +0100311ly_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 +0100312{
Radek Krejciddace2c2021-01-08 11:30:56 +0100313 for (uint32_t i = scnode_steps; i && log_location.scnodes.count; i--) {
314 log_location.scnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100315 }
316
Radek Krejciddace2c2021-01-08 11:30:56 +0100317 for (uint32_t i = dnode_steps; i && log_location.dnodes.count; i--) {
318 log_location.dnodes.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100319 }
320
Radek Krejciddace2c2021-01-08 11:30:56 +0100321 for (uint32_t i = path_steps; i && log_location.paths.count; i--) {
322 ly_set_rm_index(&log_location.paths, log_location.paths.count - 1, free);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100323 }
324
Radek Krejciddace2c2021-01-08 11:30:56 +0100325 for (uint32_t i = in_steps; i && log_location.inputs.count; i--) {
326 log_location.inputs.count--;
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100327 }
328
Radek Krejciddace2c2021-01-08 11:30:56 +0100329 /* deallocate the empty sets */
330 if (scnode_steps && !log_location.scnodes.count) {
331 ly_set_erase(&log_location.scnodes, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100332 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100333 if (dnode_steps && !log_location.dnodes.count) {
334 ly_set_erase(&log_location.dnodes, NULL);
335 }
336 if (path_steps && !log_location.paths.count) {
337 ly_set_erase(&log_location.paths, free);
338 }
339 if (in_steps && !log_location.inputs.count) {
340 ly_set_erase(&log_location.inputs, NULL);
Radek Krejciaddfc9a2020-12-17 20:46:35 +0100341 }
342}
343
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200344static LY_ERR
345log_store(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
346{
347 struct ly_err_item *eitem, *last;
348
349 assert(ctx && (level < LY_LLVRB));
350
351 eitem = pthread_getspecific(ctx->errlist_key);
352 if (!eitem) {
353 /* if we are only to fill in path, there must have been an error stored */
354 assert(msg);
355 eitem = malloc(sizeof *eitem);
356 LY_CHECK_GOTO(!eitem, mem_fail);
357 eitem->prev = eitem;
358 eitem->next = NULL;
359
360 pthread_setspecific(ctx->errlist_key, eitem);
361 } else if (!msg) {
362 /* only filling the path */
363 assert(path);
364
365 /* find last error */
366 eitem = eitem->prev;
367 do {
368 if (eitem->level == LY_LLERR) {
369 /* fill the path */
370 free(eitem->path);
371 eitem->path = path;
372 return LY_SUCCESS;
373 }
374 eitem = eitem->prev;
375 } while (eitem->prev->next);
376 /* last error was not found */
377 assert(0);
Václav Kubernátd367ad92021-11-29 09:28:56 +0100378 } else if ((ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE_LAST) == LY_LOSTORE_LAST) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200379 /* overwrite last message */
380 free(eitem->msg);
381 free(eitem->path);
382 free(eitem->apptag);
383 } else {
384 /* store new message */
385 last = eitem->prev;
386 eitem->prev = malloc(sizeof *eitem);
387 LY_CHECK_GOTO(!eitem->prev, mem_fail);
388 eitem = eitem->prev;
389 eitem->prev = last;
390 eitem->next = NULL;
391 last->next = eitem;
392 }
393
394 /* fill in the information */
395 eitem->level = level;
396 eitem->no = no;
397 eitem->vecode = vecode;
398 eitem->msg = msg;
399 eitem->path = path;
400 eitem->apptag = apptag;
401 return LY_SUCCESS;
402
403mem_fail:
404 LOGMEM(NULL);
405 free(msg);
406 free(path);
407 free(apptag);
408 return LY_EMEM;
409}
410
411static void
Michal Vaskoe9391c72021-10-05 10:04:56 +0200412log_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 +0200413 const char *format, va_list args)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200414{
415 char *msg = NULL;
Radek Krejci857189e2020-09-01 13:26:36 +0200416 ly_bool free_strs;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200417
Václav Kubernátd367ad92021-11-29 09:28:56 +0100418 if (level > ATOMIC_LOAD_RELAXED(ly_ll)) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200419 /* do not print or store the message */
420 free(path);
421 return;
422 }
423
Michal Vasko5a016922021-05-07 08:19:15 +0200424 if (no == LY_EMEM) {
425 /* just print it, anything else would most likely fail anyway */
Václav Kubernátd367ad92021-11-29 09:28:56 +0100426 if (ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOLOG) {
Michal Vasko5a016922021-05-07 08:19:15 +0200427 if (log_clb) {
428 log_clb(level, LY_EMEM_MSG, path);
429 } else {
430 fprintf(stderr, "libyang[%d]: ", level);
431 vfprintf(stderr, format, args);
432 if (path) {
433 fprintf(stderr, " (path: %s)\n", path);
434 } else {
435 fprintf(stderr, "\n");
436 }
437 }
438 }
439 free(path);
440 return;
441 }
442
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200443 /* 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 +0100444 if ((level < LY_LLVRB) && ctx && (ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200445 assert(format);
446 if (vasprintf(&msg, format, args) == -1) {
447 LOGMEM(ctx);
448 free(path);
449 return;
450 }
Radek Krejcic9e64a62020-09-18 20:08:12 +0200451 if (((no & ~LY_EPLUGIN) == LY_EVALID) && (vecode == LYVE_SUCCESS)) {
452 /* assume we are inheriting the error, so inherit vecode as well */
453 vecode = ly_vecode(ctx);
454 }
Michal Vaskoe9391c72021-10-05 10:04:56 +0200455 if (log_store(ctx, level, no, vecode, msg, path, apptag ? strdup(apptag) : NULL)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200456 return;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200457 }
458 free_strs = 0;
459 } else {
460 if (vasprintf(&msg, format, args) == -1) {
461 LOGMEM(ctx);
462 free(path);
463 return;
464 }
465 free_strs = 1;
466 }
467
468 /* if we are only storing errors internally, never print the message (yet) */
Václav Kubernátd367ad92021-11-29 09:28:56 +0100469 if (ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOLOG) {
Michal Vaskod8085612020-08-21 12:55:23 +0200470 if (log_clb) {
471 log_clb(level, msg, path);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200472 } else {
473 fprintf(stderr, "libyang[%d]: %s%s", level, msg, path ? " " : "\n");
474 if (path) {
475 fprintf(stderr, "(path: %s)\n", path);
476 }
477 }
478 }
479
480 if (free_strs) {
481 free(path);
482 free(msg);
483 }
484}
485
Radek Krejci4ab61562018-09-05 15:00:37 +0200486#ifndef NDEBUG
487
488void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200489ly_log_dbg(uint32_t group, const char *format, ...)
Radek Krejci4ab61562018-09-05 15:00:37 +0200490{
491 char *dbg_format;
492 const char *str_group;
493 va_list ap;
494
Václav Kubernátd367ad92021-11-29 09:28:56 +0100495 if (!(ATOMIC_LOAD_RELAXED(ly_ldbg_groups) & group)) {
Radek Krejci4ab61562018-09-05 15:00:37 +0200496 return;
497 }
498
499 switch (group) {
500 case LY_LDGDICT:
501 str_group = "DICT";
502 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200503 case LY_LDGXPATH:
504 str_group = "XPATH";
505 break;
Michal Vaskoe558f792021-07-28 08:20:15 +0200506 case LY_LDGDEPSETS:
507 str_group = "DEPSETS";
508 break;
Radek Krejci4ab61562018-09-05 15:00:37 +0200509 default:
510 LOGINT(NULL);
511 return;
512 }
513
514 if (asprintf(&dbg_format, "%s: %s", str_group, format) == -1) {
515 LOGMEM(NULL);
516 return;
517 }
518
519 va_start(ap, format);
Michal Vaskoe9391c72021-10-05 10:04:56 +0200520 log_vprintf(NULL, LY_LLDBG, 0, 0, NULL, NULL, dbg_format, ap);
Radek Krejci4ab61562018-09-05 15:00:37 +0200521 va_end(ap);
522}
523
524#endif
525
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200526void
527ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...)
528{
529 va_list ap;
530
531 va_start(ap, format);
Michal Vaskoe9391c72021-10-05 10:04:56 +0200532 log_vprintf(ctx, level, no, 0, NULL, NULL, format, ap);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200533 va_end(ap);
534}
535
Michal Vaskodbf3e652022-10-21 08:46:25 +0200536/**
537 * @brief Append a schema node name to a generated data path, only if it fits.
538 *
539 * @param[in,out] str Generated path to update.
540 * @param[in] snode Schema node to append.
541 * @param[in] parent Last printed data node.
542 * @return LY_ERR value.
543 */
544static LY_ERR
545ly_vlog_build_path_append(char **str, const struct lysc_node *snode, const struct lyd_node *parent)
546{
547 const struct lys_module *mod, *prev_mod;
548 uint32_t len, new_len;
549 void *mem;
550
551 if (snode->nodetype & (LYS_CHOICE | LYS_CASE)) {
552 /* schema-only node */
553 return LY_SUCCESS;
554 } else if (lysc_data_parent(snode) != parent->schema) {
555 /* not a direct descendant node */
556 return LY_SUCCESS;
557 }
558
559 /* get module to print, if any */
560 mod = snode->module;
561 prev_mod = (parent->schema) ? parent->schema->module : lyd_owner_module(parent);
562 if (prev_mod == mod) {
563 mod = NULL;
564 }
565
566 /* realloc string */
567 len = strlen(*str);
568 new_len = len + 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(snode->name);
569 mem = realloc(*str, new_len + 1);
570 LY_CHECK_ERR_RET(!mem, LOGMEM(LYD_CTX(parent)), LY_EMEM);
571 *str = mem;
572
573 /* print the last schema node */
574 sprintf(*str + len, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", snode->name);
575 return LY_SUCCESS;
576}
577
578/**
579 * @brief Build log path from the stored log location information.
580 *
581 * @param[in] ctx Context to use.
582 * @param[out] path Generated log path.
583 * @return LY_ERR value.
584 */
Radek Krejci94aa9942018-09-07 17:12:17 +0200585static LY_ERR
Radek Krejciddace2c2021-01-08 11:30:56 +0100586ly_vlog_build_path(const struct ly_ctx *ctx, char **path)
Radek Krejci94aa9942018-09-07 17:12:17 +0200587{
Michal Vaskodbf3e652022-10-21 08:46:25 +0200588 int r;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100589 char *str = NULL, *prev = NULL;
Michal Vaskodbf3e652022-10-21 08:46:25 +0200590 const struct lyd_node *dnode;
Radek Krejcicb3e6472021-01-06 08:19:01 +0100591
Radek Krejci2efc45b2020-12-22 16:25:44 +0100592 *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200593
Radek Krejciddace2c2021-01-08 11:30:56 +0100594 if (log_location.paths.count && ((const char *)(log_location.paths.objs[log_location.paths.count - 1]))[0]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100595 /* simply get what is in the provided path string */
Radek Krejciddace2c2021-01-08 11:30:56 +0100596 *path = strdup((const char *)log_location.paths.objs[log_location.paths.count - 1]);
Radek Krejcic04f0a22018-09-21 15:49:45 +0200597 LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100598 } else {
Michal Vaskodbf3e652022-10-21 08:46:25 +0200599 /* data/schema node */
600 if (log_location.dnodes.count) {
601 dnode = log_location.dnodes.objs[log_location.dnodes.count - 1];
Michal Vaskoa4dfb3c2022-10-25 14:59:31 +0200602 if (dnode->parent || !lysc_data_parent(dnode->schema)) {
603 /* data node with all of its parents */
604 str = lyd_path(log_location.dnodes.objs[log_location.dnodes.count - 1], LYD_PATH_STD, NULL, 0);
605 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
606 } else {
Michal Vaskodbf3e652022-10-21 08:46:25 +0200607 /* data parsers put all the parent nodes in the set, but they are not connected */
608 str = lyd_path_set(&log_location.dnodes, LYD_PATH_STD);
Michal Vasko3e65ee32022-10-21 10:09:51 +0200609 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
Michal Vaskoa4dfb3c2022-10-25 14:59:31 +0200610 }
Michal Vaskodbf3e652022-10-21 08:46:25 +0200611
Michal Vaskoa4dfb3c2022-10-25 14:59:31 +0200612 /* sometimes the last node is not created yet and we only have the schema node */
613 if (log_location.scnodes.count) {
614 ly_vlog_build_path_append(&str, log_location.scnodes.objs[log_location.scnodes.count - 1], dnode);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200615 }
Michal Vaskodbf3e652022-10-21 08:46:25 +0200616
617 r = asprintf(path, "Data location \"%s\"", str);
618 free(str);
619 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
620 } else if (log_location.scnodes.count) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100621 str = lysc_path(log_location.scnodes.objs[log_location.scnodes.count - 1], LYSC_PATH_LOG, NULL, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100622 LY_CHECK_ERR_RET(!str, LOGMEM(ctx), LY_EMEM);
623
Michal Vaskodbf3e652022-10-21 08:46:25 +0200624 r = asprintf(path, "Schema location \"%s\"", str);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100625 free(str);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200626 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100627 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100628
Michal Vaskodbf3e652022-10-21 08:46:25 +0200629 /* line */
630 prev = *path;
Radek Krejciddace2c2021-01-08 11:30:56 +0100631 if (log_location.line) {
Michal Vaskodbf3e652022-10-21 08:46:25 +0200632 r = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L", log_location.line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100633 free(prev);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200634 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100635
Radek Krejciddace2c2021-01-08 11:30:56 +0100636 log_location.line = 0;
637 } else if (log_location.inputs.count) {
Michal Vaskodbf3e652022-10-21 08:46:25 +0200638 r = asprintf(path, "%s%sine number %" PRIu64, prev ? prev : "", prev ? ", l" : "L",
Radek Krejciddace2c2021-01-08 11:30:56 +0100639 ((struct ly_in *)log_location.inputs.objs[log_location.inputs.count - 1])->line);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100640 free(prev);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200641 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100642 }
643
644 if (*path) {
645 prev = *path;
Michal Vaskodbf3e652022-10-21 08:46:25 +0200646 r = asprintf(path, "%s.", prev);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100647 free(prev);
Michal Vaskodbf3e652022-10-21 08:46:25 +0200648 LY_CHECK_ERR_RET(r == -1, LOGMEM(ctx), LY_EMEM);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100649 }
Radek Krejci94aa9942018-09-07 17:12:17 +0200650 }
651
Radek Krejci94aa9942018-09-07 17:12:17 +0200652 return LY_SUCCESS;
653}
654
655void
Michal Vaskoe9391c72021-10-05 10:04:56 +0200656ly_vlog(const struct ly_ctx *ctx, const char *apptag, LY_VECODE code, const char *format, ...)
Radek Krejci94aa9942018-09-07 17:12:17 +0200657{
658 va_list ap;
Michal Vasko22df3f02020-08-24 13:29:22 +0200659 char *path = NULL;
Radek Krejci94aa9942018-09-07 17:12:17 +0200660
Václav Kubernátd367ad92021-11-29 09:28:56 +0100661 if (ATOMIC_LOAD_RELAXED(path_flag) && ctx) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100662 ly_vlog_build_path(ctx, &path);
Radek Krejci94aa9942018-09-07 17:12:17 +0200663 }
664
665 va_start(ap, format);
Michal Vaskoe9391c72021-10-05 10:04:56 +0200666 log_vprintf(ctx, LY_LLERR, LY_EVALID, code, path, apptag, format, ap);
Radek Krejci94aa9942018-09-07 17:12:17 +0200667 /* path is spent and should not be freed! */
668 va_end(ap);
669}
670
Michal Vasko193dacd2022-10-13 08:43:05 +0200671/**
672 * @brief Print a log message from an extension plugin callback.
673 *
674 * @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
675 * @param[in] plugin_name Name of the plugin generating the message.
676 * @param[in] level Log message level (error, warning, etc.)
677 * @param[in] err_no Error type code.
678 * @param[in] path Optional path of the error.
679 * @param[in] format Format string to print.
680 * @param[in] ap Var arg list for @p format.
681 */
682static void
683ly_ext_log(const struct ly_ctx *ctx, const char *plugin_name, LY_LOG_LEVEL level, LY_ERR err_no, const char *path,
684 const char *format, va_list ap)
Radek Krejci0935f412019-08-20 16:15:18 +0200685{
Radek Krejci0935f412019-08-20 16:15:18 +0200686 char *plugin_msg;
Radek Krejci0935f412019-08-20 16:15:18 +0200687
Václav Kubernátd367ad92021-11-29 09:28:56 +0100688 if (ATOMIC_LOAD_RELAXED(ly_ll) < level) {
Radek Krejci0935f412019-08-20 16:15:18 +0200689 return;
690 }
Michal Vasko193dacd2022-10-13 08:43:05 +0200691 if (asprintf(&plugin_msg, "Ext plugin \"%s\": %s", plugin_name, format) == -1) {
692 LOGMEM(ctx);
Radek Krejci0935f412019-08-20 16:15:18 +0200693 return;
694 }
695
Michal Vasko193dacd2022-10-13 08:43:05 +0200696 log_vprintf(ctx, level, (level == LY_LLERR ? LY_EPLUGIN : 0) | err_no, LYVE_OTHER, path ? strdup(path) : NULL, NULL,
697 plugin_msg, ap);
698 free(plugin_msg);
699}
700
701LIBYANG_API_DEF void
702lyplg_ext_parse_log(const struct lysp_ctx *pctx, const struct lysp_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no,
703 const char *format, ...)
704{
705 va_list ap;
706 char *path = NULL;
707
708 if (ATOMIC_LOAD_RELAXED(path_flag)) {
709 ly_vlog_build_path(PARSER_CTX(pctx), &path);
710 }
711
Radek Krejci0935f412019-08-20 16:15:18 +0200712 va_start(ap, format);
Michal Vasko193dacd2022-10-13 08:43:05 +0200713 ly_ext_log(PARSER_CTX(pctx), ext->record->plugin.id, level, err_no, path, format, ap);
Radek Krejci0935f412019-08-20 16:15:18 +0200714 va_end(ap);
715
Michal Vasko193dacd2022-10-13 08:43:05 +0200716 free(path);
717}
718
719LIBYANG_API_DEF void
720lyplg_ext_compile_log(const struct lysc_ctx *cctx, const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no,
721 const char *format, ...)
722{
723 va_list ap;
724
725 va_start(ap, format);
726 ly_ext_log(ext->module->ctx, ext->def->plugin->id, level, err_no, cctx ? cctx->path : NULL, format, ap);
727 va_end(ap);
728}
729
730LIBYANG_API_DEF void
731lyplg_ext_compile_log_path(const char *path, const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no,
732 const char *format, ...)
733{
734 va_list ap;
735
736 va_start(ap, format);
737 ly_ext_log(ext->module->ctx, ext->def->plugin->id, level, err_no, path, format, ap);
738 va_end(ap);
Radek Krejci0935f412019-08-20 16:15:18 +0200739}
740
Michal Vasko177d0ed2020-11-23 16:43:03 +0100741/**
Michal Vaskoc78a6092021-05-07 15:27:35 +0200742 * @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 +0100743 */
744static void
Michal Vaskoc78a6092021-05-07 15:27:35 +0200745_ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem, const char *format, ...)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200746{
Michal Vasko177d0ed2020-11-23 16:43:03 +0100747 va_list ap;
748 char *path_dup = NULL;
749
750 LY_CHECK_ARG_RET(ctx, eitem, );
751
752 if (eitem->path) {
753 /* duplicate path because it will be freed */
754 path_dup = strdup(eitem->path);
755 LY_CHECK_ERR_RET(!path_dup, LOGMEM(ctx), );
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200756 }
Michal Vasko177d0ed2020-11-23 16:43:03 +0100757
Michal Vaskoc78a6092021-05-07 15:27:35 +0200758 va_start(ap, format);
Michal Vaskoe9391c72021-10-05 10:04:56 +0200759 log_vprintf(ctx, eitem->level, eitem->no, eitem->vecode, path_dup, eitem->apptag, format, ap);
Michal Vasko177d0ed2020-11-23 16:43:03 +0100760 va_end(ap);
Michal Vasko177d0ed2020-11-23 16:43:03 +0100761}
762
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100763LIBYANG_API_DEF void
Michal Vasko177d0ed2020-11-23 16:43:03 +0100764ly_err_print(const struct ly_ctx *ctx, struct ly_err_item *eitem)
765{
Michal Vaskoc78a6092021-05-07 15:27:35 +0200766 /* String ::ly_err_item.msg cannot be used directly because it may contain the % character */
767 _ly_err_print(ctx, eitem, "%s", eitem->msg);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200768}