267 lines
7.9 KiB
Python
Executable File
267 lines
7.9 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright (c) 2019 Huawei Technologies Co., Ltd.
|
|
# A-Tune is licensed under the Mulan PSL v1.
|
|
# You can use this software according to the terms and conditions of the Mulan PSL v1.
|
|
# You may obtain a copy of Mulan PSL v1 at:
|
|
# http://license.coscl.org.cn/MulanPSL
|
|
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
# PURPOSE.
|
|
# See the Mulan PSL v1 for more details.
|
|
# Create: 2019-10-29
|
|
|
|
"""
|
|
The base class of the monitor, used to report the given config, get the collected info,
|
|
decode the collected info, format the collected info and output collected info to file.
|
|
"""
|
|
|
|
import sys
|
|
import logging
|
|
from public import *
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class Monitor():
|
|
"""Base class for monitors"""
|
|
|
|
# sub class should init these
|
|
_module = "UNKNOWN"
|
|
_purpose = "UNKNOWN"
|
|
|
|
# for inner options usage
|
|
_option = ""
|
|
|
|
def __init__(self, user=None):
|
|
"""
|
|
Initialize.
|
|
|
|
:param user(optional): "UT" for unit test, others are ignored
|
|
:returns: None
|
|
:raises: None
|
|
"""
|
|
self._user = user
|
|
|
|
def module(self):
|
|
"""
|
|
Get the the module of this monitor.
|
|
|
|
:param: None
|
|
:returns: The module of this monitor
|
|
:raises: None
|
|
"""
|
|
return self._module
|
|
|
|
def purpose(self):
|
|
"""
|
|
Get the the purpose of this monitor.
|
|
|
|
:param: None
|
|
:returns: The purpose of this monitor
|
|
:raises: None
|
|
"""
|
|
return self._purpose
|
|
|
|
def _getopt(self):
|
|
"""
|
|
Get the the inner option of this monitor.
|
|
Multi-options should be splited by ";".
|
|
|
|
:param: None
|
|
:returns: The iterator for get all inner options
|
|
:raises: None
|
|
"""
|
|
return iter(self._option.split(";"))
|
|
|
|
def _getpara(self, paras):
|
|
"""
|
|
Get all the configs from one string.
|
|
|
|
:param paras: The configs string splited by ";"
|
|
:returns None: No parameter
|
|
:returns parameter: next parameter
|
|
:raises: None
|
|
"""
|
|
if paras is None:
|
|
return None
|
|
|
|
try:
|
|
nextp = next(paras)
|
|
except StopIteration:
|
|
return None
|
|
|
|
if nextp == "":
|
|
nextp = None
|
|
return nextp
|
|
|
|
def report(self, fmt, path, para=None):
|
|
"""
|
|
Report the given config.
|
|
|
|
:param fmt: The option for format(fmt)
|
|
:param path: The path to output, None for pass through
|
|
:param para: Multi-options for get(para) and decode(para), should be splited by ";"
|
|
:returns None: Success
|
|
:returns info: Success, output info
|
|
:returns Exceptions: Fail, with info
|
|
:raises: None
|
|
"""
|
|
try:
|
|
if para is None:
|
|
paras = None
|
|
else:
|
|
paras = iter(para.split(";"))
|
|
info = self._get(self._getpara(paras))
|
|
decoded_info = self.decode(info, self._getpara(paras))
|
|
fmted_info = self.format(decoded_info, fmt)
|
|
return self.output(fmted_info, path)
|
|
except Exception as err:
|
|
if self._user == "UT":
|
|
raise err
|
|
else:
|
|
logger.error(
|
|
"{}.{}: {}".format(
|
|
self.__class__.__name__,
|
|
sys._getframe().f_code.co_name,
|
|
str(err)))
|
|
return err
|
|
|
|
def _get(self, para):
|
|
"""
|
|
The inner method to get collected info.
|
|
The sub class should implement this method.
|
|
|
|
:param para: The option for get,
|
|
[%s]:
|
|
"--interval=" to specify period of time
|
|
"--cpu=" to select which cpu
|
|
"--event=" to select which event
|
|
:returns value: Success, collected info string
|
|
:raises Exceptions: Fail, with info
|
|
"""
|
|
err = NotImplementedError("_get method is not implemented")
|
|
logger.error(
|
|
"{}.{}: {}".format(
|
|
self.__class__.__name__,
|
|
sys._getframe().f_code.co_name,
|
|
str(err)))
|
|
raise err
|
|
|
|
def get(self, para=None):
|
|
"""
|
|
Get the collected info.
|
|
|
|
:param para(optional): The option for get
|
|
:returns info: Success, collected info string
|
|
:returns Exceptions: Fail, error in _get()
|
|
:raises: None
|
|
"""
|
|
try:
|
|
ret = self._get(para)
|
|
except Exception as err:
|
|
if self._user == "UT":
|
|
raise err
|
|
else:
|
|
logger.error(
|
|
"{}.{}: {}".format(
|
|
self.__class__.__name__,
|
|
sys._getframe().f_code.co_name,
|
|
str(err)))
|
|
return err
|
|
return ret
|
|
|
|
def decode(self, info, para):
|
|
"""
|
|
The inner method to decode collected info.
|
|
|
|
:param info: The collected info string
|
|
:param para: The option for decode,
|
|
[%s]:
|
|
"--fields=" to select which data
|
|
"--cpu=" to select which cpu
|
|
"--nic=" to select which net interface
|
|
"--device=" to select which device
|
|
:returns info: Success, decoded info
|
|
:raises NotImplementedError: Error, not supported
|
|
:raises Exceptions: Fail, with info
|
|
"""
|
|
if para is None:
|
|
return info
|
|
else:
|
|
err = NotImplementedError("Not supported decode: {}".format(para))
|
|
logger.error(
|
|
"{}.{}: {}".format(
|
|
self.__class__.__name__,
|
|
sys._getframe().f_code.co_name,
|
|
str(err)))
|
|
raise err
|
|
|
|
def format(self, info, fmt):
|
|
"""
|
|
The inner method to format collected info.
|
|
|
|
:param info: The decoded info
|
|
:param fmt: The option for format,
|
|
[raw, data, %s]:
|
|
"raw" for original string
|
|
"xml" for xml string
|
|
"json" for json string
|
|
"data" for list of decoded data string
|
|
"table" for pretty table string
|
|
:returns info: Success, formatted info
|
|
:raises NotImplementedError: Error, not supported
|
|
:raises Exceptions: Fail, with info
|
|
"""
|
|
if (fmt == "raw"):
|
|
return info
|
|
elif (fmt == "data"):
|
|
return info.split()
|
|
else:
|
|
err = NotImplementedError("Not supported format: {}".format(fmt))
|
|
logger.error(
|
|
"{}.{}: {}".format(
|
|
self.__class__.__name__,
|
|
sys._getframe().f_code.co_name,
|
|
str(err)))
|
|
raise err
|
|
|
|
def output(self, info, path):
|
|
"""
|
|
The method to output collected info to file.
|
|
|
|
:param info: The formatted info
|
|
:param path: The path to output, None for pass through
|
|
:returns None: Success
|
|
:returns info: Success, output info
|
|
:raises: None
|
|
"""
|
|
if path is None:
|
|
return info
|
|
|
|
f = open(path, mode='w', buffering=-1, encoding=None,
|
|
errors=None, newline=None)
|
|
f.write(info)
|
|
f.close()
|
|
return None
|
|
|
|
|
|
def walk_class_type(father, class_type, desc, datas):
|
|
if "class" in father and \
|
|
father["class"] == class_type:
|
|
if "description" in father and \
|
|
(desc is None or father["description"] == desc):
|
|
datas.append(father)
|
|
return
|
|
if "children" in father:
|
|
for i in father["children"]:
|
|
walk_class_type(i, class_type, desc, datas)
|
|
|
|
|
|
def get_class_type(all, class_type, desc=None):
|
|
datas = []
|
|
walk_class_type(all, class_type, desc, datas)
|
|
dict_datas = {}
|
|
dict_datas[class_type + "s"] = datas
|
|
return dict_datas
|