org.apache.accumulo.monitor.servlets.DefaultServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.accumulo.monitor.servlets.DefaultServlet.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.accumulo.monitor.servlets;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.accumulo.core.master.thrift.MasterMonitorInfo;
import org.apache.accumulo.core.util.Duration;
import org.apache.accumulo.core.util.Pair;
import org.apache.accumulo.monitor.Monitor;
import org.apache.accumulo.monitor.ZooKeeperStatus;
import org.apache.accumulo.monitor.ZooKeeperStatus.ZooKeeperState;
import org.apache.accumulo.monitor.util.celltypes.NumberType;
import org.apache.commons.httpclient.util.HttpURLConnection;

public class DefaultServlet extends BasicServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected String getTitle(HttpServletRequest req) {
        return "Accumulo Overview";
    }

    private void getResource(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        try {
            String path = req.getRequestURI();

            if (path.endsWith(".jpg"))
                resp.setContentType("image/jpeg");

            if (path.endsWith(".html"))
                resp.setContentType("text/html");

            path = path.substring(1);
            InputStream data = BasicServlet.class.getClassLoader().getResourceAsStream(path);
            ServletOutputStream out = resp.getOutputStream();
            try {
                if (data != null) {
                    byte[] buffer = new byte[1024];
                    int n;
                    while ((n = data.read(buffer)) > 0)
                        out.write(buffer, 0, n);
                } else {
                    out.write(("could not get resource " + path + "").getBytes(UTF_8));
                }
            } finally {
                if (data != null)
                    data.close();
            }
        } catch (Throwable t) {
            log.error(t, t);
            throw new IOException(t);
        }
    }

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Verify that this is the active Monitor instance
        if (!isActiveMonitor()) {
            resp.sendError(HttpURLConnection.HTTP_UNAVAILABLE, STANDBY_MONITOR_MESSAGE);
            return;
        }
        if (req.getRequestURI().startsWith("/web"))
            getResource(req, resp);
        else if (req.getRequestURI().startsWith("/monitor"))
            resp.sendRedirect("/master");
        else if (req.getRequestURI().startsWith("/errors"))
            resp.sendRedirect("/problems");
        else
            super.doGet(req, resp);
    }

    public static final int GRAPH_WIDTH = 450;
    public static final int GRAPH_HEIGHT = 150;

    private static void plotData(StringBuilder sb, String title, @SuppressWarnings("rawtypes") List data,
            boolean points) {
        plotData(sb, title, points, new ArrayList<String>(), data);
    }

    @SuppressWarnings("rawtypes")
    private static void plotData(StringBuilder sb, String title, boolean points, List<String> labels,
            List... series) {
        sb.append("<div class=\"plotHeading\">");
        sb.append(title);
        sb.append("</div>");
        sb.append("</br>");
        String id = "c" + title.hashCode();
        sb.append("<div id=\"" + id + "\" style=\"width:" + GRAPH_WIDTH + "px;height:" + GRAPH_HEIGHT
                + "px;\"></div>\n");

        sb.append("<script type=\"text/javascript\">\n");
        sb.append("$(function () {\n");

        for (int i = 0; i < series.length; i++) {

            @SuppressWarnings("unchecked")
            List<Pair<Long, ? extends Number>> data = series[i];
            sb.append("    var d" + i + " = [");

            String sep = "";
            for (Pair<Long, ? extends Number> point : data) {
                if (point.getSecond() == null)
                    continue;

                String y;
                if (point.getSecond() instanceof Double)
                    y = String.format("%1.2f", point.getSecond());
                else
                    y = point.getSecond().toString();

                sb.append(sep);
                sep = ",";
                sb.append("[" + utc2local(point.getFirst()) + "," + y + "]");
            }
            sb.append("    ];\n");
        }

        String opts = "lines: { show: true }";
        if (points)
            opts = "points: { show: true, radius: 1 }";

        sb.append("    $.plot($(\"#" + id + "\"),");
        String sep = "";

        String colors[] = new String[] { "red", "blue", "green", "black" };

        sb.append("[");
        for (int i = 0; i < series.length; i++) {
            sb.append(sep);
            sep = ",";
            sb.append("{ ");
            if (labels.size() > 0) {
                sb.append("label: \"" + labels.get(i) + "\", ");
            }
            sb.append("data: d" + i + ", " + opts + ", color:\"" + colors[i] + "\" }");
        }
        sb.append("], ");
        sb.append("{yaxis:{}, xaxis:{mode:\"time\",minTickSize: [1, \"minute\"],timeformat: \"%H:%M<br />"
                + getShortTZName() + "\", ticks:3}});");
        sb.append("   });\n");
        sb.append("</script>\n");
    }

    /**
     * Shows the current time zone (based on the current time) short name
     */
    private static String getShortTZName() {
        TimeZone tz = TimeZone.getDefault();
        return tz.getDisplayName(tz.inDaylightTime(new Date()), TimeZone.SHORT);
    }

    /**
     * Converts a unix timestamp in UTC to one that is relative to the local timezone
     */
    private static Long utc2local(Long utcMillis) {
        Calendar currentCalendar = Calendar.getInstance(); // default timezone
        currentCalendar.setTimeInMillis(utcMillis + currentCalendar.getTimeZone().getOffset(utcMillis));
        return currentCalendar.getTime().getTime();
    }

    @Override
    protected void pageBody(HttpServletRequest req, HttpServletResponse resp, StringBuilder sb) throws IOException {

        sb.append("<table class='noborder'>\n");
        sb.append("<tr>\n");

        sb.append("<td class='noborder'>\n");
        doAccumuloTable(sb);
        sb.append("</td>\n");

        sb.append("<td class='noborder'>\n");
        doZooKeeperTable(sb);
        sb.append("</td>\n");

        sb.append("</tr></table>\n");
        sb.append("<br />\n");

        sb.append("<p><table class=\"noborder\">\n");

        sb.append("<tr><td>\n");
        plotData(sb, "Ingest (Entries/s)", Monitor.getIngestRateOverTime(), false);
        sb.append("</td><td>\n");
        plotData(sb, "Scan (Entries/s)", false, Arrays.asList("Read", "Returned"), Monitor.getScanRateOverTime(),
                Monitor.getQueryRateOverTime());
        sb.append("</td></tr>\n");

        sb.append("<tr><td>\n");
        plotData(sb, "Ingest (MB/s)", Monitor.getIngestByteRateOverTime(), false);
        sb.append("</td><td>\n");
        plotData(sb, "Scan (MB/s)", Monitor.getQueryByteRateOverTime(), false);
        sb.append("</td></tr>\n");

        sb.append("<tr><td>\n");
        plotData(sb, "Load Average", Monitor.getLoadOverTime(), false);
        sb.append("</td><td>\n");
        plotData(sb, "Seeks", Monitor.getLookupsOverTime(), false);
        sb.append("</td></tr>\n");

        sb.append("<tr><td>\n");
        plotData(sb, "Minor Compactions", Monitor.getMinorCompactionsOverTime(), false);
        sb.append("</td><td>\n");
        plotData(sb, "Major Compactions", Monitor.getMajorCompactionsOverTime(), false);
        sb.append("</td></tr>\n");

        sb.append("<tr><td>\n");
        plotData(sb, "Index Cache Hit Rate", Monitor.getIndexCacheHitRateOverTime(), true);
        sb.append("</td><td>\n");
        plotData(sb, "Data Cache Hit Rate", Monitor.getDataCacheHitRateOverTime(), true);
        sb.append("</td></tr>\n");

        sb.append("</table>\n");
    }

    private void doAccumuloTable(StringBuilder sb) throws IOException {
        // Accumulo
        MasterMonitorInfo info = Monitor.getMmi();
        sb.append("<table>\n");
        sb.append("<tr><th colspan='2'><a href='/master'>Accumulo Master</a></th></tr>\n");
        if (info == null) {
            sb.append("<tr><td colspan='2'><span class='error'>Master is Down</span></td></tr>\n");
        } else {

            try {
                boolean highlight = false;
                tableRow(sb, (highlight = !highlight), "<a href='/tables'>Tables</a>",
                        NumberType.commas(Monitor.getTotalTables()));
                tableRow(sb, (highlight = !highlight), "<a href='/tservers'>Tablet&nbsp;Servers</a>",
                        NumberType.commas(info.tServerInfo.size(), 1, Long.MAX_VALUE));
                tableRow(sb, (highlight = !highlight), "<a href='/tservers'>Dead&nbsp;Tablet&nbsp;Servers</a>",
                        NumberType.commas(info.deadTabletServers.size(), 0, 0));
                tableRow(sb, (highlight = !highlight), "Tablets",
                        NumberType.commas(Monitor.getTotalTabletCount(), 1, Long.MAX_VALUE));
                tableRow(sb, (highlight = !highlight), "Entries", NumberType.commas(Monitor.getTotalEntries()));
                tableRow(sb, (highlight = !highlight), "Lookups", NumberType.commas(Monitor.getTotalLookups()));
                tableRow(sb, (highlight = !highlight), "Uptime",
                        Duration.format(System.currentTimeMillis() - Monitor.getStartTime()));
            } catch (Exception e) {
                log.debug(e, e);
            }
        }
        sb.append("</table>\n");
    }

    private void doZooKeeperTable(StringBuilder sb) throws IOException {
        // Zookeepers
        sb.append("<table>\n");
        sb.append("<tr><th colspan='3'>Zookeeper</th></tr>\n");
        sb.append("<tr><th>Server</th><th>Mode</th><th>Clients</th></tr>\n");

        boolean highlight = false;
        for (ZooKeeperState k : ZooKeeperStatus.getZooKeeperStatus()) {
            if (k.clients >= 0) {
                tableRow(sb, (highlight = !highlight), k.keeper, k.mode, k.clients);
            } else {
                tableRow(sb, false, k.keeper, "<span class='error'>Down</span>", "");
            }
        }
        sb.append("</table>\n");
    }

    public static void tableRow(StringBuilder sb, boolean highlight, Object... cells) {
        sb.append(highlight ? "<tr class='highlight'>" : "<tr>");
        for (int i = 0; i < cells.length; ++i) {
            Object cell = cells[i];
            String cellValue = cell == null ? "" : String.valueOf(cell).trim();
            sb.append("<td class='").append(i < cells.length - 1 ? "left" : "right").append("'>")
                    .append(cellValue.isEmpty() ? "-" : cellValue).append("</td>");
        }
        sb.append("</tr>\n");
    }
}