# -*- coding: utf-8
# pylint: disable=unused-import
#------------------------------------------------------------------#
__author__ = "Xavier MARCELET <xavier@marcelet.com>"
#------------------------------------------------------------------#
from future.utils import with_metaclass
from ..error import XtdError
from .. import mixin
from ..tools import thread
from .. import error
from .counter import BaseCounter
from .handler import BaseHandler
#------------------------------------------------------------------#
[docs]class StatManager(with_metaclass(mixin.Singleton, thread.SafeThreadGroup)):
[docs] def __init__(self):
super(StatManager, self).__init__(__name__)
self.m_counters = {}
[docs] def exists(self, p_ns, p_name):
l_list = self.m_counters.get(p_ns, [])
l_counters = [ x for x in l_list if x.m_name == p_name ]
return len(l_counters) != 0
[docs] def register_counter(self, p_ns, p_counter):
""" Register a counter in global statistics
Args:
p_ns (str): namespace
p_counter (BaseCounter): counter object to add
Raises:
XtdError: counter already defined for this namespace
XtdError: ``p_counter`` is not a valid :py:class:`~xtd.core.stat.counter.BaseCounter` object
"""
if not issubclass(p_counter.__class__, BaseCounter):
raise XtdError(__name__, "attempt to add invalid object type")
if self.exists(p_ns, p_counter.m_name):
raise XtdError(__name__, "already defined counter '%s' in namespace '%s'",
p_counter.m_name, p_ns)
if not p_ns in self.m_counters:
self.m_counters[p_ns] = []
self.m_counters[p_ns].append(p_counter)
[docs] def register_handler(self, p_handler):
""" Register an counter output handler
Args:
p_handler (BaseHandler) : new handler to add
Raises:
XtdError: given ``p_handler`` is not a valid :py:class:`~xtd.core.stat.handler.BaseHandler`
"""
if not issubclass(p_handler.__class__, BaseHandler):
raise error.XtdError(__name__, "handlers must be BaseHandler based class")
self.add_thread(p_handler)
[docs] def get(self, p_ns, p_name):
""" Get a counter in a particular namespace
Returns:
BaseCounter: requests counter
Raises:
XtdError: undefined namespace ``p_ns``
XtdError: undefined counter ``p_name`` for given namespace
"""
if not p_ns in self.m_counters:
raise error.XtdError(__name__, "undefined namespace '%s'" % p_ns)
for c_counter in self.m_counters[p_ns]:
if c_counter.m_name == p_name:
return c_counter
raise error.XtdError(__name__, "undefined counter '%s' in namespace '%s'" % (p_name, p_ns))
[docs] def write(self):
""" Output counter is all registered handlers """
for c_handler in self.m_threads:
c_handler.write()
[docs] def get_all(self):
""" Get registered counters
Example:
::
{
"name.space.1" : [ <counter-object-1>, <counter-object-2>, ... ],
...
"name.space.N" : [ <counter-object-N>, <counter-object-N+1>, ... ],
}
Returns:
dict: dictionary containing raw counters
"""
return self.m_counters
[docs] def get_json(self):
""" Get counter data in a dictionary
Example:
::
{
"name.space.1" : {
"counter1" : <value1>,
"counter2" : <value2>
},
...
"name.space" : {
"counterN" : <valueN>
}
}
Returns:
dict: counter's name and value organized by namespace
"""
l_res = {}
for c_ns, c_counters in self.m_counters.items():
l_res[c_ns] = {}
for c_counter in c_counters:
c_counter.update()
def functor(p_name, p_value):
# pylint: disable=cell-var-from-loop
l_res[c_ns][p_name] = p_value
c_counter.visit(functor)
return l_res
#------------------------------------------------------------------#
# Local Variables:
# ispell-local-dictionary: "american"
# End: