improvements on interactive client
- fix handling of exceptions - add selective logging - improve formatting of values Change-Id: I69c11e95aca1cdd222800fd3fd192a6b12b38411 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29348 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
parent
0a28192c15
commit
71aaf7187a
@ -356,7 +356,7 @@ class SecopClient(ProxyClient):
|
|||||||
except ConnectionClosed:
|
except ConnectionClosed:
|
||||||
pass
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.error('rxthread ended with %s' % e)
|
self.log.error('rxthread ended with %r', e)
|
||||||
self._rxthread = None
|
self._rxthread = None
|
||||||
self.disconnect(False)
|
self.disconnect(False)
|
||||||
if self._shutdown:
|
if self._shutdown:
|
||||||
@ -490,7 +490,7 @@ class SecopClient(ProxyClient):
|
|||||||
|
|
||||||
def _unhandled_message(self, action, ident, data):
|
def _unhandled_message(self, action, ident, data):
|
||||||
if not self.callback(None, 'unhandledMessage', action, ident, data):
|
if not self.callback(None, 'unhandledMessage', action, ident, data):
|
||||||
self.log.warning('unhandled message: %s %s %r' % (action, ident, data))
|
self.log.warning('unhandled message: %s %s %r', action, ident, data)
|
||||||
|
|
||||||
def _set_state(self, online, state=None):
|
def _set_state(self, online, state=None):
|
||||||
# remark: reconnecting is treated as online
|
# remark: reconnecting is treated as online
|
||||||
|
@ -23,10 +23,11 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import json
|
import re
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from secop.client import SecopClient
|
from secop.client import SecopClient
|
||||||
from secop.errors import SECoPError
|
from secop.errors import SECoPError
|
||||||
|
from secop.datatypes import get_datatype
|
||||||
|
|
||||||
USAGE = """
|
USAGE = """
|
||||||
Usage:
|
Usage:
|
||||||
@ -58,10 +59,15 @@ class Logger:
|
|||||||
if lev == loglevel:
|
if lev == loglevel:
|
||||||
func = self.emit
|
func = self.emit
|
||||||
setattr(self, lev, func)
|
setattr(self, lev, func)
|
||||||
|
self._minute = 0
|
||||||
|
|
||||||
@staticmethod
|
def emit(self, fmt, *args, **kwds):
|
||||||
def emit(fmt, *args, **kwds):
|
now = time.time()
|
||||||
print(str(fmt) % args)
|
minute = now // 60
|
||||||
|
if minute != self._minute:
|
||||||
|
self._minute = minute
|
||||||
|
print(time.strftime('--- %H:%M:%S ---', time.localtime(now)))
|
||||||
|
print('%6.3f' % (now % 60.0), str(fmt) % args)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def noop(fmt, *args, **kwds):
|
def noop(fmt, *args, **kwds):
|
||||||
@ -77,6 +83,8 @@ class PrettyFloat(float):
|
|||||||
|
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
|
_log_pattern = re.compile('.*')
|
||||||
|
|
||||||
def __init__(self, name, secnode):
|
def __init__(self, name, secnode):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._secnode = secnode
|
self._secnode = secnode
|
||||||
@ -89,15 +97,12 @@ class Module:
|
|||||||
|
|
||||||
def _one_line(self, pname, minwid=0):
|
def _one_line(self, pname, minwid=0):
|
||||||
"""return <module>.<param> = <value> truncated to one line"""
|
"""return <module>.<param> = <value> truncated to one line"""
|
||||||
|
param = getattr(type(self), pname)
|
||||||
try:
|
try:
|
||||||
value = getattr(self, pname)
|
value = getattr(self, pname)
|
||||||
# make floats appear with 7 digits only
|
r = param.format(value)
|
||||||
r = repr(json.loads(json.dumps(value), parse_float=PrettyFloat))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
r = repr(e)
|
r = repr(e)
|
||||||
unit = getattr(type(self), pname).unit
|
|
||||||
if unit:
|
|
||||||
r += ' %s' % unit
|
|
||||||
pname = pname.ljust(minwid)
|
pname = pname.ljust(minwid)
|
||||||
vallen = 113 - len(self._name) - len(pname)
|
vallen = 113 - len(self._name) - len(pname)
|
||||||
if len(r) > vallen:
|
if len(r) > vallen:
|
||||||
@ -174,13 +179,21 @@ class Module:
|
|||||||
'\n'.join(self._one_line(k, wid) for k in self._parameters),
|
'\n'.join(self._one_line(k, wid) for k in self._parameters),
|
||||||
', '.join(k + '()' for k in self._commands))
|
', '.join(k + '()' for k in self._commands))
|
||||||
|
|
||||||
|
def logging(self, level='comlog', pattern='.*'):
|
||||||
|
self._log_pattern = re.compile(pattern)
|
||||||
|
self._secnode.request('logging', self._name, level)
|
||||||
|
|
||||||
|
def handle_log_message_(self, data):
|
||||||
|
if self._log_pattern.match(data):
|
||||||
|
self._secnode.log.info('%s: %r', self._name, data)
|
||||||
|
|
||||||
|
|
||||||
class Param:
|
class Param:
|
||||||
def __init__(self, name, unit=None):
|
def __init__(self, name, datainfo):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.prev = None
|
self.prev = None
|
||||||
self.prev_time = 0
|
self.prev_time = 0
|
||||||
self.unit = unit
|
self.datatype = get_datatype(datainfo)
|
||||||
|
|
||||||
def __get__(self, obj, owner):
|
def __get__(self, obj, owner):
|
||||||
if obj is None:
|
if obj is None:
|
||||||
@ -198,6 +211,9 @@ class Param:
|
|||||||
except SECoPError as e:
|
except SECoPError as e:
|
||||||
obj._secnode.log.error(repr(e))
|
obj._secnode.log.error(repr(e))
|
||||||
|
|
||||||
|
def format(self, value):
|
||||||
|
return self.datatype.format_value(value)
|
||||||
|
|
||||||
|
|
||||||
class Command:
|
class Command:
|
||||||
def __init__(self, name, modname, secnode):
|
def __init__(self, name, modname, secnode):
|
||||||
@ -250,14 +266,24 @@ class Client(SecopClient):
|
|||||||
self.log.info('overwrite module %s', modname)
|
self.log.info('overwrite module %s', modname)
|
||||||
attrs = {}
|
attrs = {}
|
||||||
for pname, pinfo in moddesc['parameters'].items():
|
for pname, pinfo in moddesc['parameters'].items():
|
||||||
unit = pinfo['datainfo'].get('unit')
|
attrs[pname] = Param(pname, pinfo['datainfo'])
|
||||||
attrs[pname] = Param(pname, unit)
|
|
||||||
for cname in moddesc['commands']:
|
for cname in moddesc['commands']:
|
||||||
attrs[cname] = Command(cname, modname, self)
|
attrs[cname] = Command(cname, modname, self)
|
||||||
mobj = type('M_%s' % modname, (Module,), attrs)(modname, self)
|
mobj = type('M_%s' % modname, (Module,), attrs)(modname, self)
|
||||||
if 'status' in mobj._parameters:
|
if 'status' in mobj._parameters:
|
||||||
self.register_callback((modname, 'status'), updateEvent=mobj._status_value_update)
|
self.register_callback((modname, 'status'), updateEvent=mobj._status_value_update)
|
||||||
self.register_callback((modname, 'value'), updateEvent=mobj._status_value_update)
|
self.register_callback((modname, 'value'), updateEvent=mobj._status_value_update)
|
||||||
|
|
||||||
setattr(main, modname, mobj)
|
setattr(main, modname, mobj)
|
||||||
|
self.register_callback(None, self.unhandledMessage)
|
||||||
self.log.info('%s', USAGE)
|
self.log.info('%s', USAGE)
|
||||||
|
|
||||||
|
def unhandledMessage(self, action, ident, data):
|
||||||
|
"""handle logging messages"""
|
||||||
|
if action == 'log':
|
||||||
|
modname = ident.split(':')[0]
|
||||||
|
modobj = getattr(main, modname, None)
|
||||||
|
if modobj:
|
||||||
|
modobj.handle_log_message_(data)
|
||||||
|
return
|
||||||
|
self.log.info('module %s not found', modname)
|
||||||
|
self.log.info('unhandled: %s %s %r', action, ident, data)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user