import logging import universal_tsdb as utsdb import functools import time logging.basicConfig(format='%(asctime)s %(levelname)8s %(name)s: %(message)s', datefmt='%m/%d/%Y %H:%M:%S') logger = logging.getLogger('qolab.tsdb') logger.setLevel(logging.INFO) class Ingester(utsdb.Ingester): """ Same as universal_tsdb.Ingester byt set measurement_prefix. so measurement becomes measurement_prefix.measurement """ def __init__(self, client, batch=0, measurement_prefix=''): super().__init__(client, batch=batch) self.measurement_prefix=measurement_prefix def append(self, timestamp=None, tags=None, measurement=None, **kwargs): if self.measurement_prefix is None or not isinstance(self.measurement_prefix, str): raise ValueError('Invalid measurement_prefix, it should be string') if measurement is None or not isinstance(measurement, str): raise ValueError('Invalid measurement, it should be string') qolab_measurement = '.'.join((self.measurement_prefix, measurement)) # space is illegal for measurements fields qolab_measurement=qolab_measurement.replace(' ', '-') logger.debug(f'{qolab_measurement=} {tags=}, {kwargs=}') return super().append(timestamp=timestamp, tags=tags, measurement=qolab_measurement, **kwargs) def tsdb_append_metric_for_class_setter_or_getter(tsdb_logger=None): def wrap(f): @functools.wraps(f) def wrapper(*args, **kwds): if f.__name__[0:3] != 'get' and f.__name__[0:3] != 'set': logger.warning(f'Do not know how to work with {f.__name__}, it is neither set... or get...') ret = f(*args, **kwds) return ret cls = args[0] action = f.__name__[0:3] var_name = f.__name__[3:] val = None device_type=cls.config['Device type'] if action == 'get': """ getter """ val = f(*args, **kwds) ts = time.time() ret = val else: """ setter """ val = args[1] ts = time.time() ret = f(*args, **kwds) logger.debug(f'function {f.__name__} {action} {var_name} = {val}') ts_ms = int(ts*1000) fields={var_name: val} try: if cls.tsdb_ingester is not None: cls.tsdb_ingester.append(ts_ms, measurement=device_type, tags={'action': action}, **fields) except ValueError as err: logger.error(f'{err=} in function {f.__name__}: {var_name} = {val}') return ret return wrapper return wrap if __name__ == '__main__': from qolab.hardware.basic import BasicInstrument tsdb_client = utsdb.Client('influx', 'http://localhost:8428', database='qolab') tsdb_ingester = Ingester(tsdb_client, batch=10, measurement_prefix='experiment.title') class InstWithLog(BasicInstrument): def __init__(self, *args, **kwds): super().__init__(*args, **kwds) self.config['Device type'] = 'TestTSDBLogger' self.config['Device model'] = 'v01' self.config['FnamePrefix'] = 'test_log' self.config['SavePath'] = './data' self.deviceProperties = ['D']; self.d = 13.45 @BasicInstrument.tsdb_append def setD(self, val): self.d=val @BasicInstrument.tsdb_append def getD(self): """ get D variable """ return self.d dev = InstWithLog(tsdb_ingester=tsdb_ingester) dev.getD() dev.setD(3) tsdb_ingester.commit()