import rrdtool
import pvl.invoke
import tempfile
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, *defs, **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!
XXX: tempfile suffix as .png?
"""
if out is None :
# tempfile
out_file = tempfile.NamedTemporaryFile(suffix='.png', delete=True) # python2.6
out_path = out_file.name
elif out is False :
out_file = None
out_path = '-'
else :
# for reading
out_path = out
out_file = True # open later
log.debug("%s", out_path)
# XXX: handle tempfile close?
width, height, out_lines = cmd(rrdtool.graph, (out_path, ), opts, defs)
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))