pvl/rrd/api.py
author Tero Marttila <terom@paivola.fi>
Sun, 10 Feb 2013 13:20:29 +0200
changeset 205 f7658198c224
parent 155 9f2967ba81ef
child 232 5894c70dc6a8
permissions -rw-r--r--
pvl.verkko.hosts: refactor RealtimeHandler to use HostsTable
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))