def render_graph_content_html(graph_recipe, graph_data_range, graph_render_options): output = "" try: graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) main_graph_html = render_graph_or_error_html(graph_artwork, graph_data_range, graph_render_options) previews = graph_render_options["show_time_range_previews"] if graph_recipe['specification'][0] == 'forecast': previews = False if previews: output += "<div class=\"graph_with_timeranges\">" output += main_graph_html output += render_time_range_selection(graph_recipe, graph_render_options) output += "</div>" else: output += main_graph_html except livestatus.MKLivestatusNotFoundError: output += render_graph_error_html( _("Cannot fetch data via Livestatus"), _("Cannot create graph")) except Exception as e: output += render_graph_error_html(e, _("Cannot create graph")) return output
def render_graph_content_html(graph_recipe, graph_data_range, graph_render_options) -> HTML: output = HTML() try: graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) main_graph_html = render_graph_or_error_html(graph_artwork, graph_data_range, graph_render_options) previews = graph_render_options["show_time_range_previews"] if graph_recipe["specification"][0] == "forecast": previews = False if previews: output += html.render_div( main_graph_html + render_time_range_selection( graph_recipe, graph_render_options), class_="graph_with_timeranges", ) else: output += main_graph_html except livestatus.MKLivestatusNotFoundError: output += render_graph_error_html( _("Cannot fetch data via Livestatus"), _("Cannot create graph")) except Exception as e: output += render_graph_error_html(e, _("Cannot create graph")) return output
def render_time_range_selection(graph_recipe, graph_render_options): now = int(time.time()) output: RenderOutput = "<table class=timeranges>" graph_render_options = copy.deepcopy(graph_render_options) for timerange_attrs in config.graph_timeranges: duration = timerange_attrs["duration"] assert isinstance(duration, int) graph_render_options.update({ "size": (20, 4), "font_size": 6.0, # pt "onclick": "cmk.graphs.change_graph_timerange(graph, %d)" % duration, "fixed_timerange": True, # Do not follow timerange changes of other graphs "title": timerange_attrs["title"], "show_legend": False, "show_controls": False, "preview": True, "resizable": False, "interaction": False, }) timerange = now - duration, now graph_data_range = { "time_range": timerange, "step": 2 * estimate_graph_step_for_html(timerange, graph_render_options), } output += "<td title=\"%s\">\n" % (_("Change graph timerange to: %s") % timerange_attrs["title"]) graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) output += render_graph_html(graph_artwork, graph_data_range, graph_render_options) output += "\n</td>" output += "</tr><tr>" output += "</table>" return output
def _answer_graph_image_request() -> None: try: host_name = request.var("host") if not host_name: raise MKGeneralException(_("Missing mandatory \"host\" parameter")) service_description = request.var("service", "_HOST_") site = request.var("site") # FIXME: We should really enforce site here. But it seems that the notification context # has no idea about the site of the host. This could be optimized later. #if not site: # raise MKGeneralException("Missing mandatory \"site\" parameter") try: row = get_graph_data_from_livestatus(site, host_name, service_description) except livestatus.MKLivestatusNotFoundError: if config.debug: raise raise Exception( _("Cannot render graph: host %s, service %s not found.") % (host_name, service_description)) site = row["site"] # Always use 25h graph in notifications end_time = time.time() start_time = end_time - (25 * 3600) graph_render_options = graph_image_render_options() graph_identification = ( "template", { "site": site, "host_name": host_name, "service_description": service_description, "graph_index": None, # all graphs }) graph_data_range = graph_image_data_range(graph_render_options, start_time, end_time) graph_recipes = graph_identification_types.create_graph_recipes( graph_identification, destination=html_render.GraphDestinations.notification) num_graphs = request.get_integer_input("num_graphs") or len(graph_recipes) graphs = [] for graph_recipe in graph_recipes[:num_graphs]: graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) graph_png = render_graph_image(graph_artwork, graph_data_range, graph_render_options) graphs.append(base64.b64encode(graph_png).decode("ascii")) response.set_data(json.dumps(graphs)) except Exception as e: logger.error("Call to ajax_graph_images.py failed: %s\n%s", e, traceback.format_exc()) if config.debug: raise
def render_time_range_selection(graph_recipe, graph_render_options) -> HTML: now = int(time.time()) graph_render_options = copy.deepcopy(graph_render_options) rows = [] for timerange_attrs in config.graph_timeranges: duration = timerange_attrs["duration"] assert isinstance(duration, int) graph_render_options.update({ "size": (20, 4), "font_size": 6.0, # pt "onclick": "cmk.graphs.change_graph_timerange(graph, %d)" % duration, "fixed_timerange": True, # Do not follow timerange changes of other graphs "title": timerange_attrs["title"], "show_legend": False, "show_controls": False, "preview": True, "resizable": False, "interaction": False, }) timerange = now - duration, now graph_data_range = { "time_range": timerange, "step": 2 * estimate_graph_step_for_html(timerange, graph_render_options), } graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) rows.append( html.render_td( render_graph_html(graph_artwork, graph_data_range, graph_render_options), title=_("Change graph timerange to: %s") % timerange_attrs["title"], )) return html.render_table(HTML().join( html.render_tr(content) for content in rows), class_="timeranges")
def host_service_graph_dashlet_cmk(graph_identification, custom_graph_render_options): graph_render_options = default_dashlet_graph_render_options.copy() graph_render_options = artwork.add_default_render_options( graph_render_options) graph_render_options.update(custom_graph_render_options) width_var = html.request.get_float_input_mandatory("width", 0.0) width = int((width_var / html_size_per_ex)) height_var = html.request.get_float_input_mandatory("height", 0.0) height = int((height_var / html_size_per_ex)) bounds = _graph_margin_ex(graph_render_options) height -= _graph_title_height_ex(graph_render_options) height -= bounds.top + bounds.bottom width -= bounds.left + bounds.right graph_render_options["size"] = (width, height) # The timerange is specified in PNP like manner. range_secs = { "0": 4 * 3600, "1": 25 * 3600, "2": 7 * 86400, "3": 31 * 86400, "4": 366 * 86400, } secs_var = html.request.var("timerange") if secs_var not in range_secs: secs = 4 * 3600 else: secs = range_secs[secs_var] end_time = time.time() start_time = end_time - secs graph_data_range = { "time_range": (start_time, end_time), } graph_data_range["step"] = estimate_graph_step_for_html( graph_data_range["time_range"], graph_render_options) try: graph_recipes = graph_identification_types.create_graph_recipes( graph_identification, destination=GraphDestinations.dashlet) if graph_recipes: graph_recipe = graph_recipes[0] else: raise MKGeneralException(_("Failed to calculate a graph recipe.")) except livestatus.MKLivestatusNotFoundError: html.div(_("Cannot render graphs: cannot fetch data via Livestatus"), class_="error") return # When the legend is enabled, we need to reduce the height by the height of the legend to # make the graph fit into the dashlet area. if graph_render_options["show_legend"]: # TODO FIXME: This graph artwork is calulated twice. Once here and once in render_graphs_from_specification_html() graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) if graph_artwork["curves"]: legend_height = graph_legend_height_ex(graph_render_options, graph_artwork) graph_render_options["size"] = (width, height - legend_height) html_code = render_graphs_from_definitions([graph_recipe], graph_data_range, graph_render_options, render_async=False) html.write(html_code)
def render_ajax_graph(context): graph_data_range = context["data_range"] graph_render_options = context["render_options"] graph_recipe = context["definition"] start_time_var = html.request.var("start_time") end_time_var = html.request.var("end_time") step_var = html.request.var("step") if start_time_var is not None and end_time_var is not None and step_var is not None: start_time = float(start_time_var) end_time = float(end_time_var) step = float(step_var) else: start_time, end_time = graph_data_range["time_range"] step = graph_data_range["step"] size = graph_render_options["size"] resize_x_var = html.request.var("resize_x") resize_y_var = html.request.var("resize_y") if resize_x_var is not None and resize_y_var is not None: render_opt_x, render_opt_y = context["render_options"]["size"] size_x = max(min_resize_width, float(resize_x_var) / html_size_per_ex + render_opt_x) size_y = max(min_resize_height, float(resize_y_var) / html_size_per_ex + render_opt_y) config.user.save_file("graph_size", (size_x, size_y)) size = (size_x, size_y) range_from_var = html.request.var("range_from") range_to_var = html.request.var("range_to") if range_from_var is not None and range_to_var is not None: vertical_range: Optional[Tuple[float, float]] = (float(range_from_var), float(range_to_var)) else: vertical_range = None if html.request.has_var("pin"): artwork.save_graph_pin() if html.request.has_var("consolidation_function"): graph_recipe["consolidation_function"] = html.request.var( "consolidation_function") graph_render_options["size"] = size graph_data_range["time_range"] = (start_time, end_time) graph_data_range["vertical_range"] = vertical_range graph_data_range["step"] = step # Persist the current data range for the graph editor if graph_render_options["editing"]: save_user_graph_data_range(graph_data_range) graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) html_code = render_graph_html_content(graph_artwork, graph_data_range, graph_render_options) return { "html": html_code, "graph": graph_artwork, "context": { "graph_id": context["graph_id"], "definition": graph_recipe, "data_range": graph_data_range, "render_options": graph_render_options, } }
def host_service_graph_dashlet_cmk( graph_identification: GraphIdentifier, custom_graph_render_options, ): graph_render_options = {**default_dashlet_graph_render_options} graph_render_options = artwork.add_default_render_options( graph_render_options) graph_render_options.update(custom_graph_render_options) width_var = request.get_float_input_mandatory("width", 0.0) width = int((width_var / html_size_per_ex)) height_var = request.get_float_input_mandatory("height", 0.0) height = int((height_var / html_size_per_ex)) bounds = _graph_margin_ex(graph_render_options) height -= _graph_title_height_ex(graph_render_options) height -= bounds.top + bounds.bottom width -= bounds.left + bounds.right graph_render_options["size"] = (width, height) timerange = json.loads(request.get_str_input_mandatory("timerange")) if isinstance(timerange, list): end_time = timerange[1] start_time = timerange[0] else: end_time = time.time() start_time = end_time - float(timerange) graph_data_range = { "time_range": (start_time, end_time), } graph_data_range["step"] = estimate_graph_step_for_html( graph_data_range["time_range"], graph_render_options) graph_recipes = resolve_graph_recipe_with_error_handling( graph_identification, destination=GraphDestinations.dashlet, ) if not isinstance(graph_recipes, list): return graph_recipes # This is to html.write the exception if graph_recipes: graph_recipe = graph_recipes[0] else: raise MKGeneralException(_("Failed to calculate a graph recipe.")) # When the legend is enabled, we need to reduce the height by the height of the legend to # make the graph fit into the dashlet area. if graph_render_options["show_legend"]: # TODO FIXME: This graph artwork is calulated twice. Once here and once in render_graphs_from_specification_html() graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) if graph_artwork["curves"]: legend_height = graph_legend_height_ex(graph_render_options, graph_artwork) graph_render_options["size"] = (width, height - legend_height) html_code = render_graphs_from_definitions([graph_recipe], graph_data_range, graph_render_options, render_async=False) html.write_html(html_code)
def render_ajax_graph(context): graph_data_range = context["data_range"] graph_render_options = context["render_options"] graph_recipe = context["definition"] if html.request.has_var("start_time"): start_time = float(html.request.var("start_time")) end_time = float(html.request.var("end_time")) step = float(html.request.var("step")) else: start_time, end_time = graph_data_range["time_range"] step = graph_data_range["step"] if html.request.has_var("resize_x"): # then has always also resize_y size_x = max( min_resize_width, float(html.request.var("resize_x")) / html_size_per_ex + context["render_options"]["size"][0]) size_y = max( min_resize_height, float(html.request.var("resize_y")) / html_size_per_ex + context["render_options"]["size"][1]) size = size_x, size_y config.user.save_file("graph_size", size) else: size = context["render_options"]["size"] if html.request.has_var("range_from"): range_from = float(html.request.var("range_from")) range_to = float(html.request.var("range_to")) vertical_range = (range_from, range_to) else: vertical_range = None if html.request.has_var("pin"): artwork.save_graph_pin() if html.request.has_var("consolidation_function"): graph_recipe["consolidation_function"] = html.request.var( "consolidation_function") graph_render_options["size"] = size graph_data_range["time_range"] = (start_time, end_time) graph_data_range["vertical_range"] = vertical_range graph_data_range["step"] = step # Persist the current data range for the graph editor if graph_render_options["editing"]: save_user_graph_data_range(graph_data_range) graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) html_code = render_graph_html_content(graph_artwork, graph_data_range, graph_render_options) return { "html": html_code, "graph": graph_artwork, "context": { "graph_id": context["graph_id"], "definition": graph_recipe, "data_range": graph_data_range, "render_options": graph_render_options, } }