"""dsc_datatool.output.prometheus See `man dsc-datatool-output prometheus`. Part of dsc_datatool. :copyright: 2024 OARC, Inc. """ import re import sys import atexit from dsc_datatool import Output, args, encoding _re = re.compile(r'([\\\n"])') def _key(key): return re.sub(_re, r'\\\1', key) def _val(val): ret = re.sub(_re, r'\\\1', val) if ret == '': return '""' return '"%s"' % ret class Prometheus(Output): show_timestamp = True start_timestamp = True fh = None type_def = '' type_printed = False prefix = '' def __init__(self, opts): Output.__init__(self, opts) timestamp = opts.get('timestamp', 'start') if timestamp == 'hide': self.show_timestamp = False elif timestamp == 'start': pass elif timestamp == 'stop': self.start_timestamp = False else: raise Exception('timestamp option invalid') file = opts.get('file', None) append = opts.get('append', False) if file: if append: self.fh = open(file, 'a', encoding=encoding) else: self.fh = open(file, 'w', encoding=encoding) atexit.register(self.close) else: self.fh = sys.stdout self.prefix = opts.get('prefix', '') def close(self): if self.fh: self.fh.close() self.fh = None def _process(self, tags, timestamp, dimension, fh): if dimension.dimensions is None: return if len(dimension.dimensions) > 0: if not (dimension.name == 'All' and dimension.value == 'ALL'): tags += ',%s=%s' % (_key(dimension.name.lower()), _val(dimension.value)) for d2 in dimension.dimensions: self._process(tags, timestamp, d2, fh) return if dimension.values is None: return if len(dimension.values) > 0: tags += ',%s=' % _key(dimension.name.lower()) for k, v in dimension.values.items(): if not self.type_printed: print(self.type_def, file=fh) self.type_printed = True if self.show_timestamp: print('%s%s} %s %s' % (tags, _val(k), v, timestamp), file=fh) else: print('%s%s} %s' % (tags, _val(k), v), file=fh) def process(self, datasets): for dataset in datasets: self.type_def = '# TYPE %s gauge' % _key(dataset.name.lower()) self.type_printed = False tags = '%s%s{server=%s,node=%s' % (self.prefix, _key(dataset.name.lower()), _val(args.server), _val(args.node)) if self.start_timestamp: timestamp = dataset.start_time * 1000 else: timestamp = dataset.end_time * 1000 for d in dataset.dimensions: self._process(tags, timestamp, d, self.fh) if sys.version_info[0] == 3 and sys.version_info[1] == 5: # pragma: no cover Output.__init_subclass__(Prometheus)