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"), }
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"), }
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"