def list_logs(host, logfiles): rowno = 0 for log_file in logfiles: rowno += 1 if rowno == 1: html.write("<tr class=groupheader>\n") html.write("<th>"+_('Level')+"</th><th>"+_('Logfile')+"</th>") html.write("<th>"+_('Last Entry')+"</th><th>"+_('Entries')+"</th></tr>\n") file_display = form_file_to_ext(log_file) logs = parse_file(host, log_file) if logs == [] or type(logs) != list: # corrupted logfile if logs == []: logs = "empty" html.write("<tr class=%s0>\n" % (rowno % 2 == 0 and "odd" or "even")) html.write("<td>-</td><td>%s</td><td>%s</td><td>0</td></tr>\n" % (htmllib.attrencode(logs), htmllib.attrencode(file_display))) else: worst_log = get_worst_log(logs) last_log = get_last_log(logs) state = worst_log['level'] state_name = form_level(state) html.write("<tr class=%s%d>\n" % (rowno % 2 == 0 and "odd" or "even", state)) html.write("<td class=\"state%d\">%s</td>\n" % (state, state_name)) html.write("<td><a href=\"logwatch.py?host=%s&file=%s\">%s</a></td>\n" % (htmllib.urlencode(host), htmllib.urlencode(file_display),htmllib.attrencode(file_display))) html.write("<td>%s</td><td>%s</td></tr>\n" % \ (form_datetime(last_log['datetime']), len(logs))) if rowno == 0: html.write('<tr><td colspan=4>'+_('No logs found for this host.')+'</td></tr>\n')
def add_wato_folder_to_url(url, wato_folder): if not wato_folder: return url elif '/' in url: return url # do not append wato_folder to non-Check_MK-urls elif '?' in url: return url + "&wato_folder=" + htmllib.urlencode(wato_folder) else: return url + "?wato_folder=" + htmllib.urlencode(wato_folder)
def paint_host_list(site, hosts): from htmllib import urlencode h = "" first = True for host in hosts: if first: first = False else: h += ", " link = "view.py?view_name=hoststatus&site=%s&host=%s" % (urlencode(site), urlencode(host)) if html.var("display_options"): link += "&display_options=%s" % html.var("display_options") h += "<a href=\"%s\">%s</a></div>" % (link, host) return "", h
def paint_host_list(site, hosts): from htmllib import urlencode h = "" first = True for host in hosts: if first: first = False else: h += ", " link = "view.py?view_name=hoststatus&site=%s&host=%s" % ( urlencode(site), urlencode(host)) if html.var("display_options"): link += "&display_options=%s" % html.var("display_options") h += "<a href=\"%s\">%s</a></div>" % (link, host) return "", h
def show_host_log_list(host): master_url = html.var('master_url', '') html.header(_("Logfiles of host %s") % host, stylesheets = stylesheets) html.begin_context_buttons() html.context_button(_("Services"), "%sview.py?view_name=host&site=&host=%s" % (master_url, htmllib.urlencode(host)), 'services') html.context_button(_("All logfiles"), "logwatch.py") html.context_button(_("Analyze Host Patterns"), "%swato.py?mode=pattern_editor&host=%s" % (master_url, htmllib.urlencode(host)), 'analyze') html.end_context_buttons() html.write("<table class=data>\n") list_logs(host, host_logs(host)) html.write("</table>\n") html.footer()
def do_log_ack(host, filename): file = form_file_to_int(filename) file_display = form_file_to_ext(file) html.header(_("Acknowledge logfile %s - %s") % (htmllib.attrencode(host), file_display), stylesheets = stylesheets) html.begin_context_buttons() html.context_button(_("All logfiles of Host"), "logwatch.py?host=%s" % htmllib.urlencode(host)) html.end_context_buttons() ack = html.var('ack') if not html.confirm(_("Do you really want to acknowledge the log file <tt>%s</tt> by <b>deleting</b> all stored messages?") % filename): html.footer() return if not (config.may("general.act") and may_see(host)): html.write("<h1 class=error>"+_('Permission denied')+"</h1>\n") html.write("<div class=error>" + _('You are not allowed to acknowledge the logs of the host %s</div>') % htmllib.attrencode(host)) html.footer() return # filter invalid values if ack != '1': raise MKUserError('ack', _('Invalid value for ack parameter.')) try: os.remove(defaults.logwatch_dir + '/' + host + '/' + file) message = '<b>'+_('%s: %s Acknowledged') % (htmllib.attrencode(host), htmllib.attrencode(file_display)) +'</b><br>' message += '<p>' message += _('The log messages from host "%s" in file "%s" have been acknowledged.') % \ (htmllib.attrencode(host), htmllib.attrencode(file_display)) message += '</p>' html.message(message) except Exception, e: html.show_error(_('The log file "%s" from host "%s" could not be deleted: %s.') % \ (htmllib.attrencode(file_display), htmllib.attrencode(host), e))
def show_file(host, filename): master_url = html.var('master_url', '') int_filename = form_file_to_int(filename) html.header(_("Logfiles of Host %s: %s") % (host, filename), stylesheets = stylesheets) html.begin_context_buttons() html.context_button(_("Services"), "%sview.py?view_name=host&site=&host=%s" % (master_url, htmllib.urlencode(host)), 'services') html.context_button(_("All Logfiles of Host"), html.makeuri([('file', '')])) html.context_button(_("All Logfiles"), html.makeuri([('host', ''), ('file', '')])) html.context_button(_("Analyze Patterns"), "%swato.py?mode=pattern_editor&host=%s&file=%s" % (master_url, htmllib.urlencode(host), htmllib.urlencode(filename)), 'analyze') if html.var('_hidecontext', 'no') == 'yes': hide_context_label = _('Show Context') hide_context_param = 'no' hide = True else: hide_context_label = _('Hide Context') hide_context_param = 'yes' hide = False logs = parse_file(host, int_filename, hide) if type(logs) != list: html.end_context_buttons() html.show_error(_("Unable to show logfile: <b>%s</b>") % logs) html.footer() return elif logs == []: html.end_context_buttons() html.message(_("This logfile contains no unacknowledged messages.")) html.footer() return ack_button(host, int_filename) html.context_button(hide_context_label, html.makeuri([('_hidecontext', hide_context_param)])) html.end_context_buttons() html.write("<div id=logwatch>\n") for log in logs: html.write('<div class="chunk">\n'); html.write('<table class="section">\n<tr>\n'); html.write('<td class="%s">%s</td>\n' % (form_level(log['level']), form_level(log['level']))); html.write('<td class="date">%s</td>\n' % (form_datetime(log['datetime']))); html.write('</tr>\n</table>\n'); for line in log['lines']: html.write('<p class="%s">' % line['class']) edit_url = master_url + "wato.py?" + htmllib.urlencode_vars([ ('mode', 'pattern_editor'), ('host', host), ('file', filename), ('match', line['line']), ]) html.icon_button(edit_url, _("Analyze this line"), "analyze") html.write('%s</p>\n' % (htmllib.attrencode(line['line']) )) html.write('</div>\n') html.write("</div>\n") html.footer()
def render_statistics(pie_id, what, table, filter): html.write("<div class=stats>") pie_diameter = 130 pie_left_aspect = 0.5 pie_right_aspect = 0.8 # Is the query restricted to a certain WATO-path? wato_folder = html.var("wato_folder") if wato_folder: # filter += "Filter: host_state = 0" filter += "Filter: host_filename ~ ^/wato/%s/\n" % wato_folder.replace( "\n", "") # Is the query restricted to a host contact group? host_contact_group = html.var("host_contact_group") if host_contact_group: filter += "Filter: host_contact_groups >= %s\n" % host_contact_group.replace( "\n", "") # Is the query restricted to a service contact group? service_contact_group = html.var("service_contact_group") if service_contact_group: filter += "Filter: service_contact_groups >= %s\n" % service_contact_group.replace( "\n", "") query = "GET %s\n" % what for entry in table: query += entry[3] query += filter result = html.live.query_summed_stats(query) pies = zip(table, result) total = sum([x[1] for x in pies]) html.write( '<canvas class=pie width=%d height=%d id="%s_stats" style="float: left"></canvas>' % (pie_diameter, pie_diameter, pie_id)) html.write('<img src="images/globe.png" class="globe">') html.write('<table class="hoststats%s" style="float:left">' % (len(pies) > 1 and " narrow" or "")) table_entries = pies while len(table_entries) < 6: table_entries = table_entries + [(("", "#95BBCD", "", ""), " ")] table_entries.append(((_("Total"), "", "all%s" % what, ""), total)) for (name, color, viewurl, query), count in table_entries: url = "view.py?view_name=" + viewurl + "&filled_in=filter&search=1&wato_folder=" \ + htmllib.urlencode(html.var("wato_folder", "")) if host_contact_group: url += '&opthost_contactgroup=' + host_contact_group if service_contact_group: url += '&optservice_contactgroup=' + service_contact_group html.write('<tr><th><a href="%s">%s</a></th>' % (url, name)) style = '' if color: style = ' style="background-color: %s"' % color html.write('<td class=color%s>' '</td><td><a href="%s">%s</a></td></tr>' % (style, url, count)) html.write("</table>") r = 0.0 pie_parts = [] if total > 0: # Count number of non-empty classes num_nonzero = 0 for info, value in pies: if value > 0: num_nonzero += 1 # Each non-zero class gets at least a view pixels of visible thickness. # We reserve that space right now. All computations are done in percent # of the radius. separator = 0.02 # 3% of radius remaining_separatorspace = num_nonzero * separator # space for separators remaining_radius = 1 - remaining_separatorspace # remaining space remaining_part = 1.0 # keep track of remaining part, 1.0 = 100% # Loop over classes, begin with most outer sphere. Inner spheres show # worse states and appear larger to the user (which is the reason we # are doing all this stuff in the first place) for (name, color, viewurl, q), value in pies[::1]: if value > 0 and remaining_part > 0: # skip empty classes # compute radius of this sphere *including all inner spheres!* The first # sphere always gets a radius of 1.0, of course. radius = remaining_separatorspace + remaining_radius * ( remaining_part**(1 / 3.0)) pie_parts.append('chart_pie("%s", %f, %f, %r, true);' % (pie_id, pie_right_aspect, radius, color)) pie_parts.append('chart_pie("%s", %f, %f, %r, false);' % (pie_id, pie_left_aspect, radius, color)) # compute relative part of this class part = float(value) / total # ranges from 0 to 1 remaining_part -= part remaining_separatorspace -= separator html.write("</div>") html.javascript( """ function chart_pie(pie_id, x_scale, radius, color, right_side) { var context = document.getElementById(pie_id + "_stats").getContext('2d'); if (!context) return; var pie_x = %(x)f; var pie_y = %(y)f; var pie_d = %(d)f; context.fillStyle = color; context.save(); context.translate(pie_x, pie_y); context.scale(x_scale, 1); context.beginPath(); if(right_side) context.arc(0, 0, (pie_d / 2) * radius, 1.5 * Math.PI, 0.5 * Math.PI, false); else context.arc(0, 0, (pie_d / 2) * radius, 0.5 * Math.PI, 1.5 * Math.PI, false); context.closePath(); context.fill(); context.restore(); context = null; } if (has_canvas_support()) { %(p)s } """ % { "x": pie_diameter / 2, "y": pie_diameter / 2, "d": pie_diameter, 'p': '\n'.join(pie_parts) })
def render_statistics(pie_id, what, table, filter): html.write("<div class=stats>") pie_diameter = 130 pie_left_aspect = 0.5 pie_right_aspect = 0.8 # Is the query restricted to a certain WATO-path? wato_folder = html.var("wato_folder") if wato_folder: # filter += "Filter: host_state = 0" filter += "Filter: host_filename ~ ^/wato/%s/\n" % wato_folder.replace("\n", "") query = "GET %s\n" % what for entry in table: query += entry[3] query += filter result = html.live.query_summed_stats(query) pies = zip(table, result) total = sum([x[1] for x in pies]) html.write('<canvas class=pie width=%d height=%d id="%s_stats" style="float: left"></canvas>' % (pie_diameter, pie_diameter, pie_id)) html.write('<img src="images/globe.png" class="globe">') html.write('<table class="hoststats%s" style="float:left">' % ( len(pies) > 1 and " narrow" or "")) table_entries = pies while len(table_entries) < 6: table_entries = table_entries + [ (("", "#95BBCD", "", ""), " ") ] table_entries.append(((_("Total"), "", "all%s" % what, ""), total)) for (name, color, viewurl, query), count in table_entries: url = "view.py?view_name=" + viewurl + "&filled_in=filter&search=1&wato_folder=" \ + htmllib.urlencode(html.var("wato_folder", "")) html.write('<tr><th><a href="%s">%s</a></th>' % (url, name)) style = '' if color: style = ' style="background-color: %s"' % color html.write('<td class=color%s>' '</td><td><a href="%s">%s</a></td></tr>' % (style, url, count)) html.write("</table>") r = 0.0 pie_parts = [] if total > 0: # Count number of non-empty classes num_nonzero = 0 for info, value in pies: if value > 0: num_nonzero += 1 # Each non-zero class gets at least a view pixels of visible thickness. # We reserve that space right now. All computations are done in percent # of the radius. separator = 0.02 # 3% of radius remaining_separatorspace = num_nonzero * separator # space for separators remaining_radius = 1 - remaining_separatorspace # remaining space remaining_part = 1.0 # keep track of remaining part, 1.0 = 100% # Loop over classes, begin with most outer sphere. Inner spheres show # worse states and appear larger to the user (which is the reason we # are doing all this stuff in the first place) for (name, color, viewurl, q), value in pies[::1]: if value > 0 and remaining_part > 0: # skip empty classes # compute radius of this sphere *including all inner spheres!* The first # sphere always gets a radius of 1.0, of course. radius = remaining_separatorspace + remaining_radius * (remaining_part ** (1/3.0)) pie_parts.append('chart_pie("%s", %f, %f, %r);' % (pie_id, pie_right_aspect, radius, color)) pie_parts.append('chart_pie("%s", -%f, %f, %r);' % (pie_id, pie_left_aspect, radius, color)) # compute relative part of this class part = float(value) / total # ranges from 0 to 1 remaining_part -= part remaining_separatorspace -= separator html.write("</div>") html.javascript(""" function chart_pie(pie_id, x_scale, radius, color) { var context = document.getElementById(pie_id + "_stats").getContext('2d'); if (!context) return; var pie_x = %(x)f; var pie_y = %(y)f; var pie_d = %(d)f; context.fillStyle = color; context.save(); context.translate(pie_x, pie_y); context.scale(x_scale, 1); context.beginPath(); context.moveTo(0, 0); context.arc(0, 0, (pie_d / 2) * radius, 1.5 * Math.PI, 0.5 * Math.PI, false); context.closePath(); context.fill(); context.restore(); context = null; } if (has_canvas_support()) { %(p)s } """ % { "x" : pie_diameter / 2, "y": pie_diameter/2, "d" : pie_diameter, 'p': '\n'.join(pie_parts) })