[sonic-yang-mgmt] Adding flag to disable/enable log printing (#9659)

#### Why I did it
Fixes https://github.com/Azure/sonic-utilities/issues/1871

From [generic-config-updater](https://github.com/Azure/sonic-utilities/tree/master/generic_config_updater) we call `sonic-yang-mgmt` multiple times in order to check a certain change to ConfigDb is valid or not. It is expected for some changes to be invalid, so always printing errors from `sonic-yang-mgmt` makes the output hard to read.

In this PR, we are adding a way to control if logs should be printed or not.

#### How I did it
- Added `print_log_enabled` flag to sonic_yang ctor
- Converted all `print` statements to `sysLog(..., doPrint=True)`

#### How to verify it
unit-test passing means the change did not break logs.

#### Info about libyang logging
libyang provides an extensive logging logic which can support a lot of scenarios:
- ly_log_level: setting logging level
  - LY_LLERR
  - LY_LLWRN
  - ... 
- ly_set_log_clb: setting log callback to customize the default behavior which is printing the msgs
- ly_log_options: setting logging options 
  - LY_LOLOG: If callback is set use it, otherwise just print. If flag is not set, do nothing.
  - ...

For more info refer to:
- https://netopeer.liberouter.org/doc/libyang/devel/html/group__logopts.html#gaff80501597ed76344a679be2b90a1d0a
- https://netopeer.liberouter.org/doc/libyang/devel/html/group__log.html#gac88b78694dfe9efe0450a69603f7eceb


#### What's next?
Consume the new flag `print_log_enabled` in [generic-config-updater](https://github.com/Azure/sonic-utilities/tree/master/generic_config_updater) to reduce the logging clutter. 

#### Which release branch to backport (provide reason below if selected)

<!--
- Note we only backport fixes to a release branch, *not* features!
- Please also provide a reason for the backporting below.
- e.g.
- [x] 202006
-->

- [ ] 201811
- [ ] 201911
- [ ] 202006
- [ ] 202012
- [ ] 202106

#### Description for the changelog
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog:
-->


#### A picture of a cute animal (not mandatory but encouraged)
This commit is contained in:
Mohamed Ghoneim 2022-01-04 19:42:10 -08:00 committed by Judy Joseph
parent 013413d9ce
commit 9cbdac6ede
2 changed files with 31 additions and 30 deletions

View File

@ -12,7 +12,7 @@ i.e. it is mixin not parent class.
""" """
class SonicYang(SonicYangExtMixin): class SonicYang(SonicYangExtMixin):
def __init__(self, yang_dir, debug=False): def __init__(self, yang_dir, debug=False, print_log_enabled=True):
self.yang_dir = yang_dir self.yang_dir = yang_dir
self.ctx = None self.ctx = None
self.module = None self.module = None
@ -21,6 +21,11 @@ class SonicYang(SonicYangExtMixin):
# logging vars # logging vars
self.SYSLOG_IDENTIFIER = "sonic_yang" self.SYSLOG_IDENTIFIER = "sonic_yang"
self.DEBUG = debug self.DEBUG = debug
self.print_log_enabled = print_log_enabled
if not print_log_enabled:
# The default libyang log options are ly.LY_LOLOG|ly.LY_LOSTORE_LAST.
# Removing ly.LY_LOLOG will stop libyang from printing the logs.
ly.set_log_options(ly.LY_LOSTORE_LAST)
# yang model files, need this map it to module # yang model files, need this map it to module
self.yangFiles = list() self.yangFiles = list()
@ -51,11 +56,10 @@ class SonicYang(SonicYangExtMixin):
pass pass
def sysLog(self, debug=syslog.LOG_INFO, msg=None, doPrint=False): def sysLog(self, debug=syslog.LOG_INFO, msg=None, doPrint=False):
# log debug only if enabled # log debug only if enabled
if self.DEBUG == False and debug == syslog.LOG_DEBUG: if self.DEBUG == False and debug == syslog.LOG_DEBUG:
return return
if doPrint: if doPrint and self.print_log_enabled:
print("{}({}):{}".format(self.SYSLOG_IDENTIFIER, debug, msg)) print("{}({}):{}".format(self.SYSLOG_IDENTIFIER, debug, msg))
syslog.openlog(self.SYSLOG_IDENTIFIER) syslog.openlog(self.SYSLOG_IDENTIFIER)
syslog.syslog(debug, msg) syslog.syslog(debug, msg)
@ -64,7 +68,7 @@ class SonicYang(SonicYangExtMixin):
return return
def fail(self, e): def fail(self, e):
print(e) self.sysLog(msg=e, debug=syslog.LOG_ERR, doPrint=True)
raise e raise e
""" """
@ -76,7 +80,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
return self.ctx.parse_module_path(yang_file, ly.LYS_IN_YANG) return self.ctx.parse_module_path(yang_file, ly.LYS_IN_YANG)
except Exception as e: except Exception as e:
print("Failed to load yang module file: " + yang_file) self.sysLog(msg="Failed to load yang module file: " + yang_file, debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
""" """
@ -120,7 +124,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
ctx.parse_module_path(str(file), ly.LYS_IN_YANG) ctx.parse_module_path(str(file), ly.LYS_IN_YANG)
except Exception as e: except Exception as e:
print("Failed to parse yang module file: " + file) self.sysLog(msg="Failed to parse yang module file: " + file, debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
return ctx return ctx
@ -134,7 +138,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
data_node = self.ctx.parse_data_path(data_file, ly.LYD_JSON, ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT) data_node = self.ctx.parse_data_path(data_file, ly.LYD_JSON, ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT)
except Exception as e: except Exception as e:
print("Failed to load data file: " + str(data_file)) self.sysLog(msg="Failed to load data file: " + str(data_file), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
else: else:
self.root = data_node self.root = data_node
@ -176,7 +180,7 @@ class SonicYang(SonicYangExtMixin):
for i in range(1, len(data_files)): for i in range(1, len(data_files)):
self._merge_data(data_files[i]) self._merge_data(data_files[i])
except Exception as e: except Exception as e:
print("Failed to load data files") self.sysLog(msg="Failed to load data files", debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
return return
@ -217,7 +221,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
module = self.ctx.get_module(str(module_name)) module = self.ctx.get_module(str(module_name))
except Exception as e: except Exception as e:
print("Cound not get module: " + str(module_name)) self.sysLog(msg="Cound not get module: " + str(module_name), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
else: else:
if (module is not None): if (module is not None):
@ -256,7 +260,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
self._validate_data(self.root, self.ctx) self._validate_data(self.root, self.ctx)
except Exception as e: except Exception as e:
print("Failed to validate data tree") self.sysLog(msg="Failed to validate data tree\n{", debug=syslog.LOG_ERR, doPrint=True)
raise SonicYangException("Failed to validate data tree\n{}".\ raise SonicYangException("Failed to validate data tree\n{}".\
format(str(e))) format(str(e)))
@ -267,12 +271,12 @@ class SonicYang(SonicYangExtMixin):
""" """
def _find_parent_data_node(self, data_xpath): def _find_parent_data_node(self, data_xpath):
if (self.root is None): if (self.root is None):
print("data not loaded") self.sysLog(msg="data not loaded", debug=syslog.LOG_ERR, doPrint=True)
return None return None
try: try:
data_node = self._find_data_node(data_xpath) data_node = self._find_data_node(data_xpath)
except Exception as e: except Exception as e:
print("Failed to find data node from xpath: " + str(data_xpath)) self.sysLog(msg="Failed to find data node from xpath: " + str(data_xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
else: else:
if data_node is not None: if data_node is not None:
@ -291,7 +295,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
data_node = self._find_parent_data_node(data_xpath) data_node = self._find_parent_data_node(data_xpath)
except Exception as e: except Exception as e:
print("Failed to find parent node from xpath: " + str(data_xpath)) self.sysLog(msg="Failed to find parent node from xpath: " + str(data_xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
else: else:
if data_node is not None: if data_node is not None:
@ -310,7 +314,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
data_node = self.root.new_path(self.ctx, xpath, val, 0, 0) data_node = self.root.new_path(self.ctx, xpath, val, 0, 0)
except Exception as e: except Exception as e:
print("Failed to add data node for path: " + str(xpath)) self.sysLog(msg="Failed to add data node for path: " + str(xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
else: else:
return data_node return data_node
@ -326,7 +330,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
set = self.root.find_path(data_xpath) set = self.root.find_path(data_xpath)
except Exception as e: except Exception as e:
print("Failed to find data node from xpath: " + str(data_xpath)) self.sysLog(msg="Failed to find data node from xpath: " + str(data_xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
else: else:
if set is not None: if set is not None:
@ -386,7 +390,7 @@ class SonicYang(SonicYangExtMixin):
#check if the node added to the data tree #check if the node added to the data tree
self._find_data_node(data_xpath) self._find_data_node(data_xpath)
except Exception as e: except Exception as e:
print("add_node(): Failed to add data node for xpath: " + str(data_xpath)) self.sysLog(msg="add_node(): Failed to add data node for xpath: " + str(data_xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
""" """
@ -426,10 +430,10 @@ class SonicYang(SonicYangExtMixin):
#deleted node not found #deleted node not found
return True return True
else: else:
print('Could not delete Node') self.sysLog(msg='Could not delete Node', debug=syslog.LOG_ERR, doPrint=True)
return False return False
else: else:
print("failed to find node, xpath: " + xpath) self.sysLog(msg="failed to find node, xpath: " + xpath, debug=syslog.LOG_ERR, doPrint=True)
return False return False
@ -443,7 +447,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
data_node = self._find_data_node(data_xpath) data_node = self._find_data_node(data_xpath)
except Exception as e: except Exception as e:
print("find_data_node_value(): Failed to find data node from xpath: {}".format(data_xpath)) self.sysLog(msg="find_data_node_value(): Failed to find data node from xpath: {}".format(data_xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
else: else:
if (data_node is not None): if (data_node is not None):
@ -462,7 +466,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
self.root.new_path(self.ctx, data_xpath, str(value), ly.LYD_ANYDATA_STRING, ly.LYD_PATH_OPT_UPDATE) self.root.new_path(self.ctx, data_xpath, str(value), ly.LYD_ANYDATA_STRING, ly.LYD_PATH_OPT_UPDATE)
except Exception as e: except Exception as e:
print("set data node value failed for xpath: " + str(data_xpath)) self.sysLog(msg="set data node value failed for xpath: " + str(data_xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
""" """
@ -497,7 +501,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
schema_node = self._find_schema_node(schema_xpath) schema_node = self._find_schema_node(schema_xpath)
except Exception as e: except Exception as e:
print("Cound not find the schema node from xpath: " + str(schema_xpath)) self.sysLog(msg="Cound not find the schema node from xpath: " + str(schema_xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
return ref_list return ref_list
@ -505,7 +509,7 @@ class SonicYang(SonicYangExtMixin):
backlinks = schema_node.backlinks() backlinks = schema_node.backlinks()
if backlinks.number() > 0: if backlinks.number() > 0:
for link in backlinks.schema(): for link in backlinks.schema():
print("backlink schema: {}".format(link.path())) self.sysLog(msg="backlink schema: {}".format(link.path()), doPrint=True)
ref_list.append(link.path()) ref_list.append(link.path())
return ref_list return ref_list
@ -521,7 +525,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
data_node = self._find_data_node(data_xpath) data_node = self._find_data_node(data_xpath)
except Exception as e: except Exception as e:
print("find_data_dependencies(): Failed to find data node from xpath: {}".format(data_xapth)) self.sysLog(msg="find_data_dependencies(): Failed to find data node from xpath: {}".format(data_xapth), debug=syslog.LOG_ERR, doPrint=True)
return ref_list return ref_list
try: try:
@ -538,7 +542,7 @@ class SonicYang(SonicYangExtMixin):
if value == casted.value_str(): if value == casted.value_str():
ref_list.append(data_set.path()) ref_list.append(data_set.path())
except Exception as e: except Exception as e:
print('Failed to find node or dependencies for {}'.format(data_xpath)) self.sysLog(msg='Failed to find node or dependencies for {}'.format(data_xpath), debug=syslog.LOG_ERR, doPrint=True)
raise SonicYangException("Failed to find node or dependencies for \ raise SonicYangException("Failed to find node or dependencies for \
{}\n{}".format(data_xpath, str(e))) {}\n{}".format(data_xpath, str(e)))
@ -598,7 +602,7 @@ class SonicYang(SonicYangExtMixin):
try: try:
schema_node = self._find_schema_node(schema_xpath) schema_node = self._find_schema_node(schema_xpath)
except Exception as e: except Exception as e:
print("get_data_type(): Failed to find schema node from xpath: {}".format(schema_xpath)) self.sysLog(msg="get_data_type(): Failed to find schema node from xpath: {}".format(schema_xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e) self.fail(e)
return None return None
@ -618,7 +622,7 @@ class SonicYang(SonicYangExtMixin):
subtype = data_node.subtype() subtype = data_node.subtype()
if (subtype is not None): if (subtype is not None):
if data_node.schema().subtype().type().base() != ly.LY_TYPE_LEAFREF: if data_node.schema().subtype().type().base() != ly.LY_TYPE_LEAFREF:
print("get_leafref_type() node type for data xpath: {} is not LEAFREF".format(data_xpath)) self.sysLog(msg="get_leafref_type() node type for data xpath: {} is not LEAFREF".format(data_xpath), debug=syslog.LOG_ERR, doPrint=True)
return ly.LY_TYPE_UNKNOWN return ly.LY_TYPE_UNKNOWN
else: else:
return subtype.value_type() return subtype.value_type()

View File

@ -214,10 +214,7 @@ class SonicYangExtMixin:
del self.jIn[table] del self.jIn[table]
if len(self.tablesWithOutYang): if len(self.tablesWithOutYang):
print("Note: Below table(s) have no YANG models:") self.sysLog(msg=f"Note: Below table(s) have no YANG models: {', '.join(self.tablesWithOutYang)}", doPrint=True)
for table in self.tablesWithOutYang.keys():
print(str(table), end=", ")
print()
if croppedFile: if croppedFile:
with open(croppedFile, 'w') as f: with open(croppedFile, 'w') as f: