Esempio n. 1
0
def create_graph_recipe_from_template(graph_template: GraphTemplate,
                                      translated_metrics: TranslatedMetrics,
                                      row: Row) -> GraphRecipe:
    def _metric(metric_definition: MetricDefinition) -> GraphMetric:
        metric = GraphMetric({
            "title":
            metric_line_title(metric_definition, translated_metrics),
            "line_type":
            metric_definition[1],
            "expression":
            metric_expression_to_graph_recipe_expression(
                metric_definition[0],
                translated_metrics,
                row,
                graph_template.get("consolidation_function", "max"),
            ),
        })

        unit_color = metric_unit_color(metric_definition[0],
                                       translated_metrics)
        if unit_color:
            metric.update({
                "color": unit_color["color"],
                "unit": unit_color["unit"],
            })
        return metric

    metrics = list(map(_metric, graph_template["metrics"]))
    units = {m["unit"] for m in metrics}
    if len(units) > 1:
        raise MKGeneralException(
            _("Cannot create graph with metrics of "
              "different units '%s'") % ", ".join(units))

    title = replace_expressions(str(graph_template.get("title", "")),
                                translated_metrics)
    if not title:
        title = next((m["title"] for m in metrics if m["title"]), "")

    return {
        "title":
        title,
        "metrics":
        metrics,
        "unit":
        units.pop(),
        "explicit_vertical_range":
        get_graph_range(graph_template, translated_metrics),
        "horizontal_rules":
        horizontal_rules_from_thresholds(
            graph_template.get("scalars", []),
            translated_metrics),  # e.g. lines for WARN and CRIT
        "omit_zero_metrics":
        graph_template.get("omit_zero_metrics", False),
        "consolidation_function":
        graph_template.get("consolidation_function", "max"),
    }
Esempio n. 2
0
def create_graph_recipe_from_template(graph_template, translated_metrics, row):
    def _metrics(metric_definition):
        return {
            **metric_unit_color(metric_definition[0], translated_metrics), "title":
            metric_line_title(metric_definition, translated_metrics),
            "line_type":
            metric_definition[1],
            "expression":
            metric_expression_to_graph_recipe_expression(
                metric_definition[0], translated_metrics, row,
                graph_template.get("consolidation_function", "max"))
        }

    metrics = list(map(_metrics, graph_template['metrics']))
    units = {m['unit'] for m in metrics}
    if len(units) > 1:
        raise MKGeneralException(
            _("Cannot create graph with metrics of "
              "different units '%s'") % ", ".join(units))

    title = replace_expressions(graph_template.get("title", ""),
                                translated_metrics)
    if not title:
        title = next((m['title'] for m in metrics if m['title']), "")

    return {
        "title":
        title,
        "metrics":
        metrics,
        "unit":
        units.pop(),
        "explicit_vertical_range":
        get_graph_range(graph_template, translated_metrics),
        "horizontal_rules":
        _horizontal_rules_from_thresholds(
            graph_template.get("scalars", []),
            translated_metrics),  # e.g. lines for WARN and CRIT
        "omit_zero_metrics":
        graph_template.get("omit_zero_metrics", False),
        "consolidation_function":
        graph_template.get("consolidation_function", "max"),
    }
Esempio n. 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"