1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
import logging
import universal_tsdb as utsdb
from universal_tsdb import Client, MaxErrorsException
import functools
import time
__all__ = [
'Client', 'Ingester', 'MaxErrorsException'
]
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 but sets 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
if cls.config['DeviceNickname'] is not None:
device_type=cls.config['DeviceNickname']
else:
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 = 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, device_nickname='tester')
dev.getD()
dev.setD(3)
tsdb_ingester.commit()
|