Skip to content

Commit 129e30d

Browse files
xingchaozhallenma
authored andcommitted
[CARMEL-3519] Viewpoint Support (#27)
1 parent 6135138 commit 129e30d

File tree

50 files changed

+2266
-107
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2266
-107
lines changed

assembly/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@
7979
<artifactId>spark-repl_${scala.binary.version}</artifactId>
8080
<version>${project.version}</version>
8181
</dependency>
82+
<dependency>
83+
<groupId>org.apache.spark</groupId>
84+
<artifactId>spark-viewpoint_${scala.binary.version}</artifactId>
85+
<version>${project.version}</version>
86+
</dependency>
8287

8388
<!--
8489
Because we don't shade dependencies anymore, we need to restore Guava to compile scope so

core/src/main/resources/org/apache/spark/ui/static/historypage-common.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
$(document).ready(function() {
1919
if ($('#last-updated').length) {
2020
var lastUpdatedMillis = Number($('#last-updated').text());
21-
$('#last-updated').text(formatTimeMillis(lastUpdatedMillis));
21+
$('#last-updated').text(formatTimeMillisWithTimeZone(lastUpdatedMillis, 0));
2222
}
2323

2424
$('#time-zone').text(getTimeZone());

core/src/main/resources/org/apache/spark/ui/static/historypage-template.html

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
Started
4747
</span>
4848
</th>
49-
{{#showCompletedColumns}}
5049
<th>
5150
<span data-toggle="tooltip" data-placement="top" title="The completed time of this application.">
5251
Completed
@@ -57,7 +56,6 @@
5756
Duration
5857
</span>
5958
</th>
60-
{{/showCompletedColumns}}
6159
<th>
6260
<span data-toggle="tooltip" data-placement="top" title="The Spark user of this application">
6361
Spark User
@@ -85,10 +83,8 @@
8583
<td><a href="{{uiroot}}/history/{{id}}/{{attemptId}}/jobs/">{{attemptId}}</a></td>
8684
{{/hasMultipleAttempts}}
8785
<td>{{startTime}}</td>
88-
{{#showCompletedColumns}}
8986
<td>{{endTime}}</td>
9087
<td><span title="{{durationMillisec}}">{{duration}}</span></td>
91-
{{/showCompletedColumns}}
9288
<td>{{sparkUser}}</td>
9389
<td>{{lastUpdated}}</td>
9490
<td><a href="{{log}}" class="btn btn-info btn-mini">Download</a></td>

core/src/main/resources/org/apache/spark/ui/static/historypage.js

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ function getColumnIndex(columns, columnName) {
5555
return -1;
5656
}
5757

58+
function onSearch() {
59+
var searchStr = $('#search').val().toLowerCase().trim();
60+
if (searchStr == "") {
61+
return;
62+
}
63+
var reg= /^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$/;
64+
if (searchStr.match(reg)) {
65+
window.location.href="/?session="+searchStr;
66+
} else if(searchStr.indexOf("hdmi-") >= 0) {
67+
window.location.href="/?queue="+searchStr;
68+
} else {
69+
window.location.href="/?user="+searchStr;
70+
}
71+
}
72+
5873
jQuery.extend( jQuery.fn.dataTableExt.oSort, {
5974
"title-numeric-pre": function ( a ) {
6075
var x = a.match(/title="*(-?[0-9\.]+)/)[1];
@@ -105,22 +120,34 @@ $(document).ready(function() {
105120

106121
var historySummary = $("#history-summary");
107122
var searchString = window.location.search;
108-
var requestedIncomplete = getParameterByName("showIncomplete", searchString);
109-
requestedIncomplete = (requestedIncomplete == "true" ? true : false);
123+
124+
var searchSessionId = getParameterByName("session", searchString);
125+
var searchUserId = getParameterByName("user", searchString)
126+
var longRunning = getParameterByName("longRunning", searchString)
127+
longRunning = (longRunning == "true" ? true : false);
128+
129+
var url = "api/v1/applications?limit=" + appLimit
130+
if(searchSessionId != "") {
131+
url += "&session=" + searchSessionId
132+
}
133+
134+
if(searchUserId != "") {
135+
url += "&user=" + searchUserId
136+
}
137+
138+
if(longRunning) {
139+
url += "&longRunning=" + longRunning
140+
}
110141

111142
var appParams = {
112-
limit: appLimit,
113-
status: (requestedIncomplete ? "running" : "completed")
114143
};
115144

116-
$.getJSON(uiRoot + "/api/v1/applications", appParams, function(response,status,jqXHR) {
145+
console.log(url)
146+
$.getJSON(url, appParams, function(response,status,jqXHR) {
117147
var array = [];
118148
var hasMultipleAttempts = false;
119149
for (var i in response) {
120150
var app = response[i];
121-
if (app["attempts"][0]["completed"] == requestedIncomplete) {
122-
continue; // if we want to show for Incomplete, we skip the completed apps; otherwise skip incomplete ones.
123-
}
124151
var version = "Unknown"
125152
if (app["attempts"].length > 0) {
126153
version = app["attempts"][0]["appSparkVersion"]
@@ -131,18 +158,22 @@ $(document).ready(function() {
131158
hasMultipleAttempts = true;
132159
}
133160
var num = app["attempts"].length;
161+
if(num >= 1) {
162+
var latestAttempt = app["attempts"][num -1]
163+
var latestAttemptId = (latestAttempt.hasOwnProperty("attemptId") ? latestAttempt["attemptId"] : "")
134164
for (var j in app["attempts"]) {
135165
var attempt = app["attempts"][j];
136-
attempt["startTime"] = formatTimeMillis(attempt["startTimeEpoch"]);
137-
attempt["endTime"] = formatTimeMillis(attempt["endTimeEpoch"]);
138-
attempt["lastUpdated"] = formatTimeMillis(attempt["lastUpdatedEpoch"]);
166+
attempt["startTime"] = formatTimeMillisWithTimeZone(attempt["startTimeEpoch"], 0);
167+
attempt["endTime"] = formatTimeMillisWithTimeZone(attempt["endTimeEpoch"], 0);
168+
attempt["lastUpdated"] = formatTimeMillisWithTimeZone(attempt["lastUpdatedEpoch"], 0);
139169
attempt["log"] = uiRoot + "/api/v1/applications/" + id + "/" +
140170
(attempt.hasOwnProperty("attemptId") ? attempt["attemptId"] + "/" : "") + "logs";
141171
attempt["durationMillisec"] = attempt["duration"];
142172
attempt["duration"] = formatDuration(attempt["duration"]);
143-
var app_clone = {"id" : id, "name" : name, "version": version, "num" : num, "attempts" : [attempt]};
173+
var app_clone = {"version": version, "id" : id, "name" : name, "num" : num, "attempts" : [attempt], "latestAttemptId": latestAttemptId};
144174
array.push(app_clone);
145175
}
176+
}
146177
}
147178
if(array.length < 20) {
148179
$.fn.dataTable.defaults.paging = false;
@@ -152,7 +183,6 @@ $(document).ready(function() {
152183
"uiroot": uiRoot,
153184
"applications": array,
154185
"hasMultipleAttempts": hasMultipleAttempts,
155-
"showCompletedColumns": !requestedIncomplete,
156186
};
157187

158188
$.get(uiRoot + "/static/historypage-template.html", function(template) {
@@ -177,6 +207,7 @@ $(document).ready(function() {
177207
{name: 'eventLog'},
178208
],
179209
"autoWidth": false,
210+
"searching": false,
180211
"deferRender": true
181212
};
182213

@@ -190,12 +221,7 @@ $(document).ready(function() {
190221
conf.columns = removeColumnByName(conf.columns, attemptIdColumnName);
191222
}
192223

193-
var defaultSortColumn = completedColumnName;
194-
if (requestedIncomplete) {
195-
defaultSortColumn = startedColumnName;
196-
conf.columns = removeColumnByName(conf.columns, completedColumnName);
197-
conf.columns = removeColumnByName(conf.columns, durationColumnName);
198-
}
224+
var defaultSortColumn = startedColumnName;
199225
conf.order = [[ getColumnIndex(conf.columns, defaultSortColumn), "desc" ]];
200226
conf.columnDefs = [
201227
{"searchable": false, "targets": [getColumnIndex(conf.columns, durationColumnName)]}
@@ -206,4 +232,17 @@ $(document).ready(function() {
206232
$('#history-summary [data-toggle="tooltip"]').tooltip();
207233
});
208234
});
235+
236+
237+
if(searchSessionId != "") {
238+
$('#search').val(searchSessionId);
239+
}
240+
if(searchUserId != "") {
241+
$('#search').val(searchUserId);
242+
}
243+
$('#search').bind('keypress',function(event){
244+
if(event.keyCode == "13") {
245+
onSearch();
246+
}
247+
});
209248
});

core/src/main/resources/org/apache/spark/ui/static/utils.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@ function padZeroes(num) {
5151
return ("0" + num).slice(-2);
5252
}
5353

54+
function formatTimeMillisWithTimeZone(timeMillis, timeZone) {
55+
if (timeMillis <= 0) {
56+
return "-";
57+
} else {
58+
var offset_GMT = new Date().getTimezoneOffset();
59+
var dt = new Date(timeMillis + offset_GMT * 60 * 1000 + timeZone * 60 * 60 * 1000);
60+
return dt.getFullYear() + "-" +
61+
padZeroes(dt.getMonth() + 1) + "-" +
62+
padZeroes(dt.getDate()) + " " +
63+
padZeroes(dt.getHours()) + ":" +
64+
padZeroes(dt.getMinutes()) + ":" +
65+
padZeroes(dt.getSeconds());
66+
}
67+
}
68+
5469
function formatTimeMillis(timeMillis) {
5570
if (timeMillis <= 0) {
5671
return "-";

core/src/main/scala/org/apache/spark/SparkContext.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,15 @@ class SparkContext(config: SparkConf) extends Logging {
15631563
}
15641564
}
15651565

1566+
/**
1567+
* :: DeveloperApi ::
1568+
* Register a listener to event log queue.
1569+
*/
1570+
@DeveloperApi
1571+
def addSparkListenerToEventLogQueue(listener: SparkListenerInterface): Unit = {
1572+
listenerBus.addToEventLogQueue(listener)
1573+
}
1574+
15661575
/**
15671576
* :: DeveloperApi ::
15681577
* Register a listener to receive up-calls from events that happen during execution.
@@ -2474,6 +2483,24 @@ class SparkContext(config: SparkConf) extends Logging {
24742483
driverUpdates))
24752484
}
24762485

2486+
def getSparkListenerApplicationStart(): Option[SparkListenerApplicationStart] = {
2487+
Some(SparkListenerApplicationStart(appName, Some(applicationId),
2488+
startTime, sparkUser, applicationAttemptId, schedulerBackend.getDriverLogUrls))
2489+
}
2490+
2491+
def getSparkListenerEnvironmentUpdate(): Option[SparkListenerEnvironmentUpdate] = {
2492+
if (taskScheduler != null) {
2493+
val schedulingMode = getSchedulingMode.toString
2494+
val addedJarPaths = addedJars.keys.toSeq
2495+
val addedFilePaths = addedFiles.keys.toSeq
2496+
val environmentDetails = SparkEnv.environmentDetails(conf, hadoopConfiguration,
2497+
schedulingMode, addedJarPaths, addedFilePaths)
2498+
Some(SparkListenerEnvironmentUpdate(environmentDetails))
2499+
} else {
2500+
None
2501+
}
2502+
}
2503+
24772504
// In order to prevent multiple SparkContexts from being active at the same time, mark this
24782505
// context as having finished construction.
24792506
// NOTE: this must be placed at the end of the SparkContext constructor.

core/src/main/scala/org/apache/spark/deploy/SparkHadoopUtil.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,8 @@ private[spark] object SparkHadoopUtil {
408408

409409
val SPARK_YARN_CREDS_COUNTER_DELIM = "-"
410410

411+
val HIVE_SESSION_ID = "spark.hive.session.id"
412+
411413
/**
412414
* Number of records to update input metrics when reading from HadoopRDDs.
413415
*

core/src/main/scala/org/apache/spark/deploy/history/HistoryPage.scala

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,20 @@ import org.apache.spark.ui.{UIUtils, WebUIPage}
2727
private[history] class HistoryPage(parent: HistoryServer) extends WebUIPage("") {
2828

2929
def render(request: HttpServletRequest): Seq[Node] = {
30-
val requestedIncomplete = Option(request.getParameter("showIncomplete"))
30+
val sessionId =
31+
Option(request.getParameter("session")).getOrElse("").trim
32+
33+
val userId =
34+
Option(request.getParameter("user")).getOrElse("").trim
35+
36+
val longRunning = Option(request.getParameter("longRunning"))
3137
.getOrElse("false").toBoolean
3238

33-
val displayApplications = parent.getApplicationList()
34-
.exists(isApplicationCompleted(_) != requestedIncomplete)
39+
val displayApplications = parent.getApplicationList().
40+
filter(p => sessionId == "" || p.id.endsWith(sessionId)).
41+
filter(p => userId == "" || p.attempts.exists(_.sparkUser.equalsIgnoreCase(userId))).
42+
length > 0
43+
3544
val eventLogsUnderProcessCount = parent.getEventLogsUnderProcess()
3645
val lastUpdatedTime = parent.getLastUpdatedTime()
3746
val providerConfig = parent.getProviderConfig()
@@ -58,7 +67,27 @@ private[history] class HistoryPage(parent: HistoryServer) extends WebUIPage("")
5867
}
5968

6069
{
61-
<p>Client local time zone: <span id="time-zone"></span></p>
70+
<p>Time zone: <span>UTC</span></p>
71+
}
72+
73+
{
74+
<div><table style="width:100%"><tbody><tr>
75+
<td><b style="margin-left:-30px;margin-right:5px">
76+
</b>
77+
{
78+
if (!longRunning) {
79+
<a href={
80+
UIUtils.prependBaseUri(request, "/?" + "longRunning=true")}>
81+
Long Running
82+
</a>
83+
}
84+
}
85+
</td>
86+
<td align="right">
87+
<input type="text" placeholder="Input Session Id or User Id" id="search"
88+
style="min-width:280px;margin-right:1px;margin-top:10px"/>
89+
<button class="btn btn-info" onclick="onSearch()">Search</button>
90+
</td></tr></tbody></table></div>
6291
}
6392

6493
{
@@ -68,31 +97,15 @@ private[history] class HistoryPage(parent: HistoryServer) extends WebUIPage("")
6897
<div id="history-summary" class="row-fluid"></div> ++
6998
<script src={UIUtils.prependBaseUri(request, "/static/historypage.js")}></script> ++
7099
<script>setAppLimit({parent.maxApplications})</script>
71-
} else if (requestedIncomplete) {
72-
<h4>No incomplete applications found!</h4>
73100
} else if (eventLogsUnderProcessCount > 0) {
74-
<h4>No completed applications found!</h4>
101+
<h4>No applications found!</h4>
75102
} else {
76-
<h4>No completed applications found!</h4> ++ parent.emptyListingHtml
103+
<h4>No applications found!</h4> ++ parent.emptyListingHtml
77104
}
78105
}
79-
80-
<a href={makePageLink(request, !requestedIncomplete)}>
81-
{
82-
if (requestedIncomplete) {
83-
"Back to completed applications"
84-
} else {
85-
"Show incomplete applications"
86-
}
87-
}
88-
</a>
89106
</div>
90107
</div>
91-
UIUtils.basicSparkPage(request, content, "History Server", true)
92-
}
93-
94-
private def makePageLink(request: HttpServletRequest, showIncomplete: Boolean): String = {
95-
UIUtils.prependBaseUri(request, "/?" + "showIncomplete=" + showIncomplete)
108+
UIUtils.basicSparkPage(request, content, parent.serviceName, true)
96109
}
97110

98111
private def isApplicationCompleted(appInfo: ApplicationInfo): Boolean = {

0 commit comments

Comments
 (0)