azkaban-aplcache
Changes
src/java/azkaban/executor/ExecutorManager.java 58(+44 -14)
src/web/css/azkaban.css 21(+20 -1)
src/web/js/azkaban.exflow.view.js 7(+7 -0)
src/web/js/azkaban.flow.view.js 2(+1 -1)
src/web/js/azkaban.joblog.view.js 51(+51 -0)
Details
src/java/azkaban/executor/ExecutorManager.java 58(+44 -14)
diff --git a/src/java/azkaban/executor/ExecutorManager.java b/src/java/azkaban/executor/ExecutorManager.java
index 4419e70..993f3c5 100644
--- a/src/java/azkaban/executor/ExecutorManager.java
+++ b/src/java/azkaban/executor/ExecutorManager.java
@@ -455,19 +455,9 @@ public class ExecutorManager {
flow.setSubmitted(true);
}
- public long getExecutableFlowLog(ExecutableFlow flow, StringBuffer buffer, long startChar, long maxSize) throws ExecutorManagerException {
- String path = flow.getExecutionPath();
- File execPath = new File(path);
- if (!execPath.exists()) {
- logger.error("Execution dir for " + flow + " doesn't exist.");
- return -1;
- }
-
- String logFileName = "_flow." + flow.getExecutionId() + ".log";
- File flowLogFile = new File(execPath, logFileName);
-
- if (!flowLogFile.exists()) {
- logger.error("Execution log for " + flowLogFile + " doesn't exist.");
+ private long readLog(File logFile, StringBuffer buffer, long startChar, long maxSize) {
+ if (!logFile.exists()) {
+ logger.error("Execution log for " + logFile + " doesn't exist.");
return -1;
}
@@ -476,7 +466,7 @@ public class ExecutorManager {
char[] charBuffer = new char[LOG_BUFFER_READ_SIZE];
try {
- fileReader = new FileReader(flowLogFile);
+ fileReader = new FileReader(logFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
@@ -514,6 +504,46 @@ public class ExecutorManager {
return charPosition;
}
+ public long getExecutionJobLog(ExecutableFlow flow, String jobid, StringBuffer buffer, long startChar, long maxSize) throws ExecutorManagerException {
+ String path = flow.getExecutionPath();
+ File execPath = new File(path);
+ if (!execPath.exists()) {
+ logger.error("Execution dir for " + flow + " doesn't exist.");
+ return -1;
+ }
+
+ String logFileName = "_job." + flow.getExecutionId() + "." + jobid + ".log";
+ File logFile = new File(execPath, logFileName);
+
+ if (!logFile.exists()) {
+ logger.error("Execution log for " + logFile + " doesn't exist.");
+ return -1;
+ }
+
+ long charPosition = readLog(logFile, buffer, startChar, maxSize);
+ return charPosition;
+ }
+
+ public long getExecutableFlowLog(ExecutableFlow flow, StringBuffer buffer, long startChar, long maxSize) throws ExecutorManagerException {
+ String path = flow.getExecutionPath();
+ File execPath = new File(path);
+ if (!execPath.exists()) {
+ logger.error("Execution dir for " + flow + " doesn't exist.");
+ return -1;
+ }
+
+ String logFileName = "_flow." + flow.getExecutionId() + ".log";
+ File flowLogFile = new File(execPath, logFileName);
+
+ if (!flowLogFile.exists()) {
+ logger.error("Execution log for " + flowLogFile + " doesn't exist.");
+ return -1;
+ }
+
+ long charPosition = readLog(flowLogFile, buffer, startChar, maxSize);
+ return charPosition;
+ }
+
public void cleanupAll(ExecutableFlow exflow) throws ExecutorManagerException{
String path = exflow.getExecutionPath();
File executionPath = new File(path);
diff --git a/src/java/azkaban/webapp/AzkabanWebServer.java b/src/java/azkaban/webapp/AzkabanWebServer.java
index 173379c..79a14fa 100644
--- a/src/java/azkaban/webapp/AzkabanWebServer.java
+++ b/src/java/azkaban/webapp/AzkabanWebServer.java
@@ -43,8 +43,7 @@ import azkaban.user.XmlUserManager;
import azkaban.utils.Props;
import azkaban.utils.Utils;
import azkaban.webapp.servlet.AzkabanServletContextListener;
-import azkaban.webapp.servlet.ExecutionServlet;
-import azkaban.webapp.servlet.FlowExecutorServlet;
+import azkaban.webapp.servlet.ExecutorServlet;
import azkaban.webapp.servlet.HistoryServlet;
import azkaban.webapp.servlet.IndexServlet;
import azkaban.webapp.servlet.ProjectManagerServlet;
@@ -347,8 +346,7 @@ public class AzkabanWebServer {
root.addServlet(staticServlet, "/favicon.ico");
root.addServlet(new ServletHolder(new ProjectManagerServlet()),"/manager");
- root.addServlet(new ServletHolder(new FlowExecutorServlet()),"/executor");
- root.addServlet(new ServletHolder(new ExecutionServlet()),"/executions");
+ root.addServlet(new ServletHolder(new ExecutorServlet()),"/executor");
root.addServlet(new ServletHolder(new HistoryServlet()), "/history");
root.setAttribute(AzkabanServletContextListener.AZKABAN_SERVLET_CONTEXT_KEY, app);
diff --git a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
index 01c69b7..8fe3bf0 100644
--- a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
@@ -44,7 +44,7 @@
<div id="all-jobs-content">
<div class="section-hd flow-header">
- <h2><a href="${context}/executions?execid=${execid}">Flow Execution <span>$execid</span></a></h2>
+ <h2><a href="${context}/executor?execid=${execid}">Flow Execution <span>$execid</span></a></h2>
<div class="section-sub-hd">
<h4><a href="${context}/manager?project=${projectName}">Project <span>$projectName</span></a></h4>
<h4 class="separator">></h4>
@@ -58,7 +58,7 @@
<li class="lidivider">|</li>
<li><a id="jobslistViewLink" href="#jobslist">Job List</a></li>
<li class="lidivider">|</li>
- <li><a id="flowLogViewLink" href="#log">Log</a></li>
+ <li><a id="flowLogViewLink" href="#log">Flow Log</a></li>
</ul>
<ul id="actionsBtns" class="buttons">
<li><div id="pausebtn" class="btn2">Pause</div></li>
@@ -100,7 +100,7 @@
</tbody>
</table>
</div>
- <div id="flowLogView">
+ <div id="flowLogView" class="logView">
<div class="logHeader"><div class="logButtonRow"><div id="updateLogBtn" class="btn7">Load More</div></div></div>
<div class="logViewer">
<pre id="logSection" class="log"></pre>
diff --git a/src/java/azkaban/webapp/servlet/velocity/executionspage.vm b/src/java/azkaban/webapp/servlet/velocity/executionspage.vm
index 3dd9c6f..2c04c8b 100644
--- a/src/java/azkaban/webapp/servlet/velocity/executionspage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/executionspage.vm
@@ -50,7 +50,7 @@
#foreach($flow in $runningFlows)
<tr class="row" >
<td class="tb-name">
- <a href="${context}/executions?execid=${flow.executionId}">$utils.extractNumericalId(${flow.executionId})</a>
+ <a href="${context}/executor?execid=${flow.executionId}">$utils.extractNumericalId(${flow.executionId})</a>
</td>
<td><a href="${context}/manager?project=${flow.projectId}&flow=${flow.flowId}">${flow.flowId}</a></td>
<td>
@@ -91,7 +91,7 @@
#foreach($flow in $recentlyFinished)
<tr class="row" >
<td class="tb-name">
- <a href="${context}/executions?execid=${flow.executionId}">$utils.extractNumericalId(${flow.executionId})</a>
+ <a href="${context}/executor?execid=${flow.executionId}">$utils.extractNumericalId(${flow.executionId})</a>
</td>
<td><a href="${context}/manager?project=${flow.projectId}&flow=${flow.flowId}">${flow.flowId}</a></td>
<td>
diff --git a/src/java/azkaban/webapp/servlet/velocity/historypage.vm b/src/java/azkaban/webapp/servlet/velocity/historypage.vm
index 7204cee..1a94a39 100644
--- a/src/java/azkaban/webapp/servlet/velocity/historypage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/historypage.vm
@@ -54,7 +54,7 @@
#foreach($flow in $flowHistory)
<tr class="row" >
<td class="tb-name">
- <a href="${context}/executions?execid=${flow.execId}">$utils.extractNumericalId(${flow.execId})</a>
+ <a href="${context}/executor?execid=${flow.execId}">$utils.extractNumericalId(${flow.execId})</a>
</td>
<td class="tb-name">
<a href="${context}/manager?project=${flow.projectId}&flow=${flow.flowId}">${flow.flowId}</a>
diff --git a/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm b/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm
new file mode 100644
index 0000000..dd9f233
--- /dev/null
+++ b/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+ <head>
+#parse( "azkaban/webapp/servlet/velocity/style.vm" )
+ <script type="text/javascript" src="${context}/js/jquery/jquery.js"></script>
+ <script type="text/javascript" src="${context}/js/namespace.js"></script>
+ <script type="text/javascript" src="${context}/js/underscore-1.2.1-min.js"></script>
+ <script type="text/javascript" src="${context}/js/backbone-0.5.3-min.js"></script>
+ <script type="text/javascript" src="${context}/js/jquery.simplemodal.js"></script>
+ <script type="text/javascript" src="${context}/js/azkaban.ajax.utils.js"></script>
+ <script type="text/javascript" src="${context}/js/azkaban.nav.js"></script>
+ <script type="text/javascript" src="${context}/js/azkaban.joblog.view.js"></script>
+ <script type="text/javascript">
+ var contextURL = "${context}";
+ var currentTime = ${currentTime};
+ var timezone = "${timezone}";
+ var errorMessage = ${error_message};
+ var successMessage = ${success_message};
+
+ var projectName = "${projectName}";
+ var flowName = "${flowid}";
+ var execId = "${execid}";
+ var jobId = "${jobid}";
+ </script>
+ </head>
+ <body>
+ #set($current_page="executing")
+#parse( "azkaban/webapp/servlet/velocity/nav.vm" )
+ <div class="content">
+#if($errorMsg)
+ <div class="box-error-message">$errorMsg</div>
+#else
+#if($error_message != "null")
+ <div class="box-error-message">$error_message</div>
+#elseif($success_message != "null")
+ <div class="box-success-message">$success_message</div>
+#end
+
+ <div id="all-jobs-content">
+ <div class="section-hd flow-header">
+ <h2><a href="${context}/executor?execid=${execid}&job=${jobid}">Job Execution<span>$jobid</span></a></h2>
+ <div class="section-sub-hd">
+ <h4><a href="${context}/manager?project=${projectName}">Project <span>$projectName</span></a></h4>
+ <h4 class="separator">></h4>
+ <h4><a href="${context}/executor?execid=${execid}#jobslist">Execution <span>$execid</span></a></h4>
+ <h4 class="separator">></h4>
+ <h4><a href="${context}/manager?project=${projectName}&flow=${flowid}">Flow <span>$flowid</span></a></h4>
+ <h4 class="separator">></h4>
+ <h4><a href="${context}/manager?project=${projectName}&flow=${flowid}&job=$jobid">Job <span>$jobid</span></a></h4>
+ </div>
+ </div>
+ </div>
+
+ <div id="headertabs" class="headertabs">
+ <ul>
+ <li><a id="logViewLink" href="#log">Log</a></li>
+ </ul>
+ </div>
+
+ <div id="jobLogView" class="logView">
+ <div class="logHeader"><div class="logButtonRow"><div id="updateLogBtn" class="btn7">Load More</div></div></div>
+ <div class="logViewer">
+ <pre id="logSection" class="log"></pre>
+ </div>
+ </div>
+#end
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/src/java/azkaban/webapp/servlet/velocity/nav.vm b/src/java/azkaban/webapp/servlet/velocity/nav.vm
index 7999a7f..2517d8f 100644
--- a/src/java/azkaban/webapp/servlet/velocity/nav.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/nav.vm
@@ -9,7 +9,7 @@
<ul id="nav" class="nav">
<li id="all-jobs-tab" #if($current_page == 'all')class="selected"#end onClick="navMenuClick('$!context/')"><a href="$!context/">Projects</a></li>
<li id="scheduled-jobs-tab" #if($current_page == 'schedule')class="scheduled"#end onClick="navMenuClick('$!context/schedule')"><a href="$!context/schedule">Scheduled</a></li>
- <li id="executing-jobs-tab" #if($current_page == 'executing')class="selected"#end onClick="navMenuClick('$!context/executions')"><a href="$!context/executions">Executing</a></li>
+ <li id="executing-jobs-tab" #if($current_page == 'executing')class="selected"#end onClick="navMenuClick('$!context/executor')"><a href="$!context/executor">Executing</a></li>
<li id="history-jobs-tab" #if($current_page == 'history')class="selected"#end onClick="navMenuClick('$!context/history')"><a href="$!context/history">History</a></li>
<li><a href="$!context/fs">HDFS</a></li>
</ul>
src/web/css/azkaban.css 21(+20 -1)
diff --git a/src/web/css/azkaban.css b/src/web/css/azkaban.css
index fa0c773..449e05d 100644
--- a/src/web/css/azkaban.css
+++ b/src/web/css/azkaban.css
@@ -1166,7 +1166,7 @@ tr:hover td {
background: #E0E0E0;
}
-#flowLogView {
+.logView {
position: absolute;
top: 210px;
bottom: 5px;
@@ -1175,6 +1175,16 @@ tr:hover td {
background: #E0E0E0;
}
+#flowLogView {
+ top: 210px;
+ bottom: 5px;
+}
+
+#jobLogView {
+ top: 210px;
+ bottom: 5px;
+}
+
.logHeader {
height: 30px;
margin: 0px;
@@ -1197,6 +1207,15 @@ tr:hover td {
overflow:scroll;
}
+.logLink {
+ text-align: center;
+}
+
+.logLink a {
+ text-decoration: underline;
+ margin: 0px;
+}
+
.log {
padding-left: 15px;
font-family: "courier";
src/web/js/azkaban.exflow.view.js 7(+7 -0)
diff --git a/src/web/js/azkaban.exflow.view.js b/src/web/js/azkaban.exflow.view.js
index 79ec6a4..8dbe54c 100644
--- a/src/web/js/azkaban.exflow.view.js
+++ b/src/web/js/azkaban.exflow.view.js
@@ -823,6 +823,13 @@ azkaban.ExecutionListView = Backbone.View.extend({
$(status).attr("id", node.id + "-status-div");
tdStatus.appendChild(status);
+ var logURL = contextURL + "/executor?execid=" + execId + "&flow=" + flowName + "&job=" + node.id;
+ var a = document.createElement("a");
+ $(a).attr("href", logURL);
+ $(a).text("Log");
+ $(tdLog).addClass("logLink");
+ $(tdLog).append(a);
+
executingBody.append(tr);
}
});
src/web/js/azkaban.flow.view.js 2(+1 -1)
diff --git a/src/web/js/azkaban.flow.view.js b/src/web/js/azkaban.flow.view.js
index 868d8d3..73c244f 100644
--- a/src/web/js/azkaban.flow.view.js
+++ b/src/web/js/azkaban.flow.view.js
@@ -641,7 +641,7 @@ azkaban.ExecutionsView = Backbone.View.extend({
var tdId = document.createElement("td");
var execA = document.createElement("a");
- $(execA).attr("href", contextURL + "/executions?execid=" + executions[i].execId);
+ $(execA).attr("href", contextURL + "/executor?execid=" + executions[i].execId);
$(execA).text(executions[i].execId);
tdId.appendChild(execA);
row.appendChild(tdId);
src/web/js/azkaban.joblog.view.js 51(+51 -0)
diff --git a/src/web/js/azkaban.joblog.view.js b/src/web/js/azkaban.joblog.view.js
new file mode 100644
index 0000000..1150736
--- /dev/null
+++ b/src/web/js/azkaban.joblog.view.js
@@ -0,0 +1,51 @@
+$.namespace('azkaban');
+
+var logModel;
+azkaban.LogModel = Backbone.Model.extend({});
+
+var jobLogView;
+azkaban.JobLogView = Backbone.View.extend({
+ events: {
+ "click #updateLogBtn" : "handleUpdate"
+ },
+ initialize: function(settings) {
+ this.model.set({"current": 0});
+ this.handleUpdate();
+ },
+ handleUpdate: function(evt) {
+ var current = this.model.get("current");
+ var requestURL = contextURL + "/executor";
+ var model = this.model;
+
+ ajaxCall(
+ requestURL,
+ {"execid": execId, "job": jobId, "ajax":"fetchExecJobLogs", "current": current, "max": 100000},
+ function(data) {
+ console.log("fetchLogs");
+ if (data.error) {
+ showDialog("Error", data.error);
+ }
+ else {
+ var log = $("#logSection").text();
+ if (!log) {
+ log = data.log;
+ }
+ else {
+ log += data.log;
+ }
+
+ current = data.current;
+ $("#logSection").text(log);
+ model.set({"current": current, "log": log});
+ }
+ }
+ );
+ }
+});
+
+$(function() {
+ var selected;
+
+ logModel = new azkaban.LogModel();
+ jobLogView = new azkaban.JobLogView({el:$('#jobLogView'), model: logModel});
+});