azkaban-uncached
Changes
src/web/css/azkaban.css 2(+1 -1)
src/web/js/azkaban.exflow.view.js 25(+7 -18)
src/web/js/azkaban.jobdetails.view.js 299(+299 -0)
Details
diff --git a/src/java/azkaban/webapp/servlet/ExecutorServlet.java b/src/java/azkaban/webapp/servlet/ExecutorServlet.java
index 7898864..1ba4029 100644
--- a/src/java/azkaban/webapp/servlet/ExecutorServlet.java
+++ b/src/java/azkaban/webapp/servlet/ExecutorServlet.java
@@ -71,11 +71,8 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
handleAJAXAction(req, resp, session);
}
else if (hasParam(req, "execid")) {
- if (hasParam(req, "summary")) {
- handleExecutionJobSummaryPage(req, resp, session);
- }
- else if (hasParam(req, "job")) {
- handleExecutionJobLogPage(req, resp, session);
+ if (hasParam(req, "job")) {
+ handleExecutionJobDetailsPage(req, resp, session);
}
else {
handleExecutionFlowPage(req, resp, session);
@@ -86,45 +83,8 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
}
}
- private void handleExecutionJobSummaryPage(HttpServletRequest req, HttpServletResponse resp, Session session) throws ServletException, IOException {
- Page page = newPage(req, resp, session, "azkaban/webapp/servlet/velocity/jobsummarypage.vm");
- User user = session.getUser();
- int execId = getIntParam(req, "execid");
- String jobId = getParam(req, "job");
- int attempt = getIntParam(req, "attempt", 0);
- page.add("execid", execId);
- page.add("jobid", jobId);
- page.add("attempt", attempt);
-
- ExecutableFlow flow = null;
- try {
- flow = executorManager.getExecutableFlow(execId);
- if (flow == null) {
- page.add("errorMsg", "Error loading executing flow " + execId + ": not found.");
- page.render();
- return;
- }
- } catch (ExecutorManagerException e) {
- page.add("errorMsg", "Error loading executing flow: " + e.getMessage());
- page.render();
- return;
- }
-
- int projectId = flow.getProjectId();
- Project project = getProjectPageByPermission(page, projectId, user, Type.READ);
- if (project == null) {
- page.render();
- return;
- }
-
- page.add("projectName", project.getName());
- page.add("flowid", flow.getFlowId());
-
- page.render();
- }
-
- private void handleExecutionJobLogPage(HttpServletRequest req, HttpServletResponse resp, Session session) throws ServletException, IOException {
- Page page = newPage(req, resp, session, "azkaban/webapp/servlet/velocity/joblogpage.vm");
+ private void handleExecutionJobDetailsPage(HttpServletRequest req, HttpServletResponse resp, Session session) throws ServletException, IOException {
+ Page page = newPage(req, resp, session, "azkaban/webapp/servlet/velocity/jobdetailspage.vm");
User user = session.getUser();
int execId = getIntParam(req, "execid");
String jobId = getParam(req, "job");
diff --git a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
index 33e4c90..3e4af3f 100644
--- a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
@@ -53,7 +53,7 @@
#set($current_page="all")
#set($show_schedule="false")
-#parse( "azkaban/webapp/servlet/velocity/nav.vm" )
+#parse("azkaban/webapp/servlet/velocity/nav.vm")
<div class="messaging"><p id="messageClose">X</p><p id="message"></p></div>
<div class="content">
#if($errorMsg)
@@ -119,8 +119,7 @@
<th class="date">End Time</th>
<th class="elapse">Elapsed</th>
<th class="status">Status</th>
- <th class="logs">Logs</th>
- <th class="summary">Summary</th>
+ <th class="details">Details</th>
</tr>
</thead>
<tbody id="executableBody">
@@ -147,7 +146,7 @@
</table>
</div>
-#parse( "azkaban/webapp/servlet/velocity/flowexecutionpanel.vm" )
+#parse("azkaban/webapp/servlet/velocity/flowexecutionpanel.vm")
#end
</div>
src/web/css/azkaban.css 2(+1 -1)
diff --git a/src/web/css/azkaban.css b/src/web/css/azkaban.css
index aadf527..41e0af3 100644
--- a/src/web/css/azkaban.css
+++ b/src/web/css/azkaban.css
@@ -2422,7 +2422,7 @@ span.sublabel {
width: 100px;
}
-.executionInfo table th.logs {
+.executionInfo table th.details {
width: 10px;
}
src/web/js/azkaban.exflow.view.js 25(+7 -18)
diff --git a/src/web/js/azkaban.exflow.view.js b/src/web/js/azkaban.exflow.view.js
index 955b648..fce01a8 100644
--- a/src/web/js/azkaban.exflow.view.js
+++ b/src/web/js/azkaban.exflow.view.js
@@ -101,8 +101,8 @@ azkaban.FlowTabView= Backbone.View.extend({
$("#resumebtn").hide();
$("#retrybtn").hide();
- this.model.bind('change:graph', this.handleFlowStatusChange, this);
- this.model.bind('change:update', this.handleFlowStatusChange, this);
+ this.model.bind('change:graph', this.handleFlowStatusChange, this);
+ this.model.bind('change:update', this.handleFlowStatusChange, this);
var selectedView = settings.selectedView;
if (selectedView == "jobslist") {
@@ -466,8 +466,7 @@ azkaban.ExecutionListView = Backbone.View.extend({
var tdEnd = document.createElement("td");
var tdElapse = document.createElement("td");
var tdStatus = document.createElement("td");
- var tdLog = document.createElement("td");
- var tdSummary = document.createElement("td");
+ var tdDetails = document.createElement("td");
$(tr).append(tdName);
$(tr).append(tdTimeline);
@@ -475,8 +474,7 @@ azkaban.ExecutionListView = Backbone.View.extend({
$(tr).append(tdEnd);
$(tr).append(tdElapse);
$(tr).append(tdStatus);
- $(tr).append(tdLog);
- $(tr).append(tdSummary);
+ $(tr).append(tdDetails);
$(tr).attr("id", node.id + "-row");
$(tdTimeline).attr("id", node.id + "-timeline");
$(tdStart).attr("id", node.id + "-start");
@@ -515,19 +513,10 @@ azkaban.ExecutionListView = Backbone.View.extend({
var a = document.createElement("a");
$(a).attr("href", logURL);
$(a).attr("id", node.id + "-log-link");
- $(a).text("Log");
- $(tdLog).addClass("logLink");
- $(tdLog).append(a);
+ $(a).text("Details");
+ $(tdDetails).addClass("details");
+ $(tdDetails).append(a);
- var summaryURL = contextURL + "/executor?execid=" + execId +
- "&job=" + node.id + "&summary";
- a = document.createElement("a");
- $(a).attr("href", summaryURL);
- $(a).attr("id", node.id + "-summary-link");
- $(a).text("Summary");
- $(tdSummary).addClass("logSummary");
- $(tdSummary).append(a);
-
executingBody.append(tr);
}
});
src/web/js/azkaban.jobdetails.view.js 299(+299 -0)
diff --git a/src/web/js/azkaban.jobdetails.view.js b/src/web/js/azkaban.jobdetails.view.js
new file mode 100644
index 0000000..aba399c
--- /dev/null
+++ b/src/web/js/azkaban.jobdetails.view.js
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2012 LinkedIn Corp.
+ *
+ * Licensed 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.
+ */
+
+$.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({"offset": 0});
+ this.handleUpdate();
+ },
+ handleUpdate: function(evt) {
+ var requestURL = contextURL + "/executor";
+ var model = this.model;
+ var finished = false;
+
+ var date = new Date();
+ var startTime = date.getTime();
+
+ while (!finished) {
+ var offset = this.model.get("offset");
+ var requestData = {
+ "execid": execId,
+ "jobId": jobId,
+ "ajax":"fetchExecJobLogs",
+ "offset": offset,
+ "length": 50000,
+ "attempt": attempt
+ };
+
+ var successHandler = function(data) {
+ console.log("fetchLogs");
+ if (data.error) {
+ console.log(data.error);
+ finished = true;
+ }
+ else if (data.length == 0) {
+ finished = true;
+ }
+ else {
+ var date = new Date();
+ var endTime = date.getTime();
+ if ((endTime - startTime) > 10000) {
+ finished = true;
+ showDialog("Alert","The log is taking a long time to finish loading. Azkaban has stopped loading them. Please click Refresh to restart the load.");
+ }
+
+ var re = /(https?:\/\/(([-\w\.]+)+(:\d+)?(\/([\w/_\.]*(\?\S+)?)?)?))/g;
+ var log = $("#logSection").text();
+ if (!log) {
+ log = data.data;
+ }
+ else {
+ log += data.data;
+ }
+
+ var newOffset = data.offset + data.length;
+ $("#logSection").text(log);
+ log = $("#logSection").html();
+ log = log.replace(re, "<a href=\"$1\" title=\"\">$1</a>");
+ $("#logSection").html(log);
+
+ model.set({"offset": newOffset, "log": log});
+ $(".logViewer").scrollTop(9999);
+ }
+ }
+
+ $.ajax({
+ url: requestURL,
+ type: "get",
+ async: false,
+ data: requestData,
+ dataType: "json",
+ error: function(data) {
+ console.log(data);
+ finished = true;
+ },
+ success: successHandler
+ });
+ }
+ }
+});
+
+var summaryModel;
+azkaban.SummaryModel = Backbone.Model.extend({});
+
+var jobSummaryView;
+azkaban.JobSummaryView = Backbone.View.extend({
+ events: {
+ "click #updateSummaryBtn" : "handleUpdate"
+ },
+ initialize: function(settings) {
+ this.handleUpdate();
+ },
+ handleUpdate: function(evt) {
+ var requestURL = contextURL + "/executor";
+ var model = this.model;
+ var self = this;
+
+ var requestData = {
+ "execid": execId,
+ "jobId": jobId,
+ "ajax":"fetchExecJobSummary",
+ "attempt": attempt
+ };
+
+ $.ajax({
+ url: requestURL,
+ dataType: "json",
+ data: requestData,
+ error: function(data) {
+ console.log(data);
+ },
+ success: function(data) {
+ console.log("fetchSummary");
+ if (data.error) {
+ console.log(data.error);
+ }
+ else {
+ self.renderCommandTable(data.command, data.classpath, data.params);
+ self.renderJobTable(data.summaryTableHeaders, data.summaryTableData, "summary");
+ self.renderJobTable(data.statTableHeaders, data.statTableData, "stats");
+ }
+ }
+ });
+ },
+ renderCommandTable: function(command, classpath, params) {
+ if (command) {
+ var commandTable = $("#commandTable");
+ var i;
+
+ // Add row for command
+ var tr = document.createElement("tr");
+ var td = document.createElement("td");
+ $(td).append("<b>Command</b>");
+ $(tr).append(td);
+ td = document.createElement("td");
+ $(td).text(command);
+ $(tr).append(td);
+ commandTable.append(tr);
+
+ // Add row for classpath
+ if (classpath && classpath.length > 0) {
+ tr = document.createElement("tr");
+ td = document.createElement("td");
+ $(td).append("<b>Classpath</b>");
+ $(tr).append(td);
+ td = document.createElement("td");
+ $(td).append(classpath[0]);
+ for (i = 1; i < classpath.length; i++) {
+ $(td).append("<br/>" + classpath[i]);
+ }
+ $(tr).append(td);
+ commandTable.append(tr);
+ }
+
+ // Add row for params
+ if (params && params.length > 0) {
+ tr = document.createElement("tr");
+ td = document.createElement("td");
+ $(td).append("<b>Params</b>");
+ $(tr).append(td);
+ td = document.createElement("td");
+ $(td).append(params[0]);
+ for (i = 1; i < params.length; i++) {
+ $(td).append("<br/>" + params[i]);
+ }
+ $(tr).append(td);
+ commandTable.append(tr);
+ }
+ }
+ },
+ renderJobTable: function(headers, data, prefix) {
+ if (headers) {
+ // Add table headers
+ var header = $("#" + prefix + "Header");
+ var tr = document.createElement("tr");
+ var i;
+ for (i = 0; i < headers.length; i++) {
+ var th = document.createElement("th");
+ $(th).text(headers[i]);
+ $(tr).append(th);
+ }
+ header.append(tr);
+
+ // Add table body
+ var body = $("#" + prefix + "Body");
+ for (i = 0; i < data.length; i++) {
+ tr = document.createElement("tr");
+ var row = data[i];
+ for (var j = 0; j < headers.length; j++) {
+ var td = document.createElement("td");
+ $(td).text(row[j]);
+ $(tr).append(td);
+ }
+ body.append(tr);
+ }
+ }
+ }
+});
+
+var jobTabView;
+azkaban.JobTabView = Backbone.View.extend({
+ events: {
+ 'click #jobSummaryViewLink': 'handleJobSummaryViewLinkClick',
+ 'click #jobLogViewLink': 'handleJobLogViewLinkClick'
+ },
+
+ initialize: function(settings) {
+ var selectedView = settings.selectedView;
+ if (selectedView == 'joblog') {
+ this.handleJobLogViewLinkClick();
+ }
+ else {
+ this.handleJobSummaryViewLinkClick();
+ }
+ },
+
+ render: function() {
+ },
+
+ handleJobLogViewLinkClick: function() {
+ $('#jobSummaryViewLink').removeClass('selected');
+ $('#jobSummaryView').hide();
+ $('#jobLogViewLink').addClass('selected');
+ $('#jobLogView').show();
+ },
+
+ handleJobSummaryViewLinkClick: function() {
+ $('#jobSummaryViewLink').addClass('selected');
+ $('#jobSummaryView').show();
+ $('#jobLogViewLink').removeClass('selected');
+ $('#jobLogView').hide();
+ },
+});
+
+var showDialog = function(title, message) {
+ $('#messageTitle').text(title);
+ $('#messageBox').text(message);
+ $('#messageDialog').modal({
+ closeHTML: "<a href='#' title='Close' class='modal-close'>x</a>",
+ position: ["20%",],
+ containerId: 'confirm-container',
+ containerCss: {
+ 'height': '220px',
+ 'width': '565px'
+ },
+ onShow: function (dialog) {
+ }
+ });
+}
+
+$(function() {
+ var selected;
+ logModel = new azkaban.LogModel();
+ jobLogView = new azkaban.JobLogView({
+ el: $('#jobLogView'),
+ model: logModel
+ });
+
+ summaryModel = new azkaban.SummaryModel();
+ jobSummaryView = new azkaban.JobSummaryView({
+ el: $('#jobSummaryView'),
+ model: summaryModel
+ });
+
+ jobTabView = new azkaban.JobTabView({
+ el: $('#headertabs')
+ });
+
+ if (window.location.hash) {
+ var hash = window.location.hash;
+ if (hash == '#joblog') {
+ jobTabView.handleJobLogViewLinkClick();
+ }
+ else if (hash == '#jobsummary') {
+ jobTabView.handleJobSummaryViewLinkClick();
+ }
+ }
+});