示例#1
0
def compute_graph_curves(metrics, rrd_data):
    curves = []
    for metric_definition in metrics:
        expression = metric_definition["expression"]
        time_series = evaluate_time_series_expression(expression, rrd_data)
        if not time_series:
            continue

        multi = len(time_series) > 1
        mirror_prefix = "-" if metric_definition["line_type"].startswith("-") else ""
        for i, ts in enumerate(time_series):
            title = metric_definition["title"]
            if ts.metadata.get('title') and multi:
                title += " - " + ts.metadata['title']

            color = metric_definition.get("color", ts.metadata.get('color', "#000000"))
            if i % 2 == 1 and not (expression[0] == "transformation" and
                                   expression[1][0] == "forecast"):
                color = render_color(fade_color(parse_color(color), 0.3))

            curves.append({
                "line_type": mirror_prefix + ts.metadata.get('line_type', "")
                             if multi else metric_definition["line_type"],
                "color": color,
                'title': title,
                'rrddata': ts
            })

    return curves
示例#2
0
def compute_graph_curves(metrics: Sequence[GraphMetric],
                         rrd_data: RRDData) -> list[Curve]:
    curves = []
    for metric_definition in metrics:
        expression = metric_definition["expression"]
        time_series = evaluate_time_series_expression(expression, rrd_data)
        if not time_series:
            continue

        multi = len(time_series) > 1
        mirror_prefix = "-" if metric_definition["line_type"].startswith(
            "-") else ""
        for i, ts in enumerate(time_series):
            title = metric_definition["title"]
            if ts.metadata.get("title") and multi:
                title += " - " + ts.metadata["title"]

            color = metric_definition.get("color",
                                          ts.metadata.get("color", "#000000"))
            if i % 2 == 1 and not (expression[0] == "transformation"
                                   and expression[1][0] == "forecast"):
                color = render_color(fade_color(parse_color(color), 0.3))

            curves.append(
                Curve({
                    "line_type":
                    mirror_prefix + ts.metadata.get("line_type", "")
                    if multi else metric_definition["line_type"],
                    "color":
                    color,
                    "title":
                    title,
                    "rrddata":
                    ts,
                }))

    return curves
示例#3
0
def render_graph_pnp(graph_template, translated_metrics):
    graph_title = None
    vertical_label = None

    rrdgraph_commands = ""

    legend_precision = graph_template.get("legend_precision", 2)
    legend_scale = graph_template.get("legend_scale", 1)
    legend_scale_symbol = scale_symbols[legend_scale]

    # Define one RRD variable for each of the available metrics.
    # Note: We need to use the original name, not the translated one.
    for var_name, metrics in translated_metrics.items():
        rrd = "$RRDBASE$_" + metrics["orig_name"] + ".rrd"
        scale = metrics["scale"]
        unit = metrics["unit"]

        if scale != 1.0:
            rrdgraph_commands += "DEF:%s_UNSCALED=%s:1:MAX " % (var_name, rrd)
            rrdgraph_commands += "CDEF:%s=%s_UNSCALED,%f,* " % (
                var_name, var_name, scale)

        else:
            rrdgraph_commands += "DEF:%s=%s:1:MAX " % (var_name, rrd)

        # Scaling for legend
        rrdgraph_commands += "CDEF:%s_LEGSCALED=%s,%f,/ " % (
            var_name, var_name, legend_scale)

        # Prepare negative variants for upside-down graph
        rrdgraph_commands += "CDEF:%s_NEG=%s,-1,* " % (var_name, var_name)
        rrdgraph_commands += "CDEF:%s_LEGSCALED_NEG=%s_LEGSCALED,-1,* " % (
            var_name, var_name)

    # Now add areas and lines to the graph
    graph_metrics = []

    # Graph with upside down metrics? (e.g. for Disk IO)
    have_upside_down = False

    # Compute width of the right column of the legend
    max_title_length = 0
    for nr, metric_definition in enumerate(graph_template["metrics"]):
        if len(metric_definition) >= 3:
            title = metric_definition[2]
        elif not "," in metric_definition:
            metric_name = metric_definition[0].split("#")[0]
            mi = translated_metrics[metric_name]
            title = mi["title"]
        else:
            title = ""
        max_title_length = max(max_title_length, len(title))

    for nr, metric_definition in enumerate(graph_template["metrics"]):
        metric_name = metric_definition[0]
        line_type = metric_definition[1]  # "line", "area", "stack"

        # Optional title, especially for derived values
        if len(metric_definition) >= 3:
            title = metric_definition[2]
        else:
            title = ""

        # Prefixed minus renders the metrics in negative direction
        if line_type[0] == '-':
            have_upside_down = True
            upside_down = True
            upside_down_factor = -1
            line_type = line_type[1:]
            upside_down_suffix = "_NEG"
        else:
            upside_down = False
            upside_down_factor = 1
            upside_down_suffix = ""

        if line_type == "line":
            draw_type = "LINE"
            draw_stack = ""
        elif line_type == "area":
            draw_type = "AREA"
            draw_stack = ""
        elif line_type == "stack":
            draw_type = "AREA"
            draw_stack = ":STACK"

        # User can specify alternative color using a suffixed #aabbcc
        if '#' in metric_name:
            metric_name, custom_color = metric_name.split("#", 1)
        else:
            custom_color = None

        commands = ""
        # Derived value with RBN syntax (evaluated by RRDTool!).
        if "," in metric_name:
            # We evaluate just in order to get color and unit.
            # TODO: beware of division by zero. All metrics are set to 1 here.
            _value, unit, color = evaluate(metric_name, translated_metrics)

            if "@" in metric_name:
                expression, _explicit_unit_name = metric_name.rsplit(
                    "@", 1)  # isolate expression
            else:
                expression = metric_name

            # Choose a unique name for the derived variable and compute it
            commands += "CDEF:DERIVED%d=%s " % (nr, expression)
            if upside_down:
                commands += "CDEF:DERIVED%d_NEG=DERIVED%d,-1,* " % (nr, nr)

            metric_name = "DERIVED%d" % nr
            # Scaling and upsidedown handling for legend
            commands += "CDEF:%s_LEGSCALED=%s,%f,/ " % (
                metric_name, metric_name, legend_scale)
            if upside_down:
                commands += "CDEF:%s_LEGSCALED%s=%s,%f,/ " % (
                    metric_name, upside_down_suffix, metric_name,
                    legend_scale * upside_down_factor)

        else:
            mi = translated_metrics[metric_name]
            if not title:
                title = mi["title"]
            color = parse_color_into_hexrgb(mi["color"])
            unit = mi["unit"]

        if custom_color:
            color = "#" + custom_color

        # Paint the graph itself
        # TODO: Die Breite des Titels intelligent berechnen. Bei legend = "mirrored" muss man die
        # Vefügbare Breite ermitteln und aufteilen auf alle Titel
        right_pad = " " * (max_title_length - len(title))
        commands += "%s:%s%s%s:\"%s%s\"%s " % (
            draw_type, metric_name, upside_down_suffix, color,
            title.replace(":", "\\:"), right_pad, draw_stack)
        if line_type == "area":
            commands += "LINE:%s%s%s " % (
                metric_name, upside_down_suffix,
                render_color(darken_color(parse_color(color), 0.2)))

        unit_symbol = unit["symbol"]
        if unit_symbol == "%":
            unit_symbol = "%%"
        else:
            unit_symbol = " " + unit_symbol

        graph_metrics.append((metric_name, unit_symbol, commands))

        # Use title and label of this metrics as default for the graph
        if title and not graph_title:
            graph_title = title
        if not vertical_label:
            vertical_label = unit["title"]

    # Now create the rrdgraph commands for all metrics - according to the choosen layout
    for metric_name, unit_symbol, commands in graph_metrics:
        rrdgraph_commands += commands

        legend_symbol = unit_symbol
        if unit_symbol and unit_symbol[0] == " ":
            legend_symbol = " %s%s" % (legend_scale_symbol, unit_symbol[1:])
        if legend_symbol == " bits/s":
            # Use a literal '%s' so that GPRINT outputs values with the appropriate
            # SI magnitude (e.g. 123456 -> 123.456 k)
            legend_symbol = " %sbit/s"

        for what, what_title in [("AVERAGE", _("average")), ("MAX", _("max")),
                                 ("LAST", _("last"))]:
            rrdgraph_commands += "GPRINT:%s_LEGSCALED:%s:\"%%8.%dlf%s %s\" " % (
                metric_name,
                what,
                legend_precision,
                legend_symbol,
                what_title,
            )
        rrdgraph_commands += "COMMENT:\"\\n\" "

    # add horizontal rules for warn and crit scalars
    for scalar in graph_template.get("scalars", []):
        rrdgraph_commands += _scalar_value_command(scalar, translated_metrics)

    # For graphs with both up and down, paint a gray rule at 0
    if have_upside_down:
        rrdgraph_commands += "HRULE:0#c0c0c0 "

    # Now compute the arguments for the command line of rrdgraph
    rrdgraph_arguments = ""

    graph_title = graph_template.get("title", graph_title)
    vertical_label = graph_template.get("vertical_label", vertical_label)

    rrdgraph_arguments += " --vertical-label %s --title %s " % (
        cmk.utils.quote_shell_string(
            vertical_label or " "), cmk.utils.quote_shell_string(graph_title))

    min_value, max_value = get_graph_range(graph_template, translated_metrics)
    if min_value is not None and max_value is not None:
        rrdgraph_arguments += " -l %f -u %f" % (min_value, max_value)
    else:
        rrdgraph_arguments += " -l 0"

    return graph_title + "\n" + rrdgraph_arguments + "\n" + rrdgraph_commands + "\n"