Browse Source

Merge -r 648748:648749 from trunk to 0.17 branch. Fixes HADOOP-3256.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/core/branches/branch-0.17@648750 13f79535-47bb-0310-9956-ffa450edef68
Devaraj Das 17 years ago
parent
commit
51b37f931e

+ 3 - 0
CHANGES.txt

@@ -576,6 +576,9 @@ Release 0.17.0 - Unreleased
     correctly read from the start of the split and not the beginning of the
     file. (cdouglas via acmurthy) 
 
+    HADOOP-3256. Encodes the job name used in the filename for history files.
+    (Arun Murthy via ddas)
+
 Release 0.16.3 - 2008-04-16
 
   BUG FIXES

+ 2 - 1
src/java/org/apache/hadoop/mapred/HistoryViewer.java

@@ -81,7 +81,8 @@ class HistoryViewer {
                               + historyLogDir.toString());
       }
       jobLogFile = jobFiles[0].toString();
-      String[] jobDetails = jobFiles[0].getName().split("_");
+      String[] jobDetails = 
+          JobInfo.decodeJobHistoryFileName(jobFiles[0].getName()).split("_");
       trackerHostName = jobDetails[0];
       trackerStartTime = jobDetails[1];
       jobId = jobDetails[2] + "_" + jobDetails[3] + "_" + jobDetails[4];

+ 87 - 10
src/java/org/apache/hadoop/mapred/JobHistory.java

@@ -26,6 +26,9 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -349,6 +352,75 @@ public class JobHistory {
                jobId + "_conf.xml";
     }
     
+    /**
+     * Helper function to encode the URL of the path of the job-history
+     * log file. 
+     * 
+     * @param logFile path of the job-history file
+     * @return URL encoded path
+     * @throws IOException
+     */
+    public static String encodeJobHistoryFilePath(String logFile)
+    throws IOException {
+      Path rawPath = new Path(logFile);
+      String encodedFileName = null;
+      try {
+        encodedFileName = URLEncoder.encode(rawPath.getName(), "UTF-8");
+      } catch (UnsupportedEncodingException uee) {
+        IOException ioe = new IOException();
+        ioe.initCause(uee);
+        ioe.setStackTrace(uee.getStackTrace());
+        throw ioe;
+      }
+      
+      Path encodedPath = new Path(rawPath.getParent(), encodedFileName);
+      return encodedPath.toString();
+    }
+    
+    /**
+     * Helper function to encode the URL of the filename of the job-history 
+     * log file.
+     * 
+     * @param logFileName file name of the job-history file
+     * @return URL encoded filename
+     * @throws IOException
+     */
+    public static String encodeJobHistoryFileName(String logFileName)
+    throws IOException {
+      String encodedFileName = null;
+      try {
+        encodedFileName = URLEncoder.encode(logFileName, "UTF-8");
+      } catch (UnsupportedEncodingException uee) {
+        IOException ioe = new IOException();
+        ioe.initCause(uee);
+        ioe.setStackTrace(uee.getStackTrace());
+        throw ioe;
+      }
+      return encodedFileName;
+    }
+    
+    /**
+     * Helper function to decode the URL of the filename of the job-history 
+     * log file.
+     * 
+     * @param logFileName file name of the job-history file
+     * @return URL decoded filename
+     * @throws IOException
+     */
+    public static String decodeJobHistoryFileName(String logFileName)
+    throws IOException {
+      String decodedFileName = null;
+      try {
+        decodedFileName = URLDecoder.decode(logFileName, "UTF-8");
+      } catch (UnsupportedEncodingException uee) {
+        IOException ioe = new IOException();
+        ioe.initCause(uee);
+        ioe.setStackTrace(uee.getStackTrace());
+        throw ioe;
+      }
+      return decodedFileName;
+    }
+    
     /**
      * Log job submitted event to history. Creates a new file in history 
      * for the job. if history file creation fails, it disables history 
@@ -357,9 +429,11 @@ public class JobHistory {
      * @param jobConf job conf of the job
      * @param jobConfPath path to job conf xml file in HDFS.
      * @param submitTime time when job tracker received the job
+     * @throws IOException
      */
     public static void logSubmitted(String jobId, JobConf jobConf, 
-                                    String jobConfPath, long submitTime) {
+                                    String jobConfPath, long submitTime) 
+    throws IOException {
       String jobName = jobConf.getJobName();
       String user = jobConf.getUser(); 
       FileSystem fs = null;
@@ -368,8 +442,10 @@ public class JobHistory {
 
       if (!disableHistory){
         // setup the history log file for this job
-        String logFileName = jobUniqueString +  
-                             "_" + user+ "_" + jobName;
+        String logFileName = 
+            encodeJobHistoryFileName(jobUniqueString +  "_" + user+ "_" + 
+                                     jobName);
+        
         if (logFileName.length() > MAX_FILENAME_SIZE) {
           logFileName = logFileName.substring(0, MAX_FILENAME_SIZE-1);
         }
@@ -382,16 +458,17 @@ public class JobHistory {
           userLogDir = null;
         }
         if (userLogDir != null) {
-          userLogDir = userLogDir + "/_logs/history";
+          userLogDir = userLogDir + Path.SEPARATOR + "_logs" + 
+                       Path.SEPARATOR + "history";
         }
 
-        String logFile = null;
-        String userLogFile = null;
+        Path logFile = null;
+        Path userLogFile = null;
         if (LOG_DIR != null ) {
-          logFile = LOG_DIR + File.separator + logFileName;
+          logFile = new Path(LOG_DIR, logFileName);
         }
         if (userLogDir != null ) {
-          userLogFile = userLogDir + File.separator + logFileName;
+          userLogFile = new Path(userLogDir, logFileName);
         }
 
         try{
@@ -402,7 +479,7 @@ public class JobHistory {
           if (LOG_DIR != null) {
             // create output stream for logging in hadoop.job.history.location
             fs = new Path(LOG_DIR).getFileSystem(jobConf);
-            out = fs.create(new Path(logFile), true, 4096);
+            out = fs.create(logFile, true, 4096);
             writer = new PrintWriter(out);
             writers.add(writer);
           }
@@ -410,7 +487,7 @@ public class JobHistory {
             // create output stream for logging 
             // in hadoop.job.history.user.location
             fs = new Path(userLogDir).getFileSystem(jobConf);
-            out = fs.create(new Path(userLogFile), true, 4096);
+            out = fs.create(userLogFile, true, 4096);
             writer = new PrintWriter(out);
             writers.add(writer);
           }

+ 12 - 11
src/webapps/job/analysejobhistory.jsp

@@ -19,6 +19,7 @@
 <%
   String jobid = request.getParameter("jobid");
   String logFile = request.getParameter("logFile");
+  String encodedLogFileName = JobHistory.JobInfo.encodeJobHistoryFilePath(logFile);
   String numTasks = request.getParameter("numTasks");
   int showTasks = 10 ; 
   if (numTasks != null) {
@@ -26,7 +27,7 @@
   }
   JobInfo job = (JobInfo)request.getSession().getAttribute("job");
 %>
-<h2>Hadoop Job <a href="jobdetailshistory.jsp?jobid=<%=jobid%>&&logFile=<%=logFile %>"><%=jobid %> </a></h2>
+<h2>Hadoop Job <a href="jobdetailshistory.jsp?jobid=<%=jobid%>&&logFile=<%=encodedLogFileName%>"><%=jobid %> </a></h2>
 <b>User : </b> <%=job.get(Keys.USER) %><br/> 
 <b>JobName : </b> <%=job.get(Keys.JOBNAME) %><br/> 
 <b>JobConf : </b> <%=job.get(Keys.JOBCONF) %><br/> 
@@ -100,7 +101,7 @@
 %>
 
 <h3>Time taken by best performing Map task 
-<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile%>&taskid=<%=minMap.get(Keys.TASKID)%>">
+<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>&taskid=<%=minMap.get(Keys.TASKID)%>">
 <%=minMap.get(Keys.TASKID) %></a> : <%=StringUtils.formatTimeDiff(minMap.getLong(Keys.FINISH_TIME), minMap.getLong(Keys.START_TIME) ) %></h3>
 <h3>Average time taken by Map tasks: 
 <%=StringUtils.formatTimeDiff(avgMapTime, 0) %></h3>
@@ -111,7 +112,7 @@
   for (int i=0;i<showTasks && i<mapTasks.length; i++) {
 %>
     <tr>
-    <td><a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile%>&taskid=<%=mapTasks[i].get(Keys.TASKID)%>">
+    <td><a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>&taskid=<%=mapTasks[i].get(Keys.TASKID)%>">
         <%=mapTasks[i].get(Keys.TASKID) %></a></td>
     <td><%=StringUtils.formatTimeDiff(mapTasks[i].getLong(Keys.FINISH_TIME), mapTasks[i].getLong(Keys.START_TIME)) %></td>
     </tr>
@@ -133,7 +134,7 @@
 %>
 
 <h3>The last Map task 
-<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile%>
+<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>
 &taskid=<%=lastMap.get(Keys.TASKID)%>"><%=lastMap.get(Keys.TASKID) %></a> 
 finished at (relative to the Job launch time): 
 <%=StringUtils.getFormattedTimeWithDiff(dateFormat, 
@@ -147,7 +148,7 @@ finished at (relative to the Job launch time):
   JobHistory.Task minShuffle = reduceTasks[reduceTasks.length-1] ;
 %>
 <h3>Time taken by best performing shuffle
-<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile%>
+<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>
 &taskid=<%=minShuffle.get(Keys.TASKID)%>"><%=minShuffle.get(Keys.TASKID)%></a> : 
 <%=StringUtils.formatTimeDiff(minShuffle.getLong(Keys.SHUFFLE_FINISHED), 
                               minShuffle.getLong(Keys.START_TIME) ) %></h3>
@@ -161,7 +162,7 @@ finished at (relative to the Job launch time):
 %>
     <tr>
     <td><a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=
-        <%=logFile%>&taskid=<%=reduceTasks[i].get(Keys.TASKID)%>">
+        <%=encodedLogFileName%>&taskid=<%=reduceTasks[i].get(Keys.TASKID)%>">
         <%=reduceTasks[i].get(Keys.TASKID) %></a></td>
     <td><%=
            StringUtils.formatTimeDiff(
@@ -187,7 +188,7 @@ finished at (relative to the Job launch time):
 %>
 
 <h3>The last Shuffle  
-<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile%>
+<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>
 &taskid=<%=lastShuffle.get(Keys.TASKID)%>"><%=lastShuffle.get(Keys.TASKID)%>
 </a> finished at (relative to the Job launch time): 
 <%=StringUtils.getFormattedTimeWithDiff(dateFormat,
@@ -209,7 +210,7 @@ finished at (relative to the Job launch time):
 %>
 <hr/>
 <h3>Time taken by best performing Reduce task : 
-<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile%>&taskid=<%=minReduce.get(Keys.TASKID)%>">
+<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>&taskid=<%=minReduce.get(Keys.TASKID)%>">
 <%=minReduce.get(Keys.TASKID) %></a> : 
 <%=StringUtils.formatTimeDiff(minReduce.getLong(Keys.FINISH_TIME),
     minReduce.getLong(Keys.SHUFFLE_FINISHED) ) %></h3>
@@ -223,7 +224,7 @@ finished at (relative to the Job launch time):
   for (int i=0;i<showTasks && i<reduceTasks.length; i++) {
 %>
     <tr>
-    <td><a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile%>&taskid=<%=reduceTasks[i].get(Keys.TASKID)%>">
+    <td><a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>&taskid=<%=reduceTasks[i].get(Keys.TASKID)%>">
         <%=reduceTasks[i].get(Keys.TASKID) %></a></td>
     <td><%=StringUtils.formatTimeDiff(
              reduceTasks[i].getLong(Keys.FINISH_TIME), 
@@ -239,11 +240,11 @@ finished at (relative to the Job launch time):
 %>
 
 <h3>The last Reduce task 
-<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile%>
+<a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>
 &taskid=<%=lastReduce.get(Keys.TASKID)%>"><%=lastReduce.get(Keys.TASKID)%>
 </a> finished at (relative to the Job launch time): 
 <%=StringUtils.getFormattedTimeWithDiff(dateFormat,
                               lastReduce.getLong(Keys.FINISH_TIME), 
                               job.getLong(Keys.LAUNCH_TIME) ) %></h3>
 </center>
-</body></html>
+</body></html>

+ 12 - 11
src/webapps/job/jobdetailshistory.jsp

@@ -17,6 +17,7 @@
 <%
     String jobid = request.getParameter("jobid");
     String logFile = request.getParameter("logFile");
+	String encodedLogFileName = JobHistory.JobInfo.encodeJobHistoryFilePath(logFile);
 	
     Path jobFile = new Path(logFile);
     String[] jobDetails = jobFile.getName().split("_");
@@ -87,7 +88,7 @@
       }
     }
 %>
-<b><a href="analysejobhistory.jsp?jobid=<%=jobid %>&logFile=<%=logFile %>">Analyse This Job</a></b> 
+<b><a href="analysejobhistory.jsp?jobid=<%=jobid %>&logFile=<%=encodedLogFileName%>">Analyse This Job</a></b> 
 <hr/>
 <center>
 <table border="2" cellpadding="5" cellspacing="2">
@@ -96,26 +97,26 @@
 </tr>
 <tr>
 <td>Map</td>
-    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=logFile %>&taskType=<%=Values.MAP.name() %>&status=all">
+    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=encodedLogFileName%>&taskType=<%=Values.MAP.name() %>&status=all">
         <%=totalMaps %></a></td>
-    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=logFile %>&taskType=<%=Values.MAP.name() %>&status=<%=Values.SUCCESS %>">
+    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=encodedLogFileName%>&taskType=<%=Values.MAP.name() %>&status=<%=Values.SUCCESS %>">
         <%=job.getInt(Keys.FINISHED_MAPS) %></a></td>
-    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=logFile %>&taskType=<%=Values.MAP.name() %>&status=<%=Values.FAILED %>">
+    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=encodedLogFileName%>&taskType=<%=Values.MAP.name() %>&status=<%=Values.FAILED %>">
         <%=numFailedMaps %></a></td>
-    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=logFile %>&taskType=<%=Values.MAP.name() %>&status=<%=Values.KILLED %>">
+    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=encodedLogFileName%>&taskType=<%=Values.MAP.name() %>&status=<%=Values.KILLED %>">
         <%=numKilledMaps %></a></td>
     <td><%=StringUtils.getFormattedTimeWithDiff(dateFormat, mapStarted, 0) %></td>
     <td><%=StringUtils.getFormattedTimeWithDiff(dateFormat, mapFinished, mapStarted) %></td>
 </tr>
 <tr>
 <td>Reduce</td>
-    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=logFile %>&taskType=<%=Values.REDUCE.name() %>&status=all">
+    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=encodedLogFileName%>&taskType=<%=Values.REDUCE.name() %>&status=all">
         <%=totalReduces%></a></td>
-    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=logFile %>&taskType=<%=Values.REDUCE.name() %>&status=<%=Values.SUCCESS %>">
+    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=encodedLogFileName%>&taskType=<%=Values.REDUCE.name() %>&status=<%=Values.SUCCESS %>">
         <%=job.getInt(Keys.FINISHED_REDUCES)%></a></td>
-    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=logFile %>&taskType=<%=Values.REDUCE.name() %>&status=<%=Values.FAILED %>">
+    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=encodedLogFileName%>&taskType=<%=Values.REDUCE.name() %>&status=<%=Values.FAILED %>">
         <%=numFailedReduces%></a></td>
-    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=logFile %>&taskType=<%=Values.REDUCE.name() %>&status=<%=Values.KILLED %>">
+    <td><a href="jobtaskshistory.jsp?jobid=<%=jobid %>&logFile=<%=encodedLogFileName%>&taskType=<%=Values.REDUCE.name() %>&status=<%=Values.KILLED %>">
         <%=numKilledReduces%></a></td>  
     <td><%=StringUtils.getFormattedTimeWithDiff(dateFormat, reduceStarted, 0) %></td>
     <td><%=StringUtils.getFormattedTimeWithDiff(dateFormat, reduceFinished, reduceStarted) %></td>
@@ -144,7 +145,7 @@
 <%
         for (String t : failedTasks) {
 %>
-          <a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile %>&taskid=<%=t %>"><%=t %></a>,&nbsp;
+          <a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>&taskid=<%=t %>"><%=t %></a>,&nbsp;
 <%		  
         }
 %>	
@@ -177,7 +178,7 @@
 <%
         for (String t : killedTasks) {
 %>
-          <a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=logFile %>&taskid=<%=t %>"><%=t %></a>,&nbsp;
+          <a href="taskdetailshistory.jsp?jobid=<%=jobid%>&logFile=<%=encodedLogFileName%>&taskid=<%=t %>"><%=t %></a>,&nbsp;
 <%		  
         }
 %>	

+ 24 - 6
src/webapps/job/jobhistory.jsp

@@ -46,8 +46,18 @@
     // sort the files on creation time.
     Arrays.sort(jobFiles, new Comparator<Path>() {
       public int compare(Path p1, Path p2) {
-        String[] split1 = p1.getName().split("_");
-        String[] split2 = p2.getName().split("_");
+        String dp1 = null;
+        String dp2 = null;
+        
+        try {
+          dp1 = JobHistory.JobInfo.decodeJobHistoryFileName(p1.getName());
+          dp2 = JobHistory.JobInfo.decodeJobHistoryFileName(p2.getName());
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+                
+        String[] split1 = dp1.split("_");
+        String[] split2 = dp2.split("_");
         
         // compare job tracker start time
         int res = new Date(Long.parseLong(split1[1])).compareTo(
@@ -72,17 +82,25 @@
               "<td>Job Id</td><td>Name</td><td>User</td>") ; 
     out.print("</tr>"); 
     for (Path jobFile: jobFiles) {
-      String[] jobDetails = jobFile.getName().split("_");
+      String decodedJobFileName = 
+          JobHistory.JobInfo.decodeJobHistoryFileName(jobFile.getName());
+
+      String[] jobDetails = decodedJobFileName.split("_");
       String trackerHostName = jobDetails[0];
       String trackerStartTime = jobDetails[1];
       String jobId = jobDetails[2] + "_" +jobDetails[3] + "_" + jobDetails[4] ;
       String user = jobDetails[5];
       String jobName = jobDetails[6];
+      
+      // Encode the logfile name again to cancel the decoding done by the browser
+      String encodedJobFileName = 
+          JobHistory.JobInfo.encodeJobHistoryFileName(jobFile.getName());
 %>
 <center>
 <%	
       printJob(trackerHostName, trackerStartTime, jobId,
-               jobName, user, jobFile.toString(), out) ; 
+               jobName, user, new Path(jobFile.getParent(), encodedJobFileName), 
+               out) ; 
 %>
 </center> 
 <%
@@ -91,13 +109,13 @@
 <%!
     private void printJob(String trackerHostName, String trackerid,
                           String jobId, String jobName,
-                          String user, String logFile, JspWriter out)
+                          String user, Path logFile, JspWriter out)
     throws IOException {
       out.print("<tr>"); 
       out.print("<td>" + trackerHostName + "</td>"); 
       out.print("<td>" + new Date(Long.parseLong(trackerid)) + "</td>"); 
       out.print("<td>" + "<a href=\"jobdetailshistory.jsp?jobid=" + jobId + 
-                "&logFile=" + logFile + "\">" + jobId + "</a></td>"); 
+                "&logFile=" + logFile.toString() + "\">" + jobId + "</a></td>"); 
       out.print("<td>" + jobName + "</td>"); 
       out.print("<td>" + user + "</td>"); 
       out.print("</tr>");

+ 5 - 4
src/webapps/job/jobtaskshistory.jsp

@@ -20,6 +20,7 @@
 <%	
   String jobid = request.getParameter("jobid");
   String logFile = request.getParameter("logFile");
+  String encodedLogFileName = JobHistory.JobInfo.encodeJobHistoryFilePath(logFile);
   String taskStatus = request.getParameter("status"); 
   String taskType = request.getParameter("taskType"); 
   
@@ -29,7 +30,7 @@
 %>
 <html>
 <body>
-<h2><%=taskStatus%> <%=taskType %> task list for <a href="jobdetailshistory.jsp?jobid=<%=jobid%>&&logFile=<%=logFile %>"><%=jobid %> </a></h2>
+<h2><%=taskStatus%> <%=taskType %> task list for <a href="jobdetailshistory.jsp?jobid=<%=jobid%>&&logFile=<%=encodedLogFileName%>"><%=jobid %> </a></h2>
 <center>
 <table border="2" cellpadding="5" cellspacing="2">
 <tr><td>Task Id</td><td>Start Time</td><td>Finish Time<br/></td><td>Error</td></tr>
@@ -40,7 +41,7 @@
       for (JobHistory.TaskAttempt taskAttempt : taskAttempts.values()) {
         if (taskStatus.equals(taskAttempt.get(Keys.TASK_STATUS)) || 
           taskStatus.equals("all")){
-          printTask(jobid, logFile, taskAttempt, out); 
+          printTask(jobid, encodedLogFileName, taskAttempt, out); 
         }
       }
     }
@@ -48,11 +49,11 @@
 %>
 </table>
 <%!
-  private void printTask(String jobid, String trackerId,
+  private void printTask(String jobid, String logFile,
     JobHistory.TaskAttempt attempt, JspWriter out) throws IOException{
     out.print("<tr>"); 
     out.print("<td>" + "<a href=\"taskdetailshistory.jsp?jobid=" + jobid + 
-          "&logFile="+ trackerId +"&taskid="+attempt.get(Keys.TASKID)+"\">" +
+          "&logFile="+ logFile +"&taskid="+attempt.get(Keys.TASKID)+"\">" +
           attempt.get(Keys.TASKID) + "</a></td>");
     out.print("<td>" + StringUtils.getFormattedTimeWithDiff(dateFormat, 
           attempt.getLong(Keys.START_TIME), 0 ) + "</td>");

+ 2 - 1
src/webapps/job/taskdetailshistory.jsp

@@ -17,6 +17,7 @@
 <%	
   String jobid = request.getParameter("jobid");
   String logFile = request.getParameter("logFile");
+  String encodedLogFileName = JobHistory.JobInfo.encodeJobHistoryFilePath(logFile);
   String taskid = request.getParameter("taskid"); 
   JobHistory.JobInfo job = (JobHistory.JobInfo)
                               request.getSession().getAttribute("job");
@@ -24,7 +25,7 @@
 %>
 <html>
 <body>
-<h2><%=taskid %> attempts for <a href="jobdetailshistory.jsp?jobid=<%=jobid%>&&logFile=<%=logFile %>"> <%=jobid %> </a></h2>
+<h2><%=taskid %> attempts for <a href="jobdetailshistory.jsp?jobid=<%=jobid%>&&logFile=<%=encodedLogFileName%>"> <%=jobid %> </a></h2>
 <center>
 <table border="2" cellpadding="5" cellspacing="2">
 <tr><td>Task Id</td><td>Start Time</td>