Skip to content

Commit

Permalink
[LIVY-344][WEB UI] Create Session Log Page
Browse files Browse the repository at this point in the history
[LIVY-344](https://issues.cloudera.org/browse/LIVY-344)

Created a Session Log page for viewing the session log.
Updated All Sessions Page and Session Page with links to the Log Page.
Log Page exists for both Interactive Sessions and Batches.

Tested Manually, screenshots below

![screen shot 2017-07-26 at 1 30 35 pm](https://user-images.githubusercontent.com/13952758/28643916-4668a3f0-720c-11e7-8441-526547980e7b.png)
![screen shot 2017-07-26 at 1 30 40 pm](https://user-images.githubusercontent.com/13952758/28643917-467d50ca-720c-11e7-9c08-fab578d81ad5.png)
![screen shot 2017-07-26 at 1 30 44 pm](https://user-images.githubusercontent.com/13952758/28643918-467fcfe4-720c-11e7-8d95-72fb4c57c6a8.png)

Author: Alex Bozarth <[email protected]>

Closes apache#25 from ajbozarth/log-ui.
  • Loading branch information
ajbozarth authored and jerryshao committed Aug 1, 2017
1 parent 60ee047 commit 69300a2
Showing 8 changed files with 94 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
*/

body {
padding-top: 15px;
padding: 15px 0;
}

pre {
@@ -32,6 +32,6 @@ td .progress {
margin: 0;
}

.session-summary {
#session-summary {
margin: 20px 0;
}
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ function loadSessionsTable(sessions) {
tdWrap(session.proxyUser) +
tdWrap(session.kind) +
tdWrap(session.state) +
tdWrap(driverLogLink(session)) +
tdWrap(logLinks(session, "session")) +
"</tr>"
);
});
@@ -38,7 +38,7 @@ function loadBatchesTable(sessions) {
tdWrap(session.id) +
tdWrap(appIdLink(session)) +
tdWrap(session.state) +
tdWrap(driverLogLink(session)) +
tdWrap(logLinks(session, "batch")) +
"</tr>"
);
});
Original file line number Diff line number Diff line change
@@ -46,10 +46,16 @@ function driverLogLink(session) {
if (driverLogUrl != null) {
return anchorLink(driverLogUrl, "driver");
} else {
return;
return "";
}
}

function logLinks(session, kind) {
var sessionLog = divWrap(uiLink(kind + "/" + session.id + "/log", "session"));
var driverLog = divWrap(driverLogLink(session));
return sessionLog + driverLog;
}

function appIdLink(session) {
var appUiUrl = session.appInfo.sparkUiUrl;
if (appUiUrl != null) {
@@ -71,6 +77,10 @@ function preWrap(inner) {
return "<pre>" + escapeHtml(inner) + "</pre>";
}

function divWrap(inner) {
return "<div>" + inner + "</div>";
}

function progressBar(double) {
var cent = +(double * 100).toFixed(3);
return '<div class="progress"><div class="progress-bar" style="width:'
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.
*/

function getLogPath(type, id) {
if (type == "session") {
return "/sessions/" + id + "/log";
} else if (type == "batch") {
return "/batches/" + id + "/log";
} else {
return "";
}
}

function parseLog(logLines) {
// TODO: [LIVY-387]: Separate out stdout, stderr, and YARN Diagnostics into different viewers
return preWrap(logLines.join("\n"));
}

$(document).ready(function () {
var pathArr = getPathArray();
var type = pathArr.shift();
var id = pathArr.shift();

$.getJSON(location.origin + getLogPath(type, id), {size: -1}, function(response) {
if (response) {
$("#session-log").append(parseLog(response.log));
}
});
});
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ function appendSummary(session) {
sumWrap("Proxy User", session.proxyUser) +
sumWrap("Session Kind", session.kind) +
sumWrap("State", session.state) +
sumWrap("Logs", driverLogLink(session)) +
sumWrap("Logs", logLinks(session, "session")) +
"</ul>"
);
}
Original file line number Diff line number Diff line change
@@ -230,8 +230,11 @@ abstract class SessionServlet[S <: Session, R <: RecoveryMetadata](
private def serializeLogs(session: S, fromOpt: Option[Int], sizeOpt: Option[Int]) = {
val lines = session.logLines()

val size = sizeOpt.getOrElse(100)
var size = sizeOpt.getOrElse(100)
var from = fromOpt.getOrElse(-1)
if (size < 0) {
size = lines.length
}
if (from < 0) {
from = math.max(0, lines.length - size)
}
32 changes: 30 additions & 2 deletions server/src/main/scala/org/apache/livy/server/ui/UIServlet.scala
Original file line number Diff line number Diff line change
@@ -30,6 +30,10 @@ class UIServlet extends ScalatraServlet {
private case class SessionPage(id: Int) extends Page {
val name: String = "Session " + id
}
private case class LogPage(sessionType: String, id: Int) extends Page {
val sessionName: String = sessionType + " " + id
val name: String = sessionName + " Log"
}

private def getHeader(pageName: String): Seq[Node] =
<head>
@@ -63,9 +67,15 @@ class UIServlet extends ScalatraServlet {
private def getNavBar(page: Page): Seq[Node] = {
val tabs: Seq[Node] = page match {
case _: AllSessionsPage => <li class="active"><a href="#">Sessions</a></li>
case pageInfo: SessionPage => {
case sessionPage: SessionPage => {
<li><a href="/ui">Sessions</a></li> ++
<li class="active"><a href="#">{sessionPage.name}</a></li>
}
case logPage: LogPage => {
val sessionLink = if (logPage.sessionType == "Session") "/ui/session/" + logPage.id else "#"
<li><a href="/ui">Sessions</a></li> ++
<li class="active"><a href="#">{pageInfo.name}</a></li>
<li><a href={sessionLink}>{logPage.sessionName}</a></li> ++
<li class="active"><a href="#">Log</a></li>
}
case _ => Seq.empty
}
@@ -108,4 +118,22 @@ class UIServlet extends ScalatraServlet {

createPage(SessionPage(params("id").toInt), content)
}

private def getLogPage(page: LogPage): Seq[Node] = {
val content =
<div id="log-page">
<div id="session-log"></div>
<script src="/static/js/session-log.js"></script>
</div>

createPage(page, content)
}

get("/session/:id/log") {
getLogPage(LogPage("Session", params("id").toInt))
}

get("/batch/:id/log") {
getLogPage(LogPage("Batch", params("id").toInt))
}
}
Original file line number Diff line number Diff line change
@@ -192,7 +192,7 @@ class SparkYarnApp private[utils] (
private def getYarnDiagnostics(appReport: ApplicationReport): IndexedSeq[String] = {
Option(appReport.getDiagnostics)
.filter(_.nonEmpty)
.map[IndexedSeq[String]]("YARN Diagnostics:" +: _.split("\n"))
.map[IndexedSeq[String]](_.split("\n"))
.getOrElse(IndexedSeq.empty)
}

0 comments on commit 69300a2

Please sign in to comment.