diff -r e5dafbc87cbb -r fb48ba17ae3e pvl/rrd/api.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pvl/rrd/api.py Sun Jan 20 15:37:59 2013 +0200 @@ -0,0 +1,111 @@ +import rrdtool + +import pvl.invoke + +import logging; log = logging.getLogger('pvl.rrd.api') + +""" + Wrapper around the rrdtool python interface +""" + +def timestamp (time=None) : + """ + Format datetime value for rrdtool. + """ + + if not time : + return None + + elif isinstance(time, datetime.datetime) : + return int(time.mktime(dt.timetuple())) + + elif isinstance(time, datetime.timedelta) : + raise NotImplementedError("pvl.rrd.api.timestamp: timedelta") + + else : + # dunno + return str(dt) + +def cmd (func, pre, opts, post) : + """ + Run the given rrdtool.* function, formatting the given positional arguments and options. + + Returns the return value, which varies... + """ + + log.debug("%s: %s: %s: %s", func, pre, opts, post) + + # { opt: arg } -> [ '--opt', arg ] + opts = pvl.invoke.optargs(**opts) + + # positional arguments + pre = pvl.invoke.optargs(*pre) + post = pvl.invoke.optargs(*post) + + return func(*(pre + opts + post)) + +def graph (out=None, *args, **opts) : + """ + Render a graph image and/or print a report from data stored in one or several RRDs. + + out - None -> tempfile + - False -> stdout + - path -> write to file + + Returns: + (width, height) - pixel dimensions of the resulting graph image + report_output - any PRINT'd output (?) + graph_file - file-like object containing graph image, unless out=False -> stdout + + With out=None, the returned graph_file is a tempfile which will be cleaned up by Python once close()'d! + """ + + if out is None : + # tempfile + out_file = tempfile.NamedTemporaryFile(suffix='.png', delete=True) # python2.6 + out_path = out.name + + elif out is False : + out_file = None + out_path = '-' + + else : + # for reading + out_path = out + out_file = True # open later + + # XXX: handle tempfile close? + width, height, out_lines = cmd(rrdtool.graph, (out_path, ), opts, args) + + if out_file is True : + out_file = open(out_path) + + return (width, height), out_lines, out_file + +def fetch (rrd, cf, **opts) : + """ + Fetch values from RRD. + + Returns + (start, end, step) - xrange(...) for row timestamps + (ds, ...) - columns (ds name) + ((value, ...), ...) - rows (data by ds) + """ + + return cmd(rrdtool.fetch, (rrd, cf), opts, ()) + +def _fetch (rrd, cf='AVERAGE', resolution=None, start=None, end=None, **opts) : + """ + Yields (timestamp, { ds: value }) for given ds-values, or all. + """ + + steps, sources, rows = fetch(rrd, cf, + resolution = resolution, + start = timestamp(start), + end = timestamp(end), + **opts + ) + + for ts, row in zip(xrange(*steps), rows) : + yield datetime.fromtimestamp(ts), dict(zip(sources, row)) +