| /** |
| * 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.hama.bsp; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServlet; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.apache.hadoop.util.StringUtils; |
| |
| /** |
| * A servlet that is run by the Grooms to provide the task logs via http. |
| */ |
| public class TaskLogServlet extends HttpServlet { |
| private static final long serialVersionUID = -8127091686380253950L; |
| |
| private static boolean haveTaskLog(TaskAttemptID taskId, TaskLog.LogName type) { |
| File f = TaskLog.getTaskLogFile(taskId, type); |
| return f.canRead(); |
| } |
| |
| /** |
| * Construct the taskLogUrl |
| * |
| * @param taskTrackerHostName |
| * @param httpPort |
| * @param taskAttemptID |
| * @return the taskLogUrl |
| */ |
| public static String getTaskLogUrl(String taskTrackerHostName, |
| String httpPort, String taskAttemptID) { |
| return ("http://" + taskTrackerHostName + ":" + httpPort |
| + "/tasklog?taskid=" + taskAttemptID); |
| } |
| |
| /** |
| * Find the next quotable character in the given array. |
| * |
| * @param data the bytes to look in |
| * @param pOffset the first index to look in |
| * @param end the index after the last one to look in |
| * @return the index of the quotable character or end if none was found |
| */ |
| private static int findFirstQuotable(byte[] data, int pOffset, int end) { |
| int offset = pOffset; |
| while (offset < end) { |
| switch (data[offset]) { |
| case '<': |
| case '>': |
| case '&': |
| return offset; |
| default: |
| offset += 1; |
| } |
| } |
| return offset; |
| } |
| |
| private static void quotedWrite(OutputStream out, byte[] data, int pOffset, |
| int length) throws IOException { |
| int offset = pOffset; |
| int end = offset + length; |
| while (offset < end) { |
| int next = findFirstQuotable(data, offset, end); |
| out.write(data, offset, next - offset); |
| offset = next; |
| if (offset < end) { |
| switch (data[offset]) { |
| case '<': |
| out.write("<".getBytes()); |
| break; |
| case '>': |
| out.write(">".getBytes()); |
| break; |
| case '&': |
| out.write("&".getBytes()); |
| break; |
| default: |
| out.write(data[offset]); |
| break; |
| } |
| offset += 1; |
| } |
| } |
| } |
| |
| private static void printTaskLog(HttpServletResponse response, |
| OutputStream out, TaskAttemptID taskId, long start, long end, |
| boolean plainText, TaskLog.LogName filter, boolean isCleanup) |
| throws IOException { |
| if (!plainText) { |
| out.write(("<br><b><u>" + filter + " logs</u></b><br>\n" + "<pre>\n") |
| .getBytes()); |
| } |
| |
| try { |
| InputStream taskLogReader = new TaskLog.Reader(taskId, filter, start, end); |
| byte[] b = new byte[65536]; |
| int result; |
| while (true) { |
| result = taskLogReader.read(b); |
| if (result > 0) { |
| if (plainText) { |
| out.write(b, 0, result); |
| } else { |
| quotedWrite(out, b, 0, result); |
| } |
| } else { |
| break; |
| } |
| } |
| taskLogReader.close(); |
| if (!plainText) { |
| out.write("</pre></td></tr></table><hr><br>\n".getBytes()); |
| } |
| } catch (IOException ioe) { |
| if (filter == TaskLog.LogName.DEBUGOUT) { |
| if (!plainText) { |
| out.write("</pre><hr><br>\n".getBytes()); |
| } |
| // do nothing |
| } else { |
| response.sendError(HttpServletResponse.SC_GONE, "Failed to retrieve " |
| + filter + " log for task: " + taskId); |
| out.write(("TaskLogServlet exception:\n" |
| + StringUtils.stringifyException(ioe) + "\n").getBytes()); |
| } |
| } |
| } |
| |
| /** |
| * Get the logs via http. |
| */ |
| @Override |
| public void doGet(HttpServletRequest request, HttpServletResponse response) |
| throws ServletException, IOException { |
| long start = 0; |
| long end = -1; |
| boolean plainText = false; |
| TaskLog.LogName filter = null; |
| boolean isCleanup = false; |
| |
| String taskIdStr = request.getParameter("taskid"); |
| if (taskIdStr == null) { |
| response.sendError(HttpServletResponse.SC_BAD_REQUEST, |
| "Argument taskid is required"); |
| return; |
| } |
| TaskAttemptID taskId = TaskAttemptID.forName(taskIdStr); |
| String logFilter = request.getParameter("filter"); |
| if (logFilter != null) { |
| try { |
| filter = Enum.valueOf(TaskLog.LogName.class, logFilter.toUpperCase()); |
| } catch (IllegalArgumentException iae) { |
| response.sendError(HttpServletResponse.SC_BAD_REQUEST, |
| "Illegal value for filter: " + logFilter); |
| return; |
| } |
| } |
| |
| String sLogOff = request.getParameter("start"); |
| if (sLogOff != null) { |
| start = Long.valueOf(sLogOff); |
| } |
| |
| String sLogEnd = request.getParameter("end"); |
| if (sLogEnd != null) { |
| end = Long.valueOf(sLogEnd); |
| } |
| |
| String sPlainText = request.getParameter("plaintext"); |
| if (sPlainText != null) { |
| plainText = Boolean.valueOf(sPlainText); |
| } |
| |
| String sCleanup = request.getParameter("cleanup"); |
| if (sCleanup != null) { |
| isCleanup = Boolean.valueOf(sCleanup); |
| } |
| |
| OutputStream out = response.getOutputStream(); |
| if (!plainText) { |
| out.write(("<html>\n" + "<title>Task Logs: '" + taskId + "'</title>\n" |
| + "<body>\n" + "<h1>Task Logs: '" + taskId + "'</h1><br>\n") |
| .getBytes()); |
| |
| if (filter == null) { |
| printTaskLog(response, out, taskId, start, end, plainText, |
| TaskLog.LogName.STDOUT, isCleanup); |
| printTaskLog(response, out, taskId, start, end, plainText, |
| TaskLog.LogName.STDERR, isCleanup); |
| printTaskLog(response, out, taskId, start, end, plainText, |
| TaskLog.LogName.SYSLOG, isCleanup); |
| if (haveTaskLog(taskId, TaskLog.LogName.DEBUGOUT)) { |
| printTaskLog(response, out, taskId, start, end, plainText, |
| TaskLog.LogName.DEBUGOUT, isCleanup); |
| } |
| if (haveTaskLog(taskId, TaskLog.LogName.PROFILE)) { |
| printTaskLog(response, out, taskId, start, end, plainText, |
| TaskLog.LogName.PROFILE, isCleanup); |
| } |
| } else { |
| printTaskLog(response, out, taskId, start, end, plainText, filter, |
| isCleanup); |
| } |
| |
| out.write("</body></html>\n".getBytes()); |
| out.close(); |
| } else if (filter == null) { |
| response |
| .sendError( |
| HttpServletResponse.SC_BAD_REQUEST, |
| "You must supply a value for `filter' (STDOUT, STDERR, or SYSLOG) if you set plainText = true"); |
| } else { |
| printTaskLog(response, out, taskId, start, end, plainText, filter, |
| isCleanup); |
| } |
| } |
| } |