Added CLICON_LOG_DESTINATION and CLICON_LOG_FILE for al applications

This commit is contained in:
Olof hagsand 2024-06-19 12:28:39 +02:00
parent 26062d7003
commit 0234ed94bc
22 changed files with 498 additions and 163 deletions

View file

@ -29,7 +29,9 @@ Expected: June 2024
* CLI support for multiple inline commands separated by semi-colon * CLI support for multiple inline commands separated by semi-colon
* New `clixon-config@2024-04-01.yang` revision * New `clixon-config@2024-04-01.yang` revision
* Added options: * Added options:
- `CLICON_DEBUG`: Debug flags, partly implemented. - `CLICON_LOG_DESTINATION`: Default log destination
- `CLICON_LOG_FILE`: Which file to log to if file logging
- `CLICON_DEBUG`: Debug flags
- `CLICON_YANG_SCHEMA_MOUNT_SHARE`: Share same YANGs of several moint-points - `CLICON_YANG_SCHEMA_MOUNT_SHARE`: Share same YANGs of several moint-points
- `CLICON_SOCK_PRIO`: Enable socket event priority - `CLICON_SOCK_PRIO`: Enable socket event priority
- `CLICON_XMLDB_MULTI`: Split datastore into multiple sub files - `CLICON_XMLDB_MULTI`: Split datastore into multiple sub files

View file

@ -537,6 +537,7 @@ main(int argc,
int config_dump; int config_dump;
enum format_enum config_dump_format = FORMAT_XML; enum format_enum config_dump_format = FORMAT_XML;
int print_version = 0; int print_version = 0;
int32_t d;
/* Initiate CLICON handle */ /* Initiate CLICON handle */
if ((h = backend_handle_init()) == NULL) if ((h = backend_handle_init()) == NULL)
@ -572,16 +573,15 @@ main(int argc,
cligen_output(stdout, "Clixon version: %s\n", CLIXON_GITHASH); cligen_output(stdout, "Clixon version: %s\n", CLIXON_GITHASH);
print_version++; /* plugins may also print versions w ca-version callback */ print_version++; /* plugins may also print versions w ca-version callback */
break; break;
case 'D' : { /* debug */ case 'D' : /* debug */
int d = 0; /* Try first symbolic, then numeric match
/* Try first symbolic, then numeric match */ * Cant use yang_bits_map, too early in bootstrap, there is no yang */
if ((d = clixon_debug_str2key(optarg)) < 0 && if ((d = clixon_debug_str2key(optarg)) < 0 &&
sscanf(optarg, "%d", &d) != 1){ sscanf(optarg, "%u", &d) != 1){
usage(h, argv[0]); usage(h, argv[0]);
} }
dbg |= d; dbg |= d;
break; break;
}
case 'f': /* config file */ case 'f': /* config file */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
@ -592,13 +592,18 @@ main(int argc,
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg); clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg);
break; break;
case 'l': /* Log destination: s|e|o */ case 'l': /* Log destination: s|e|o|f<file> */
if ((logdst = clixon_log_opt(optarg[0])) < 0) if ((d = clixon_logdst_str2key(optarg)) < 0){
usage(h, argv[0]); if (optarg[0] == 'f'){ /* Check for special -lf<file> syntax */
if (logdst == CLIXON_LOG_FILE && d = CLIXON_LOG_FILE;
strlen(optarg)>1 && if (strlen(optarg) > 1 &&
clixon_log_file(optarg+1) < 0) clixon_log_file(optarg+1) < 0)
goto done; goto done;
}
else
usage(h, argv[0]);
}
logdst = d;
break; break;
} }
/* /*
@ -618,7 +623,9 @@ main(int argc,
usage(h, argv[0]); usage(h, argv[0]);
goto done; goto done;
} }
/* Read debug and log options from config file if not given by command-line */
if (clixon_options_main_helper(h, dbg, logdst, __PROGRAM__) < 0)
goto done;
/* Initialize plugin module by creating a handle holding plugin and callback lists */ /* Initialize plugin module by creating a handle holding plugin and callback lists */
if (clixon_plugin_module_init(h) < 0) if (clixon_plugin_module_init(h) < 0)
goto done; goto done;

View file

@ -562,7 +562,7 @@ main(int argc,
clixon_handle h; clixon_handle h;
int logclisyntax = 0; int logclisyntax = 0;
int help = 0; int help = 0;
int logdst = CLIXON_LOG_STDERR; uint32_t logdst = 0;
char *restarg = NULL; /* what remains after options */ char *restarg = NULL; /* what remains after options */
yang_stmt *yspec; yang_stmt *yspec;
struct passwd *pw; struct passwd *pw;
@ -571,11 +571,12 @@ main(int argc,
cvec *nsctx_global = NULL; /* Global namespace context */ cvec *nsctx_global = NULL; /* Global namespace context */
size_t cligen_buflen; size_t cligen_buflen;
size_t cligen_bufthreshold; size_t cligen_bufthreshold;
int dbg=0; uint32_t dbg=0;
int nr; int nr;
int config_dump; int config_dump;
enum format_enum config_dump_format = FORMAT_XML; enum format_enum config_dump_format = FORMAT_XML;
int print_version = 0; int print_version = 0;
int32_t d;
/* Defaults */ /* Defaults */
once = 0; once = 0;
@ -608,7 +609,7 @@ main(int argc,
*/ */
optind = 1; optind = 1;
opterr = 0; opterr = 0;
while ((c = getopt(argc, argv, CLI_OPTS)) != -1) while ((c = getopt(argc, argv, CLI_OPTS)) != -1) {
switch (c) { switch (c) {
case 'h': case 'h':
/* Defer the call to usage() to later. Reason is that for helpful /* Defer the call to usage() to later. Reason is that for helpful
@ -622,16 +623,15 @@ main(int argc,
cligen_output(stdout, "Clixon version: %s\n", CLIXON_GITHASH); cligen_output(stdout, "Clixon version: %s\n", CLIXON_GITHASH);
print_version++; /* plugins may also print versions w ca-version callback */ print_version++; /* plugins may also print versions w ca-version callback */
break; break;
case 'D' : { /* debug */ case 'D' : /* debug, if set here overrides option CLICON_DEBUG */
int d = 0; /* Try first symbolic, then numeric match
/* Try first symbolic, then numeric match */ * Cant use yang_bits_map, too early in bootstrap, there is no yang */
if ((d = clixon_debug_str2key(optarg)) < 0 && if ((d = clixon_debug_str2key(optarg)) < 0 &&
sscanf(optarg, "%d", &d) != 1){ sscanf(optarg, "%d", &d) != 1){
usage(h, argv[0]); usage(h, argv[0]);
} }
dbg |= d; dbg |= d;
break; break;
}
case 'f': /* config file */ case 'f': /* config file */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
@ -642,19 +642,25 @@ main(int argc,
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg); clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg);
break; break;
case 'l': /* Log destination: s|e|o|f */ case 'l': /* Log destination: s|e|o|f<file> */
if ((logdst = clixon_log_opt(optarg[0])) < 0) if ((d = clixon_logdst_str2key(optarg)) < 0){
usage(h, argv[0]); if (optarg[0] == 'f'){ /* Check for special -lf<file> syntax */
if (logdst == CLIXON_LOG_FILE && d = CLIXON_LOG_FILE;
strlen(optarg)>1 && if (strlen(optarg) > 1 &&
clixon_log_file(optarg+1) < 0) clixon_log_file(optarg+1) < 0)
goto done; goto done;
}
else
usage(h, argv[0]);
}
logdst = d;
break; break;
} }
}
/* /*
* Logs, error and debug to stderr or syslog, set debug level * Logs, error and debug to stderr or syslog, set debug level
*/ */
clixon_log_init(h, __PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst); clixon_log_init(h, __PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst?logdst:CLIXON_LOG_STDERR);
clixon_debug_init(h, dbg); clixon_debug_init(h, dbg);
yang_init(h); yang_init(h);
@ -763,25 +769,10 @@ main(int argc,
/* Defer: Wait to the last minute to print help message */ /* Defer: Wait to the last minute to print help message */
if (help) if (help)
usage(h, argv[0]); usage(h, argv[0]);
/* Unless -D, set debug level to CLICON_DEBUG set
* Only works for one value.
*/
{
char *dstr;
int d = 0;
dstr = clicon_option_str(h, "CLICON_DEBUG"); /* Read debug and log options from config file if not given by command-line */
if (dbg == 0 && dstr && strlen(dstr)){ if (clixon_options_main_helper(h, dbg, logdst, __PROGRAM__) < 0)
if ((d = clixon_debug_str2key(dstr)) < 0 &&
sscanf(optarg, "%d", &d) != 1){
clixon_err(OE_CFG, 0, "Parsing CLICON_DEBUG: %s", dstr);
goto done; goto done;
}
clixon_debug_init(h, d);
clixon_log_init(h, __PROGRAM__, d?LOG_DEBUG:LOG_INFO, logdst);
}
}
/* Split remaining argv/argc into <cmd> and <extra-options> */ /* Split remaining argv/argc into <cmd> and <extra-options> */
if (options_split(h, argv0, argc, argv, &restarg) < 0) if (options_split(h, argv0, argc, argv, &restarg) < 0)
goto done; goto done;
@ -983,8 +974,9 @@ main(int argc,
done: done:
if (restarg) if (restarg)
free(restarg); free(restarg);
// Gets in your face if we log on stderr /* Dont log terminate on stderr or stdout */
clixon_log_init(h, __PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */ clixon_log_init(h, __PROGRAM__, LOG_INFO,
clixon_get_logflags() & ~(CLIXON_LOG_STDERR|CLIXON_LOG_STDOUT));
clixon_log(h, LOG_NOTICE, "%s: %u Terminated", __PROGRAM__, getpid()); clixon_log(h, LOG_NOTICE, "%s: %u Terminated", __PROGRAM__, getpid());
if (h) if (h)
cli_terminate(h); cli_terminate(h);

View file

@ -116,7 +116,7 @@ netconf_add_request_attr(cxobj *xrpc,
if (xml_find_type(xrep, NULL, xml_name(xa), CX_ATTR) != NULL) if (xml_find_type(xrep, NULL, xml_name(xa), CX_ATTR) != NULL)
continue; /* Skip already present (dont overwrite) */ continue; /* Skip already present (dont overwrite) */
/* Filter all clixon-lib attributes and namespace declaration /* Filter all clixon-lib attributes and namespace declaration
* to acvoid leaking internal attributes to external NETCONF * to avoid leaking internal attributes to external NETCONF
* note this is only done on top-level. * note this is only done on top-level.
*/ */
if (xml_prefix(xa) && strcmp(xml_prefix(xa), CLIXON_LIB_PREFIX) == 0) if (xml_prefix(xa) && strcmp(xml_prefix(xa), CLIXON_LIB_PREFIX) == 0)
@ -687,6 +687,7 @@ main(int argc,
int config_dump = 0; int config_dump = 0;
enum format_enum config_dump_format = FORMAT_XML; enum format_enum config_dump_format = FORMAT_XML;
int print_version = 0; int print_version = 0;
int32_t d;
/* Create handle */ /* Create handle */
if ((h = clixon_handle_init()) == NULL) if ((h = clixon_handle_init()) == NULL)
@ -703,7 +704,7 @@ main(int argc,
} }
if (clicon_username_set(h, pw->pw_name) < 0) if (clicon_username_set(h, pw->pw_name) < 0)
goto done; goto done;
while ((c = getopt(argc, argv, NETCONF_OPTS)) != -1) while ((c = getopt(argc, argv, NETCONF_OPTS)) != -1) {
switch (c) { switch (c) {
case 'h' : /* help */ case 'h' : /* help */
usage(h, argv[0]); usage(h, argv[0]);
@ -712,16 +713,14 @@ main(int argc,
cligen_output(stdout, "Clixon version: %s\n", CLIXON_GITHASH); cligen_output(stdout, "Clixon version: %s\n", CLIXON_GITHASH);
print_version++; /* plugins may also print versions w ca-version callback */ print_version++; /* plugins may also print versions w ca-version callback */
break; break;
case 'D' : { /* debug */ case 'D' : /* debug */
int d = 0;
/* Try first symbolic, then numeric match */ /* Try first symbolic, then numeric match */
if ((d = clixon_debug_str2key(optarg)) < 0 && if ((d = clixon_debug_str2key(optarg)) < 0 &&
sscanf(optarg, "%d", &d) != 1){ sscanf(optarg, "%u", &d) != 1){
usage(h, argv[0]); usage(h, argv[0]);
} }
dbg |= d; dbg |= d;
break; break;
}
case 'f': /* override config file */ case 'f': /* override config file */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
@ -733,14 +732,22 @@ main(int argc,
clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg); clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg);
break; break;
case 'l': /* Log destination: s|e|o */ case 'l': /* Log destination: s|e|o */
if ((logdst = clixon_log_opt(optarg[0])) < 0) int32_t d;
usage(h, argv[0]); d = 0;
if (logdst == CLIXON_LOG_FILE && if ((d = clixon_logdst_str2key(optarg)) < 0){
strlen(optarg)>1 && if (optarg[0] == 'f'){ /* Check for special -lf<file> syntax */
d = CLIXON_LOG_FILE;
if (strlen(optarg) > 1 &&
clixon_log_file(optarg+1) < 0) clixon_log_file(optarg+1) < 0)
goto done; goto done;
}
else
usage(h, argv[0]);
}
logdst = d;
break; break;
} }
}
/* /*
* Logs, error and debug to stderr or syslog, set debug level * Logs, error and debug to stderr or syslog, set debug level
@ -833,6 +840,9 @@ main(int argc,
argc -= optind; argc -= optind;
argv += optind; argv += optind;
/* Read debug and log options from config file if not given by command-line */
if (clixon_options_main_helper(h, dbg, logdst, __PROGRAM__) < 0)
goto done;
/* Access the remaining argv/argc options (after --) w clicon-argv_get() */ /* Access the remaining argv/argc options (after --) w clicon-argv_get() */
clicon_argv_set(h, argv0, argc, argv); clicon_argv_set(h, argv0, argc, argv);

View file

@ -329,6 +329,7 @@ main(int argc,
enum format_enum config_dump_format = FORMAT_XML; enum format_enum config_dump_format = FORMAT_XML;
int print_version = 0; int print_version = 0;
int stream_timeout = 0; int stream_timeout = 0;
int32_t d;
/* Create handle */ /* Create handle */
if ((h = restconf_handle_init()) == NULL) if ((h = restconf_handle_init()) == NULL)
@ -351,7 +352,6 @@ main(int argc,
print_version++; /* plugins may also print versions w ca-version callback */ print_version++; /* plugins may also print versions w ca-version callback */
break; break;
case 'D' : { /* debug */ case 'D' : { /* debug */
int d = 0;
/* Try first symbolic, then numeric match */ /* Try first symbolic, then numeric match */
if ((d = clixon_debug_str2key(optarg)) < 0 && if ((d = clixon_debug_str2key(optarg)) < 0 &&
sscanf(optarg, "%d", &d) != 1){ sscanf(optarg, "%d", &d) != 1){
@ -371,12 +371,17 @@ main(int argc,
clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg); clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg);
break; break;
case 'l': /* Log destination: s|e|o */ case 'l': /* Log destination: s|e|o */
if ((logdst = clixon_log_opt(optarg[0])) < 0) if ((d = clixon_logdst_str2key(optarg)) < 0){
usage(h, argv[0]); if (optarg[0] == 'f'){ /* Check for special -lf<file> syntax */
if (logdst == CLIXON_LOG_FILE && d = CLIXON_LOG_FILE;
strlen(optarg)>1 && if (strlen(optarg) > 1 &&
clixon_log_file(optarg+1) < 0) clixon_log_file(optarg+1) < 0)
goto done; goto done;
}
else
usage(h, argv[0]);
}
logdst = d;
break; break;
} /* switch getopt */ } /* switch getopt */
@ -466,6 +471,9 @@ main(int argc,
argc -= optind; argc -= optind;
argv += optind; argv += optind;
/* Read debug and log options from config file if not given by command-line */
if (clixon_options_main_helper(h, dbg, logdst, __PROGRAM__) < 0)
goto done;
/* Access the remaining argv/argc options (after --) w clicon-argv_get() */ /* Access the remaining argv/argc options (after --) w clicon-argv_get() */
clicon_argv_set(h, argv0, argc, argv); clicon_argv_set(h, argv0, argc, argv);

View file

@ -1168,6 +1168,7 @@ main(int argc,
enum format_enum config_dump_format = FORMAT_XML; enum format_enum config_dump_format = FORMAT_XML;
int print_version = 0; int print_version = 0;
int stream_timeout = 0; int stream_timeout = 0;
int32_t d;
/* Create handle */ /* Create handle */
if ((h = restconf_handle_init()) == NULL) if ((h = restconf_handle_init()) == NULL)
@ -1187,17 +1188,13 @@ main(int argc,
cligen_output(stdout, "Clixon version: %s\n", CLIXON_GITHASH); cligen_output(stdout, "Clixon version: %s\n", CLIXON_GITHASH);
print_version++; /* plugins may also print versions w ca-version callback */ print_version++; /* plugins may also print versions w ca-version callback */
break; break;
case 'D' : { /* debug. Note this overrides any setting in the config */ case 'D' : /* debug. Note this overrides any setting in the config */
int d = 0;
/* Try first symbolic, then numeric match */ /* Try first symbolic, then numeric match */
if ((d = clixon_debug_str2key(optarg)) < 0 && if ((d = clixon_debug_str2key(optarg)) < 0 &&
sscanf(optarg, "%d", &d) != 1){ sscanf(optarg, "%d", &d) != 1){
usage(h, argv[0]); usage(h, argv[0]);
} }
dbg |= d; dbg |= d;
break;
}
break; break;
case 'f': /* override config file */ case 'f': /* override config file */
if (!strlen(optarg)) if (!strlen(optarg))
@ -1210,12 +1207,17 @@ main(int argc,
clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg); clicon_option_str_set(h, "CLICON_CONFIGDIR", optarg);
break; break;
case 'l': /* Log destination: s|e|o */ case 'l': /* Log destination: s|e|o */
if ((logdst = clixon_log_opt(optarg[0])) < 0) if ((d = clixon_logdst_str2key(optarg)) < 0){
usage(h, argv0); if (optarg[0] == 'f'){ /* Check for special -lf<file> syntax */
if (logdst == CLIXON_LOG_FILE && d = CLIXON_LOG_FILE;
strlen(optarg)>1 && if (strlen(optarg) > 1 &&
clixon_log_file(optarg+1) < 0) clixon_log_file(optarg+1) < 0)
goto done; goto done;
}
else
usage(h, argv[0]);
}
logdst = d;
break; break;
} /* switch getopt */ } /* switch getopt */
@ -1324,6 +1326,10 @@ main(int argc,
argc -= optind; argc -= optind;
argv += optind; argv += optind;
/* Read debug and log options from config file if not given by command-line */
if (clixon_options_main_helper(h, dbg, logdst, __PROGRAM__) < 0)
goto done;
/* Access the remaining argv/argc options (after --) w clicon-argv_get() */ /* Access the remaining argv/argc options (after --) w clicon-argv_get() */
clicon_argv_set(h, argv0, argc, argv); clicon_argv_set(h, argv0, argc, argv);

View file

@ -359,6 +359,7 @@ main(int argc,
int config_dump = 0; int config_dump = 0;
enum format_enum config_dump_format = FORMAT_XML; enum format_enum config_dump_format = FORMAT_XML;
int print_version = 0; int print_version = 0;
int32_t d;
/* Create handle */ /* Create handle */
if ((h = clixon_handle_init()) == NULL) if ((h = clixon_handle_init()) == NULL)
@ -386,7 +387,7 @@ main(int argc,
print_version++; /* plugins may also print versions w ca-version callback */ print_version++; /* plugins may also print versions w ca-version callback */
break; break;
case 'D' : { /* debug */ case 'D' : { /* debug */
int d = 0; int32_t d = 0;
/* Try first symbolic, then numeric match */ /* Try first symbolic, then numeric match */
if ((d = clixon_debug_str2key(optarg)) < 0 && if ((d = clixon_debug_str2key(optarg)) < 0 &&
sscanf(optarg, "%d", &d) != 1){ sscanf(optarg, "%d", &d) != 1){
@ -401,12 +402,17 @@ main(int argc,
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg); clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
break; break;
case 'l': /* Log destination: s|e|o */ case 'l': /* Log destination: s|e|o */
if ((logdst = clixon_log_opt(optarg[0])) < 0) if ((d = clixon_logdst_str2key(optarg)) < 0){
usage(h, argv[0]); if (optarg[0] == 'f'){ /* Check for special -lf<file> syntax */
if (logdst == CLIXON_LOG_FILE && d = CLIXON_LOG_FILE;
strlen(optarg)>1 && if (strlen(optarg) > 1 &&
clixon_log_file(optarg+1) < 0) clixon_log_file(optarg+1) < 0)
goto done; goto done;
}
else
usage(h, argv[0]);
}
logdst = d;
break; break;
} }
if (print_version) if (print_version)
@ -467,6 +473,9 @@ main(int argc,
argc -= optind; argc -= optind;
argv += optind; argv += optind;
/* Read debug and log options from config file if not given by command-line */
if (clixon_options_main_helper(h, dbg, logdst, __PROGRAM__) < 0)
goto done;
/* Access the remaining argv/argc options (after --) w clicon-argv_get() */ /* Access the remaining argv/argc options (after --) w clicon-argv_get() */
clicon_argv_set(h, argv0, argc, argv); clicon_argv_set(h, argv0, argc, argv);

View file

@ -46,9 +46,10 @@
* Constants * Constants
*/ */
/* Debug flags are seperated into subject areas and detail /*! Debug flags are separated into subject areas and detail
*
* @see dbgmap Symbolic mapping (if you change here you may need to change dbgmap) * @see dbgmap Symbolic mapping (if you change here you may need to change dbgmap)
* @see clixon_debug in clixon-lib.yang * @see also clixon_debug_t in clixon-lib.yang
*/ */
/* Detail level */ /* Detail level */
#define CLIXON_DBG_ALWAYS 0x00000000 /* Unconditionally logged */ #define CLIXON_DBG_ALWAYS 0x00000000 /* Unconditionally logged */

View file

@ -45,11 +45,15 @@
/* /*
* Constants * Constants
*/ */
/* Where to log (masks) */ /*! Log destination as bitfields (masks)
#define CLIXON_LOG_SYSLOG 1 /* print logs on syslog */ *
#define CLIXON_LOG_STDERR 2 /* print logs on stderr */ * @see logdstmap Symbolic mapping (if you change here you may need to change logdstmap)
#define CLIXON_LOG_STDOUT 4 /* print logs on stdout */ * @see also log_desination_t in clixon-config.yang
#define CLIXON_LOG_FILE 8 /* print logs on clicon_log_filename */ */
#define CLIXON_LOG_SYSLOG 0x01 /* print logs on syslog */
#define CLIXON_LOG_STDERR 0x02 /* print logs on stderr */
#define CLIXON_LOG_STDOUT 0x04 /* print logs on stdout */
#define CLIXON_LOG_FILE 0x08 /* print logs on clixon_log_filename */
/* What kind of log (only for customizable error/logs) */ /* What kind of log (only for customizable error/logs) */
enum clixon_log_type{ enum clixon_log_type{
@ -67,6 +71,8 @@ enum clixon_log_type{
/* /*
* Prototypes * Prototypes
*/ */
char *clixon_logdst_key2str(int keyword);
int clixon_logdst_str2key(char *str);
int clixon_log_init(clixon_handle h, char *ident, int upto, int flags); int clixon_log_init(clixon_handle h, char *ident, int upto, int flags);
int clixon_log_exit(void); int clixon_log_exit(void);
int clixon_log_opt(char c); int clixon_log_opt(char c);

View file

@ -112,6 +112,9 @@ int clicon_option_add(clixon_handle h, const char *name, char *value);
/* Initialize options: set defaults, read config-file, etc */ /* Initialize options: set defaults, read config-file, etc */
int clicon_options_main(clixon_handle h); int clicon_options_main(clixon_handle h);
/* Options debug and log helper function */
int clixon_options_main_helper(clixon_handle h, uint32_t dbg, uint32_t logdst, char *ident);
/*! Check if a clicon option has a value */ /*! Check if a clicon option has a value */
int clicon_option_exists(clixon_handle h, const char *name); int clicon_option_exists(clixon_handle h, const char *name);

View file

@ -77,8 +77,10 @@ int assign_namespace_element(cxobj *x0, cxobj *x1, cxobj *x1p);
int assign_namespace_body(cxobj *x0, cxobj *x1); int assign_namespace_body(cxobj *x0, cxobj *x1);
int xml_merge(cxobj *x0, cxobj *x1, yang_stmt *yspec, char **reason); int xml_merge(cxobj *x0, cxobj *x1, yang_stmt *yspec, char **reason);
int yang_valstr2enum(yang_stmt *ytype, char *valstr, char **enumstr); int yang_valstr2enum(yang_stmt *ytype, char *valstr, char **enumstr);
int yang_bitsstr2val(clixon_handle h, yang_stmt *ytype, char *bitsstr, unsigned char **snmpval, size_t *snmplen); int yang_bitsstr2val(clixon_handle h, yang_stmt *ytype, char *bitsstr, unsigned char **outval, size_t *outlen);
int yang_val2bitsstr(clixon_handle h, yang_stmt *ytype, unsigned char *snmpval, size_t snmplen, cbuf *cb); int yang_bitsstr2flags(yang_stmt *ytype, char *bitsstr, uint32_t *flags);
int yang_val2bitsstr(clixon_handle h, yang_stmt *ytype, unsigned char *outval, size_t snmplen, cbuf *cb);
int yang_bits_map(yang_stmt *yt, char *str, char *nodeid, uint32_t *flags);
int yang_enum2valstr(yang_stmt *ytype, char *enumstr, char **valstr); int yang_enum2valstr(yang_stmt *ytype, char *enumstr, char **valstr);
int yang_enum2int(yang_stmt *ytype, char *enumstr, int32_t *val); int yang_enum2int(yang_stmt *ytype, char *enumstr, int32_t *val);
int yang_enum_int_value(cxobj *node, int32_t *val); int yang_enum_int_value(cxobj *node, int32_t *val);

View file

@ -79,9 +79,20 @@
/* Cache handle since debug calls do not have handle parameter */ /* Cache handle since debug calls do not have handle parameter */
static clixon_handle _debug_clixon_h = NULL; static clixon_handle _debug_clixon_h = NULL;
/*! The global debug level. 0 means no debug
*
* @note There are pros and cons in having the debug state as a global variable. The
* alternative to bind it to the clicon handle (h) was considered but it limits its
* usefulness, since not all functions have access to a handle.
* A compromise solution is now in place where h can be provided in the function call, but
* tolerates NULL, in which case a cached handle is used.
*/
static int _debug_level = 0;
/*! Mapping between Clixon debug symbolic names <--> bitfields /*! Mapping between Clixon debug symbolic names <--> bitfields
* *
* Mapping between specific bitfields and symbolic names, note only perfect matches * Mapping between specific bitfields and symbolic names, note only perfect matches
* @note yang_bits_map can be used as alternative but this still neeeded in bootstrapping
*/ */
static const map_str2int dbgmap[] = { static const map_str2int dbgmap[] = {
{"default", CLIXON_DBG_DEFAULT}, {"default", CLIXON_DBG_DEFAULT},
@ -152,16 +163,6 @@ clixon_debug_key_dump(FILE *f)
return -1; return -1;
} }
/*! The global debug level. 0 means no debug
*
* @note There are pros and cons in having the debug state as a global variable. The
* alternative to bind it to the clicon handle (h) was considered but it limits its
* usefulness, since not all functions have access to a handle.
* A compromise solution is now in place where h can be provided in the function call, but
* tolerates NULL, in which case a cached handle is used.
*/
static int _debug_level = 0;
/*! Initialize debug messages. Set debug level. /*! Initialize debug messages. Set debug level.
* *
* Initialize debug module. The level is used together with clixon_debug(dbglevel) calls as follows: * Initialize debug module. The level is used together with clixon_debug(dbglevel) calls as follows:

View file

@ -60,6 +60,7 @@
/* clixon */ /* clixon */
#include "clixon_queue.h" #include "clixon_queue.h"
#include "clixon_hash.h" #include "clixon_hash.h"
#include "clixon_string.h"
#include "clixon_handle.h" #include "clixon_handle.h"
#include "clixon_yang.h" #include "clixon_yang.h"
#include "clixon_xml.h" #include "clixon_xml.h"
@ -87,6 +88,47 @@ static FILE *_log_file = NULL;
/* Truncate debug strings to this length. 0 means unlimited */ /* Truncate debug strings to this length. 0 means unlimited */
static int _log_trunc = 0; static int _log_trunc = 0;
/*! Mapping between Clixon debug symbolic names <--> bitfields
*
* Also inclode shorthands: s|e|o|f|n
* Mapping between specific bitfields and symbolic names, note only perfect matches
* @see typedef log_destination_t in clixon-config.yang
*/
static const map_str2int logdstmap[] = {
{"syslog", CLIXON_LOG_SYSLOG},
{"s", CLIXON_LOG_SYSLOG},
{"stderr", CLIXON_LOG_STDERR},
{"e", CLIXON_LOG_STDERR},
{"stdout", CLIXON_LOG_STDOUT},
{"o", CLIXON_LOG_STDOUT},
{"file", CLIXON_LOG_FILE},
{"f", CLIXON_LOG_FILE},
{"n", 0x0},
{NULL, -1}
};
/*! Map from clixon debug (specific) bitmask to string
*
* @param[in] int Bitfield, see CLIXON_LOG_SYSLOG and others
* @retval str String representation of bitfield
*/
char *
clixon_logdst_key2str(int keyword)
{
return (char*)clicon_int2str(logdstmap, keyword);
}
/*! Map from clixon log destination symbolic string to bitfield
*
* @param[in] str String representation of Clixon log destination bit
* @retval int Bit representation of bitfield
*/
int
clixon_logdst_str2key(char *str)
{
return clicon_str2int(logdstmap, str);
}
/*! Initialize system logger. /*! Initialize system logger.
* *
* Make syslog(3) calls with specified ident and gates calls of level upto specified level (upto). * Make syslog(3) calls with specified ident and gates calls of level upto specified level (upto).
@ -96,9 +138,7 @@ static int _log_trunc = 0;
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ident prefix that appears on syslog (eg 'cli') * @param[in] ident prefix that appears on syslog (eg 'cli')
* @param[in] upto log priority, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG (see syslog(3)). * @param[in] upto log priority, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG (see syslog(3)).
* @param[in] flags bitmask: if CLIXON_LOG_STDERR, then print logs to stderr * @param[in] flags Log destination bitmask
* if CLIXON_LOG_SYSLOG, then print logs to syslog
* You can do a combination of both
* @retval 0 OK * @retval 0 OK
* @code * @code
* clixon_log_init(__PROGRAM__, LOG_INFO, CLIXON_LOG_STDERR); * clixon_log_init(__PROGRAM__, LOG_INFO, CLIXON_LOG_STDERR);

View file

@ -73,7 +73,6 @@
#include "clixon_debug.h" #include "clixon_debug.h"
#include "clixon_string.h" #include "clixon_string.h"
#include "clixon_file.h" #include "clixon_file.h"
#include "clixon_xml_sort.h"
#include "clixon_json.h" #include "clixon_json.h"
#include "clixon_text_syntax.h" #include "clixon_text_syntax.h"
#include "clixon_proto.h" #include "clixon_proto.h"
@ -83,8 +82,10 @@
#include "clixon_xpath.h" #include "clixon_xpath.h"
#include "clixon_yang_parse_lib.h" #include "clixon_yang_parse_lib.h"
#include "clixon_netconf_lib.h" #include "clixon_netconf_lib.h"
#include "clixon_xml_sort.h"
#include "clixon_xml_nsctx.h" #include "clixon_xml_nsctx.h"
#include "clixon_xml_io.h" #include "clixon_xml_io.h"
#include "clixon_xml_map.h"
#include "clixon_validate.h" #include "clixon_validate.h"
#include "clixon_xml_default.h" #include "clixon_xml_default.h"
@ -725,6 +726,59 @@ clicon_options_main(clixon_handle h)
return retval; return retval;
} }
/*! Options debug and log helper function
*
* If no debug or log option set in command-line, read debug or log options from
* configure file.
* Also set log file if CLICON_LOG_FILE is set
* @param[in] h Clixon handle
* @param[in] dbg Debug bitmask
* @param[in] logdst Log destination bitmask
* @param[in] ident prefix that appears on syslog
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_options_main_helper(clixon_handle h,
uint32_t dbg,
uint32_t logdst,
char *ident)
{
int retval = -1;
int relog = 0;
char *dstr;
relog = 0;
dstr = clicon_option_str(h, "CLICON_DEBUG");
if (dbg == 0 && dstr && strlen(dstr)){
if (yang_bits_map(clicon_config_yang(h),
dstr,
"/cc:clixon-config/cc:CLICON_DEBUG",
&dbg) < 0)
goto done;
relog++;
}
dstr = clicon_option_str(h, "CLICON_LOG_DESTINATION");
if (logdst == 0 && dstr && strlen(dstr)){
logdst = 0;
if (yang_bits_map(clicon_config_yang(h),
dstr,
"/cc:clixon-config/cc:CLICON_LOG_DESTINATION",
&logdst) < 0)
goto done;
relog++;
}
if (relog){
clixon_debug_init(h, dbg);
clixon_log_init(h, ident, dbg?LOG_DEBUG:LOG_INFO, logdst?logdst:CLIXON_LOG_STDERR);
}
if ((dstr = clicon_option_str(h, "CLICON_LOG_FILE")) != NULL)
clixon_log_file(dstr);
retval = 0;
done:
return retval;
}
/*! Check if a clicon option has a value /*! Check if a clicon option has a value
* *
* @param[in] h clixon_handle * @param[in] h clixon_handle

View file

@ -1669,25 +1669,25 @@ yang_bits_pos(yang_stmt *ytype,
goto done; goto done;
} }
/*! Given a YANG (bits) type node and string value, return SNMP value for bits set. /*! Given a YANG (bits) type node and string value, return value for bits set.
* *
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ytype YANG type noden * @param[in] ytype YANG type noden
* @param[in] bitsstr Value of bits as space separated string * @param[in] bitsstr Value of bits as space separated string
* @param[out] snmpval SNMP value with all bits set for given bitsstr * @param[out] outval Value with all bits set for given bitsstr (free with free)
* @param[out] snmplen length of snmpval * @param[out] outlen Length of outval
* @retval 1 OK, result in snmpval * @retval 1 OK, result in outval
* @retval 0 Invalid, not found * @retval 0 Invalid, not found
* @retval -1 Error * @retval -1 Error
* @see yang_val2bitsstr * @see yang_val2bitsstr
* XXX de-snmp:ize * @note that the output is a vector of bits originally made for SNMP bitvectors (not integers)
*/ */
int int
yang_bitsstr2val(clixon_handle h, yang_bitsstr2val(clixon_handle h,
yang_stmt *ytype, yang_stmt *ytype,
char *bitsstr, char *bitsstr,
unsigned char **snmpval, unsigned char **outval,
size_t *snmplen) size_t *outlen)
{ {
int retval = -1; int retval = -1;
int i = 0; int i = 0;
@ -1699,7 +1699,7 @@ yang_bitsstr2val(clixon_handle h,
int ret = 0; int ret = 0;
uint32_t bitpos; uint32_t bitpos;
*snmplen = 0; *outlen = 0;
if ((buffer = calloc(CLIXON_BITS_POS_MAX / 8, sizeof(unsigned char))) == NULL){ if ((buffer = calloc(CLIXON_BITS_POS_MAX / 8, sizeof(unsigned char))) == NULL){
clixon_err(OE_UNIX, errno, "calloc"); clixon_err(OE_UNIX, errno, "calloc");
goto done; goto done;
@ -1719,19 +1719,19 @@ yang_bitsstr2val(clixon_handle h,
/* Set bit at correct byte and bit position */ /* Set bit at correct byte and bit position */
byte = bitpos / 8; byte = bitpos / 8;
buffer[byte] = buffer[byte] | (1 << (7 - (bitpos % 8))); buffer[byte] = buffer[byte] | (1 << (7 - (bitpos % 8)));
*snmplen = byte + 1; *outlen = byte + 1;
if (*snmplen >= CLIXON_BITS_POS_MAX) { if (*outlen >= CLIXON_BITS_POS_MAX) {
clixon_err(OE_UNIX, EINVAL, "bit position %zu out of range. (max. allowed %d)", clixon_err(OE_UNIX, EINVAL, "bit position %zu out of range. (max. allowed %d)",
*snmplen, CLIXON_BITS_POS_MAX); *outlen, CLIXON_BITS_POS_MAX);
goto done; goto done;
} }
} }
} }
if ((*snmpval = malloc(*snmplen)) == NULL){ if ((*outval = malloc(*outlen)) == NULL){
clixon_err(OE_UNIX, errno, "calloc"); clixon_err(OE_UNIX, errno, "calloc");
goto done; goto done;
} }
memcpy(*snmpval, buffer, *snmplen); memcpy(*outval, buffer, *outlen);
retval = 1; retval = 1;
done: done:
if (buffer) if (buffer)
@ -1744,24 +1744,81 @@ yang_bitsstr2val(clixon_handle h,
goto done; goto done;
} }
/*! Given a YANG (bits) type node and SNMP value, return the string value for all bits (flags) that are set. /*! Given a YANG (bits) type node and string value, return bit values in a uint64
*
* @param[in] ytype YANG type noden
* @param[in] bitsstr Value of bits as space separated string
* @param[out] flags Pointer to integer with bit values set according to C type
* @retval 1 OK, result in u64
* @retval 0 Invalid, not found
* @retval -1 Error
* @see yang_bitsstr2val for bit vector (snmp-like)
*/
int
yang_bitsstr2flags(yang_stmt *ytype,
char *bitsstr,
uint32_t *flags)
{
int retval = -1;
int i = 0;
char **vec = NULL;
char *v;
int nvec;
int ret = 0;
uint32_t bitpos;
if (flags == NULL){
clixon_err(OE_UNIX, EINVAL, "flags is NULL");
goto done;
}
if ((vec = clicon_strsep(bitsstr, " ", &nvec)) == NULL){
clixon_err(OE_UNIX, EINVAL, "split string failed");
goto done;
}
/* Go over all set flags in given bitstring */
for (i=0; i<nvec; i++){
v = clixon_trim(vec[i]);
if (strlen(v) > 0) {
if ((ret = yang_bits_pos(ytype, v, &bitpos)) < 0)
goto done;
if (ret == 0)
goto fail;
if (bitpos >= 32) {
clixon_err(OE_UNIX, EINVAL, "bit position %u out of range. (max. allowed %d)",
bitpos, 32);
goto done;
}
*flags |= (1 << bitpos);
}
}
retval = 1;
done:
if (vec)
free(vec);
return retval;
fail:
retval = 0;
goto done;
}
/*! Given a YANG (bits) type node and value, return the string value for all bits (flags) that are set.
* *
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ytype YANG type noden * @param[in] ytype YANG type noden
* @param[in] snmpval SNMP value * @param[in] inval Input string
* @param[in] snmplen length of snmpval * @param[in] inlen Length of inval
* @param[out] cb space separated string with bit labes for all bits that are set in snmpval * @param[out] cb space separated string with bit labels for all bits that are set in inval
* @retval 1 OK, result in cb * @retval 1 OK, result in cb
* @retval 0 Invalid, not found * @retval 0 Invalid, not found
* @retval -1 Error * @retval -1 Error
* @see yang_bitsstr2val * @see yang_bitsstr2val
* XXX de-snmp:ize * @note that the output is a vector of bits originally made for SNMP bitvectors (not integers)
*/ */
int int
yang_val2bitsstr(clixon_handle h, yang_val2bitsstr(clixon_handle h,
yang_stmt *ytype, yang_stmt *ytype,
unsigned char *snmpval, unsigned char *inval,
size_t snmplen, size_t inlen,
cbuf *cb) cbuf *cb)
{ {
int retval = -1; int retval = -1;
@ -1778,7 +1835,7 @@ yang_val2bitsstr(clixon_handle h,
goto done; goto done;
} }
/* Go over all defined bits and check if it is seet in intval */ /* Go over all defined bits and check if it is seet in intval */
while ((yprev = yn_each(ytype, yprev)) != NULL && byte < snmplen){ while ((yprev = yn_each(ytype, yprev)) != NULL && byte < inlen){
if (yang_keyword_get(yprev) == Y_BIT) { if (yang_keyword_get(yprev) == Y_BIT) {
/* Use position from Y_POSITION statement if defined */ /* Use position from Y_POSITION statement if defined */
if ((ypos = yang_find(yprev, Y_POSITION, NULL)) != NULL){ if ((ypos = yang_find(yprev, Y_POSITION, NULL)) != NULL){
@ -1793,7 +1850,7 @@ yang_val2bitsstr(clixon_handle h,
if (is_first == 0) bitpos++; if (is_first == 0) bitpos++;
} }
byte = bitpos / 8; byte = bitpos / 8;
if (snmpval[byte] & (1 << (7 - (bitpos % 8)))){ if (inval[byte] & (1 << (7 - (bitpos % 8)))){
if (is_first == 0) cbuf_append_str(cb, " "); if (is_first == 0) cbuf_append_str(cb, " ");
cbuf_append_str(cb, yang_argument_get(yprev)); cbuf_append_str(cb, yang_argument_get(yprev));
} }
@ -1813,6 +1870,47 @@ yang_val2bitsstr(clixon_handle h,
goto done; goto done;
} }
/*! Map from bit string to integer bitfield given YANG mapping
*
* Given YANG node, schema-nodeid and a bits string, return a bitmap as u64
* Example: "default app2" --> CLIXON_DBG_DEFAULT | CLIXON_DBG_APP2
* @param[in] yt YANG node in tree (eg yspec)
* @param[in] str String representation of Clixon debug bits, such as "msg app2"
* @param[in] nodeid Absolute schema node identifier to leaf of option
* @param[out] u64 Bit representation
*/
int
yang_bits_map(yang_stmt *yt,
char *str,
char *nodeid,
uint32_t *flags)
{
int retval = -1;
yang_stmt *yn = NULL;
yang_stmt *yrestype;
int ret;
if (yang_abs_schema_nodeid(yt, nodeid, &yn) < 0)
goto done;
if (yn == NULL){
clixon_err(OE_YANG, 0, "yang node not found: %s", nodeid);
goto done;
}
if (yang_type_get(yn, NULL, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
goto done;
if (yrestype != NULL) {
if ((ret = yang_bitsstr2flags(yrestype, str, flags)) < 0)
goto done;
if (ret == 0){
clixon_err(OE_YANG, 0, "Bit string invalid: %s", str);
goto done;
}
}
retval = 0;
done:
return retval;
}
/*! Get integer value from xml node from yang enumeration /*! Get integer value from xml node from yang enumeration
* *
* @param[in] node XML node in a tree * @param[in] node XML node in a tree

View file

@ -120,10 +120,10 @@ expectpart "$($clixon_cli -1 -f $cfg show conf x)" 0 "x m1 a (null) b 22/22 c 44
# Negative tests # Negative tests
new "err x" new "err x"
expectpart "$($clixon_cli -1 -f $cfg -l n err x)" 255 "Config error: api-path syntax error \"/example2:x\": application unknown-element No such yang module prefix <bad-element>example2</bad-element>: Invalid argument" expectpart "$($clixon_cli -1 -f $cfg -l o err x)" 255 "Config error: api-path syntax error \"/example2:x\": application unknown-element No such yang module prefix <bad-element>example2</bad-element>: Invalid argument"
new "err x a" new "err x a"
expectpart "$($clixon_cli -1 -f $cfg -l n err x a 99)" 255 "Config error: api-path syntax error \"/example:x/m1=%s\": rpc malformed-message List key m1 length mismatch : Invalid argument" expectpart "$($clixon_cli -1 -f $cfg -l o err x a 99)" 255 "Config error: api-path syntax error \"/example:x/m1=%s\": rpc malformed-message List key m1 length mismatch : Invalid argument"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"

View file

@ -89,11 +89,11 @@ new "wait backend"
wait_backend wait_backend
new "orig error" new "orig error"
expectpart "$($clixon_cli -1 -f $cfg -l n example error orig)" 255 "Config error: api-path syntax error " ": application invalid-value Invalid api-path: (must start with '/')" expectpart "$($clixon_cli -1 -f $cfg -l o example error orig)" 255 "Config error: api-path syntax error " ": application invalid-value Invalid api-path: (must start with '/')"
if [ ${LINKAGE} = dynamic ]; then if [ ${LINKAGE} = dynamic ]; then
new "customized error" new "customized error"
expectpart "$($clixon_cli -1 -f $cfg -l n example error custom)" 255 "My new err-string" expectpart "$($clixon_cli -1 -f $cfg -l o example error custom)" 255 "My new err-string"
fi fi
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Turn on debug on backend/cli/netconf # Turn on debug on backend/cli/netconf
# Note, restconf debug used to be tested but is no longer tested here, # Also some log destination tests
# maybe in test_restconf_internal? # Note no restconf debug test
# Magic line must be first in script (see README.md) # Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -84,15 +84,57 @@ wait_restconf
new "Set backend debug using netconf" new "Set backend debug using netconf"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><debug $LIBNS><level>1</level></debug></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><debug $LIBNS><level>1</level></debug></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
new "Set cli debug using cli" # Debug
new "cli debug cli"
expectpart "$($clixon_cli -1 -f $cfg -l o debug cli 1)" 0 "^$" expectpart "$($clixon_cli -1 -f $cfg -l o debug cli 1)" 0 "^$"
# Run cli debug new "cli debug, expect 0"
new "get cli debug, expect 0"
expectpart "$($clixon_cli -1 -f $cfg show debug cli)" 0 "CLI debug:0x0" expectpart "$($clixon_cli -1 -f $cfg show debug cli)" 0 "CLI debug:0x0"
new "get cli debug expect 2" new "cli debug -o single"
expectpart "$($clixon_cli -1 -f $cfg -o CLICON_DEBUG=msg show debug cli)" 0 "CLI debug:0x2" expectpart "$($clixon_cli -1 -f $cfg -o CLICON_DEBUG=msg show debug cli)" 0 "CLI debug:0x2" --not-- "CLI debug:0x20"
new "cli debug -o multi"
expectpart "$($clixon_cli -1 -f $cfg -o CLICON_DEBUG="msg app2" show debug cli)" 0 "CLI debug:0x200002"
new "cli debug -D multi"
expectpart "$($clixon_cli -1 -f $cfg -D msg -D app2 show debug cli)" 0
# Log destination
new "cli log -lf<file>"
rm -f $dir/clixon.log
expectpart "$($clixon_cli -1 -lf$dir/clixon.log -f $cfg show version)" 0
if [ ! -f "$dir/clixon.log" ]; then
err "$dir/clixon.log" "No file"
fi
new "cli log -lfile"
rm -f $dir/clixon.log
expectpart "$($clixon_cli -1 -lfile -f $cfg show version)" 0
if [ -f "$dir/clixon.log" ]; then
err "No file" "$dir/clixon.log"
fi
new "cli log -lfile + CLICON_LOG_FILE"
rm -f $dir/clixon.log
expectpart "$($clixon_cli -1 -lfile -o CLICON_LOG_FILE=$dir/clixon.log -f $cfg show version)" 0
if [ ! -f "$dir/clixon.log" ]; then
err "$dir/clixon.log" "No file"
fi
rm -f $dir/clixon.log
new "cli log -o CLICON_LOG_DESTINATION + CLICON_LOG_FILE"
expectpart "$($clixon_cli -1 -o CLICON_LOG_DESTINATION=file -o CLICON_LOG_FILE=$dir/clixon.log -f $cfg show version)" 0
if [ ! -f "$dir/clixon.log" ]; then
err "$dir/clixon.log" "No file"
fi
rm -f $dir/clixon.log
new "cli log -o CLICON_LOG_DESTINATION + CLICON_LOG_FILE multi"
expectpart "$($clixon_cli -1 -o CLICON_LOG_DESTINATION="stdout file" -o CLICON_LOG_FILE=$dir/clixon.log -f $cfg show version)" 0
if [ ! -f "$dir/clixon.log" ]; then
err "$dir/clixon.log" "No file"
fi
new "Set backend debug using cli" new "Set backend debug using cli"
expectpart "$($clixon_cli -1 -f $cfg -l o debug backend 1)" 0 "^$" expectpart "$($clixon_cli -1 -f $cfg -l o debug backend 1)" 0 "^$"

View file

@ -52,6 +52,8 @@ module clixon-config {
revision 2024-04-01 { revision 2024-04-01 {
description description
"Added options: "Added options:
CLICON_LOG_DESTINATION: Default log destination
CLICON_LOG_FILE: Which file to log to if file logging
CLICON_DEBUG: Debug flags. CLICON_DEBUG: Debug flags.
CLICON_YANG_SCHEMA_MOUNT_SHARE: Share same YANGs of equal moint-points. CLICON_YANG_SCHEMA_MOUNT_SHARE: Share same YANGs of equal moint-points.
CLICON_SOCK_PRIO: Enable socket event priority CLICON_SOCK_PRIO: Enable socket event priority
@ -426,6 +428,33 @@ module clixon-config {
} }
} }
} }
typedef log_destination_t {
description
"Log destination flags
Can also be given directly as -l <flag> to clixon commands
Note there are also constants in the code (logdstmap) that need to be
in sync with these values.
The duplication is because of bootstrapping, logging is needed before YANG
loaded";
type bits {
bit syslog {
position 0;
description "Syslog";
}
bit stderr {
position 1;
description "Standard I/O Error";
}
bit stdout {
position 2;
description "Standard I/O Output";
}
bit file {
position 3;
description "Log to file. By default clixon.log int current directory";
}
}
}
container clixon-config { container clixon-config {
container restconf { container restconf {
uses clrc:clixon-restconf; uses clrc:clixon-restconf;
@ -456,14 +485,7 @@ module clixon-config {
Ensure that YANG_INSTALLDIR (default Ensure that YANG_INSTALLDIR (default
/usr/local/share/clixon) is present in the path"; /usr/local/share/clixon) is present in the path";
} }
leaf CLICON_DEBUG{ /* Configuration */
type cl:clixon_debug_t;
description
"Debug flags as bitfields.
Can also be given directly as -D <flag> to clixon commands (which overrides this)
Note only partly implemented;
- Only CLI, only single value, cannot be combined with -D, not in RPC";
}
leaf CLICON_CONFIGFILE{ leaf CLICON_CONFIGFILE{
type string; type string;
description description
@ -497,6 +519,7 @@ module clixon-config {
This field is a 'bootstrap' field. This field is a 'bootstrap' field.
"; ";
} }
/* YANG */
leaf CLICON_YANG_MAIN_FILE { leaf CLICON_YANG_MAIN_FILE {
type string; type string;
description description
@ -599,6 +622,7 @@ module clixon-config {
See also CLICON_XMLDB_MODSTATE where the module state info is used to tag datastores See also CLICON_XMLDB_MODSTATE where the module state info is used to tag datastores
with module information."; with module information.";
} }
/* Backend */
leaf CLICON_BACKEND_DIR { leaf CLICON_BACKEND_DIR {
type string; type string;
description description
@ -653,6 +677,7 @@ module clixon-config {
- on enable change, make the state as configured - on enable change, make the state as configured
Disable if you start the restconf daemon by other means."; Disable if you start the restconf daemon by other means.";
} }
/* Netconf */
leaf CLICON_NETCONF_DIR{ leaf CLICON_NETCONF_DIR{
type string; type string;
description "Location of netconf (frontend) .so plugins"; description "Location of netconf (frontend) .so plugins";
@ -725,6 +750,7 @@ module clixon-config {
apart from NETCONF. apart from NETCONF.
Only if CLICON_NETCONF_MONITORING"; Only if CLICON_NETCONF_MONITORING";
} }
/* HTTP and Restconf */
leaf CLICON_RESTCONF_API_ROOT { leaf CLICON_RESTCONF_API_ROOT {
type string; type string;
default "/restconf"; default "/restconf";
@ -840,6 +866,7 @@ module clixon-config {
Both feature clixon-restconf:http-data and restconf/enable-http-data Both feature clixon-restconf:http-data and restconf/enable-http-data
must be enabled for this match to occur."; must be enabled for this match to occur.";
} }
/* Clixon CLI */
leaf CLICON_CLI_DIR { leaf CLICON_CLI_DIR {
type string; type string;
description description
@ -987,6 +1014,7 @@ module clixon-config {
description description
"Default CLI output format."; "Default CLI output format.";
} }
/* Internal socket */
leaf CLICON_SOCK_FAMILY { leaf CLICON_SOCK_FAMILY {
type socket_address_family; type socket_address_family;
default UNIX; default UNIX;
@ -1056,6 +1084,7 @@ module clixon-config {
Also, any edits in candidate are discarded if the client closes the connection. Also, any edits in candidate are discarded if the client closes the connection.
This effectively disables shared candidate"; This effectively disables shared candidate";
} }
/* Datastore XMLDB */
leaf CLICON_DATASTORE_CACHE { leaf CLICON_DATASTORE_CACHE {
type datastore_cache; type datastore_cache;
default cache; default cache;
@ -1201,6 +1230,7 @@ module clixon-config {
The current only case where such a user is used is in RESTCONF authentication when The current only case where such a user is used is in RESTCONF authentication when
auth-type=none and no known user is known."; auth-type=none and no known user is known.";
} }
/* Network Configuration Access Control Model (NACM) */
leaf CLICON_NACM_MODE { leaf CLICON_NACM_MODE {
type nacm_mode; type nacm_mode;
default disabled; default disabled;
@ -1255,6 +1285,7 @@ module clixon-config {
If CLICON_MODULE_LIBRARY_RFC7895 is enabled, it sets the modules-state/module-set-id If CLICON_MODULE_LIBRARY_RFC7895 is enabled, it sets the modules-state/module-set-id
instead"; instead";
} }
/* Notification streams */
leaf CLICON_STREAM_DISCOVERY_RFC5277 { leaf CLICON_STREAM_DISCOVERY_RFC5277 {
type boolean; type boolean;
default false; default false;
@ -1311,6 +1342,27 @@ module clixon-config {
description "Retention for stream replay buffers in seconds, ie how much description "Retention for stream replay buffers in seconds, ie how much
data to store before dropping. 0 means no retention"; data to store before dropping. 0 means no retention";
} }
/* Log and debug */
leaf CLICON_DEBUG{
type cl:clixon_debug_t;
description
"Debug flags as bitfields.
Can also be given directly as -D <flag> to clixon commands (which overrides this).";
}
leaf CLICON_LOG_DESTINATION {
type log_destination_t;
description
"Log destination.
If not given, default log destination is syslog for all applications,
except clixon_cli where default is stderr.
See also command-line option -l <s|e|o|n|f>";
}
leaf CLICON_LOG_FILE {
type string;
description
"Which file to log to if log destination is file
That is CLIXON_LOG_DESTINATION is FILE or command started with -l f";
}
leaf CLICON_LOG_STRING_LIMIT { leaf CLICON_LOG_STRING_LIMIT {
type uint32; type uint32;
default 0; default 0;
@ -1318,8 +1370,8 @@ module clixon-config {
"Length limitation of debug and log strings. "Length limitation of debug and log strings.
Especially useful for dynamic debug strings, such as packet dumps. Especially useful for dynamic debug strings, such as packet dumps.
0 means no limit"; 0 means no limit";
} }
/* SNMP */
leaf-list CLICON_SNMP_MIB { leaf-list CLICON_SNMP_MIB {
description description
"Names of MIBs that are used by clixon_snmp. "Names of MIBs that are used by clixon_snmp.

View file

@ -193,7 +193,7 @@ module clixon-lib {
"Debug flags. "Debug flags.
Flags are seperated into subject areas and detail Flags are seperated into subject areas and detail
Can also be given directly as -D <flag> to clixon commands Can also be given directly as -D <flag> to clixon commands
Note there are also constants in the code thaht need to be in sync with these values"; Note there are also constants in the code that need to be in sync with these values";
type bits { type bits {
/* Subjects: */ /* Subjects: */
bit default { bit default {
@ -345,7 +345,9 @@ module clixon-lib {
A sub-object will not be noted"; A sub-object will not be noted";
} }
rpc debug { rpc debug {
description "Set debug level of backend."; description
"Set debug flags of backend.
Note only numerical values";
input { input {
leaf level { leaf level {
type uint32; type uint32;