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

@ -46,9 +46,10 @@
* 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 clixon_debug in clixon-lib.yang
* @see also clixon_debug_t in clixon-lib.yang
*/
/* Detail level */
#define CLIXON_DBG_ALWAYS 0x00000000 /* Unconditionally logged */

View file

@ -45,11 +45,15 @@
/*
* Constants
*/
/* Where to log (masks) */
#define CLIXON_LOG_SYSLOG 1 /* print logs on syslog */
#define CLIXON_LOG_STDERR 2 /* print logs on stderr */
#define CLIXON_LOG_STDOUT 4 /* print logs on stdout */
#define CLIXON_LOG_FILE 8 /* print logs on clicon_log_filename */
/*! Log destination as bitfields (masks)
*
* @see logdstmap Symbolic mapping (if you change here you may need to change logdstmap)
* @see also log_desination_t in clixon-config.yang
*/
#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) */
enum clixon_log_type{
@ -67,6 +71,8 @@ enum clixon_log_type{
/*
* 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_exit(void);
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 */
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 */
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 xml_merge(cxobj *x0, cxobj *x1, yang_stmt *yspec, char **reason);
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_val2bitsstr(clixon_handle h, yang_stmt *ytype, unsigned char *snmpval, size_t snmplen, cbuf *cb);
int yang_bitsstr2val(clixon_handle h, yang_stmt *ytype, char *bitsstr, unsigned char **outval, size_t *outlen);
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_enum2int(yang_stmt *ytype, char *enumstr, 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 */
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 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[] = {
{"default", CLIXON_DBG_DEFAULT},
@ -152,16 +163,6 @@ clixon_debug_key_dump(FILE *f)
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 module. The level is used together with clixon_debug(dbglevel) calls as follows:

View file

@ -60,6 +60,7 @@
/* clixon */
#include "clixon_queue.h"
#include "clixon_hash.h"
#include "clixon_string.h"
#include "clixon_handle.h"
#include "clixon_yang.h"
#include "clixon_xml.h"
@ -87,6 +88,47 @@ static FILE *_log_file = NULL;
/* Truncate debug strings to this length. 0 means unlimited */
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.
*
* 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] 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] flags bitmask: if CLIXON_LOG_STDERR, then print logs to stderr
* if CLIXON_LOG_SYSLOG, then print logs to syslog
* You can do a combination of both
* @param[in] flags Log destination bitmask
* @retval 0 OK
* @code
* clixon_log_init(__PROGRAM__, LOG_INFO, CLIXON_LOG_STDERR);

View file

@ -73,7 +73,6 @@
#include "clixon_debug.h"
#include "clixon_string.h"
#include "clixon_file.h"
#include "clixon_xml_sort.h"
#include "clixon_json.h"
#include "clixon_text_syntax.h"
#include "clixon_proto.h"
@ -83,8 +82,10 @@
#include "clixon_xpath.h"
#include "clixon_yang_parse_lib.h"
#include "clixon_netconf_lib.h"
#include "clixon_xml_sort.h"
#include "clixon_xml_nsctx.h"
#include "clixon_xml_io.h"
#include "clixon_xml_map.h"
#include "clixon_validate.h"
#include "clixon_xml_default.h"
@ -725,6 +726,59 @@ clicon_options_main(clixon_handle h)
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
*
* @param[in] h clixon_handle

View file

@ -1669,25 +1669,25 @@ yang_bits_pos(yang_stmt *ytype,
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] ytype YANG type noden
* @param[in] bitsstr Value of bits as space separated string
* @param[out] snmpval SNMP value with all bits set for given bitsstr
* @param[out] snmplen length of snmpval
* @retval 1 OK, result in snmpval
* @param[out] outval Value with all bits set for given bitsstr (free with free)
* @param[out] outlen Length of outval
* @retval 1 OK, result in outval
* @retval 0 Invalid, not found
* @retval -1 Error
* @see yang_val2bitsstr
* XXX de-snmp:ize
* @note that the output is a vector of bits originally made for SNMP bitvectors (not integers)
*/
int
yang_bitsstr2val(clixon_handle h,
yang_stmt *ytype,
char *bitsstr,
unsigned char **snmpval,
size_t *snmplen)
unsigned char **outval,
size_t *outlen)
{
int retval = -1;
int i = 0;
@ -1699,7 +1699,7 @@ yang_bitsstr2val(clixon_handle h,
int ret = 0;
uint32_t bitpos;
*snmplen = 0;
*outlen = 0;
if ((buffer = calloc(CLIXON_BITS_POS_MAX / 8, sizeof(unsigned char))) == NULL){
clixon_err(OE_UNIX, errno, "calloc");
goto done;
@ -1719,19 +1719,19 @@ yang_bitsstr2val(clixon_handle h,
/* Set bit at correct byte and bit position */
byte = bitpos / 8;
buffer[byte] = buffer[byte] | (1 << (7 - (bitpos % 8)));
*snmplen = byte + 1;
if (*snmplen >= CLIXON_BITS_POS_MAX) {
*outlen = byte + 1;
if (*outlen >= CLIXON_BITS_POS_MAX) {
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;
}
}
}
if ((*snmpval = malloc(*snmplen)) == NULL){
if ((*outval = malloc(*outlen)) == NULL){
clixon_err(OE_UNIX, errno, "calloc");
goto done;
}
memcpy(*snmpval, buffer, *snmplen);
memcpy(*outval, buffer, *outlen);
retval = 1;
done:
if (buffer)
@ -1744,24 +1744,81 @@ yang_bitsstr2val(clixon_handle h,
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] ytype YANG type noden
* @param[in] snmpval SNMP value
* @param[in] snmplen length of snmpval
* @param[out] cb space separated string with bit labes for all bits that are set in snmpval
* @param[in] inval Input string
* @param[in] inlen Length of inval
* @param[out] cb space separated string with bit labels for all bits that are set in inval
* @retval 1 OK, result in cb
* @retval 0 Invalid, not found
* @retval -1 Error
* @see yang_bitsstr2val
* XXX de-snmp:ize
* @note that the output is a vector of bits originally made for SNMP bitvectors (not integers)
*/
int
yang_val2bitsstr(clixon_handle h,
yang_stmt *ytype,
unsigned char *snmpval,
size_t snmplen,
unsigned char *inval,
size_t inlen,
cbuf *cb)
{
int retval = -1;
@ -1778,7 +1835,7 @@ yang_val2bitsstr(clixon_handle h,
goto done;
}
/* 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) {
/* Use position from Y_POSITION statement if defined */
if ((ypos = yang_find(yprev, Y_POSITION, NULL)) != NULL){
@ -1793,7 +1850,7 @@ yang_val2bitsstr(clixon_handle h,
if (is_first == 0) bitpos++;
}
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, " ");
cbuf_append_str(cb, yang_argument_get(yprev));
}
@ -1813,6 +1870,47 @@ yang_val2bitsstr(clixon_handle h,
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
*
* @param[in] node XML node in a tree

View file

@ -3313,9 +3313,9 @@ schema_nodeid_iterate(yang_stmt *yn,
* @see yang_desc_schema_nodeid
*/
int
yang_abs_schema_nodeid(yang_stmt *yn,
char *schema_nodeid,
yang_stmt **yres)
yang_abs_schema_nodeid(yang_stmt *yn,
char *schema_nodeid,
yang_stmt **yres)
{
int retval = -1;
cvec *nodeid_cvv = NULL;

View file

@ -838,12 +838,12 @@ yang_metadata_init(clixon_handle h)
* Skip module if already loaded
* This function is used where a yang-lib module-set is available to populate
* an XML mount-point.
* @param[in] h Clixon handle
* @param[in] h Clixon handle
* @param[in] xyanglib XML tree on the form <yang-lib>...
* @param[in] yspec Will be populated with YANGs, is consumed
* @retval 1 OK
* @retval 0 Parse error
* @retval -1 Error
* @param[in] yspec Will be populated with YANGs, is consumed
* @retval 1 OK
* @retval 0 Parse error
* @retval -1 Error
* @see xml_schema_add_mount_points
* XXX: Ensure yang-lib is always there otherwise get state dont work for mountpoint
*/