Skip to content
This repository was archived by the owner on Jan 9, 2020. It is now read-only.

Commit 7475a96

Browse files
Marcelo Vanzinsquito
authored andcommitted
[SPARK-20645][CORE] Port environment page to new UI backend.
This change modifies the status listener to collect the information needed to render the envionment page, and populates that page and the API with information collected by the listener. Tested with existing and added unit tests. Author: Marcelo Vanzin <[email protected]> Closes apache#19677 from vanzin/SPARK-20645.
1 parent 0846a44 commit 7475a96

File tree

11 files changed

+402
-92
lines changed

11 files changed

+402
-92
lines changed

core/src/main/scala/org/apache/spark/status/AppStatusListener.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,24 @@ private[spark] class AppStatusListener(
8888
kvstore.write(new ApplicationInfoWrapper(appInfo))
8989
}
9090

91+
override def onEnvironmentUpdate(event: SparkListenerEnvironmentUpdate): Unit = {
92+
val details = event.environmentDetails
93+
94+
val jvmInfo = Map(details("JVM Information"): _*)
95+
val runtime = new v1.RuntimeInfo(
96+
jvmInfo.get("Java Version").orNull,
97+
jvmInfo.get("Java Home").orNull,
98+
jvmInfo.get("Scala Version").orNull)
99+
100+
val envInfo = new v1.ApplicationEnvironmentInfo(
101+
runtime,
102+
details.getOrElse("Spark Properties", Nil),
103+
details.getOrElse("System Properties", Nil),
104+
details.getOrElse("Classpath Entries", Nil))
105+
106+
kvstore.write(new ApplicationEnvironmentInfoWrapper(envInfo))
107+
}
108+
91109
override def onApplicationEnd(event: SparkListenerApplicationEnd): Unit = {
92110
val old = appInfo.attempts.head
93111
val attempt = new v1.ApplicationAttemptInfo(

core/src/main/scala/org/apache/spark/status/AppStatusStore.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ import org.apache.spark.util.kvstore.{InMemoryStore, KVStore}
3333
*/
3434
private[spark] class AppStatusStore(store: KVStore) {
3535

36+
def applicationInfo(): v1.ApplicationInfo = {
37+
store.view(classOf[ApplicationInfoWrapper]).max(1).iterator().next().info
38+
}
39+
40+
def environmentInfo(): v1.ApplicationEnvironmentInfo = {
41+
val klass = classOf[ApplicationEnvironmentInfoWrapper]
42+
store.read(klass, klass.getName()).info
43+
}
44+
3645
def jobsList(statuses: JList[JobExecutionStatus]): Seq[v1.JobData] = {
3746
val it = store.view(classOf[JobDataWrapper]).asScala.map(_.info)
3847
if (!statuses.isEmpty()) {

core/src/main/scala/org/apache/spark/status/api/v1/ApplicationEnvironmentResource.scala

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,7 @@ private[v1] class ApplicationEnvironmentResource(ui: SparkUI) {
2626

2727
@GET
2828
def getEnvironmentInfo(): ApplicationEnvironmentInfo = {
29-
val listener = ui.environmentListener
30-
listener.synchronized {
31-
val jvmInfo = Map(listener.jvmInformation: _*)
32-
val runtime = new RuntimeInfo(
33-
jvmInfo("Java Version"),
34-
jvmInfo("Java Home"),
35-
jvmInfo("Scala Version"))
36-
37-
new ApplicationEnvironmentInfo(
38-
runtime,
39-
listener.sparkProperties,
40-
listener.systemProperties,
41-
listener.classpathEntries)
42-
}
29+
ui.store.environmentInfo()
4330
}
4431

4532
}

core/src/main/scala/org/apache/spark/status/storeTypes.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ private[spark] class ApplicationInfoWrapper(val info: ApplicationInfo) {
3434

3535
}
3636

37+
private[spark] class ApplicationEnvironmentInfoWrapper(val info: ApplicationEnvironmentInfo) {
38+
39+
/**
40+
* There's always a single ApplicationEnvironmentInfo object per application, so this
41+
* ID doesn't need to be dynamic. But the KVStore API requires an ID.
42+
*/
43+
@JsonIgnore @KVIndex
44+
def id: String = classOf[ApplicationEnvironmentInfoWrapper].getName()
45+
46+
}
47+
3748
private[spark] class ExecutorSummaryWrapper(val info: ExecutorSummary) {
3849

3950
@JsonIgnore @KVIndex

core/src/main/scala/org/apache/spark/ui/SparkUI.scala

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,10 @@ import org.apache.spark.{SecurityManager, SparkConf, SparkContext}
2525
import org.apache.spark.internal.Logging
2626
import org.apache.spark.scheduler._
2727
import org.apache.spark.status.AppStatusStore
28-
import org.apache.spark.status.api.v1.{ApiRootResource, ApplicationAttemptInfo, ApplicationInfo,
29-
UIRoot}
28+
import org.apache.spark.status.api.v1._
3029
import org.apache.spark.storage.StorageStatusListener
3130
import org.apache.spark.ui.JettyUtils._
32-
import org.apache.spark.ui.env.{EnvironmentListener, EnvironmentTab}
31+
import org.apache.spark.ui.env.EnvironmentTab
3332
import org.apache.spark.ui.exec.{ExecutorsListener, ExecutorsTab}
3433
import org.apache.spark.ui.jobs.{JobProgressListener, JobsTab, StagesTab}
3534
import org.apache.spark.ui.scope.RDDOperationGraphListener
@@ -44,7 +43,6 @@ private[spark] class SparkUI private (
4443
val sc: Option[SparkContext],
4544
val conf: SparkConf,
4645
securityManager: SecurityManager,
47-
val environmentListener: EnvironmentListener,
4846
val storageStatusListener: StorageStatusListener,
4947
val executorsListener: ExecutorsListener,
5048
val jobProgressListener: JobProgressListener,
@@ -73,7 +71,7 @@ private[spark] class SparkUI private (
7371
val stagesTab = new StagesTab(this)
7472
attachTab(stagesTab)
7573
attachTab(new StorageTab(this))
76-
attachTab(new EnvironmentTab(this))
74+
attachTab(new EnvironmentTab(this, store))
7775
attachTab(new ExecutorsTab(this))
7876
attachHandler(createStaticHandler(SparkUI.STATIC_RESOURCE_DIR, "/static"))
7977
attachHandler(createRedirectHandler("/", "/jobs/", basePath = basePath))
@@ -88,9 +86,13 @@ private[spark] class SparkUI private (
8886
initialize()
8987

9088
def getSparkUser: String = {
91-
environmentListener.sparkUser
92-
.orElse(environmentListener.systemProperties.toMap.get("user.name"))
93-
.getOrElse("<unknown>")
89+
try {
90+
Option(store.applicationInfo().attempts.head.sparkUser)
91+
.orElse(store.environmentInfo().systemProperties.toMap.get("user.name"))
92+
.getOrElse("<unknown>")
93+
} catch {
94+
case _: NoSuchElementException => "<unknown>"
95+
}
9496
}
9597

9698
def getAppName: String = appName
@@ -143,6 +145,7 @@ private[spark] class SparkUI private (
143145
def setStreamingJobProgressListener(sparkListener: SparkListener): Unit = {
144146
streamingJobProgressListener = Option(sparkListener)
145147
}
148+
146149
}
147150

148151
private[spark] abstract class SparkUITab(parent: SparkUI, prefix: String)
@@ -184,21 +187,20 @@ private[spark] object SparkUI {
184187
addListenerFn(listener)
185188
listener
186189
}
187-
val environmentListener = new EnvironmentListener
190+
188191
val storageStatusListener = new StorageStatusListener(conf)
189192
val executorsListener = new ExecutorsListener(storageStatusListener, conf)
190193
val storageListener = new StorageListener(storageStatusListener)
191194
val operationGraphListener = new RDDOperationGraphListener(conf)
192195

193-
addListenerFn(environmentListener)
194196
addListenerFn(storageStatusListener)
195197
addListenerFn(executorsListener)
196198
addListenerFn(storageListener)
197199
addListenerFn(operationGraphListener)
198200

199-
new SparkUI(store, sc, conf, securityManager, environmentListener, storageStatusListener,
200-
executorsListener, jobProgressListener, storageListener, operationGraphListener,
201-
appName, basePath, lastUpdateTime, startTime, appSparkVersion)
201+
new SparkUI(store, sc, conf, securityManager, storageStatusListener, executorsListener,
202+
jobProgressListener, storageListener, operationGraphListener, appName, basePath,
203+
lastUpdateTime, startTime, appSparkVersion)
202204
}
203205

204206
}

core/src/main/scala/org/apache/spark/ui/env/EnvironmentPage.scala

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,31 @@ import javax.servlet.http.HttpServletRequest
2121

2222
import scala.xml.Node
2323

24-
import org.apache.spark.ui.{UIUtils, WebUIPage}
24+
import org.apache.spark.SparkConf
25+
import org.apache.spark.status.AppStatusStore
26+
import org.apache.spark.ui._
2527
import org.apache.spark.util.Utils
2628

27-
private[ui] class EnvironmentPage(parent: EnvironmentTab) extends WebUIPage("") {
28-
private val listener = parent.listener
29+
private[ui] class EnvironmentPage(
30+
parent: EnvironmentTab,
31+
conf: SparkConf,
32+
store: AppStatusStore) extends WebUIPage("") {
2933

3034
def render(request: HttpServletRequest): Seq[Node] = {
35+
val appEnv = store.environmentInfo()
36+
val jvmInformation = Map(
37+
"Java Version" -> appEnv.runtime.javaVersion,
38+
"Java Home" -> appEnv.runtime.javaHome,
39+
"Scala Version" -> appEnv.runtime.scalaVersion)
40+
3141
val runtimeInformationTable = UIUtils.listingTable(
32-
propertyHeader, jvmRow, listener.jvmInformation, fixedWidth = true)
42+
propertyHeader, jvmRow, jvmInformation, fixedWidth = true)
3343
val sparkPropertiesTable = UIUtils.listingTable(propertyHeader, propertyRow,
34-
Utils.redact(parent.conf, listener.sparkProperties), fixedWidth = true)
35-
44+
Utils.redact(conf, appEnv.sparkProperties.toSeq), fixedWidth = true)
3645
val systemPropertiesTable = UIUtils.listingTable(
37-
propertyHeader, propertyRow, listener.systemProperties, fixedWidth = true)
46+
propertyHeader, propertyRow, appEnv.systemProperties, fixedWidth = true)
3847
val classpathEntriesTable = UIUtils.listingTable(
39-
classPathHeaders, classPathRow, listener.classpathEntries, fixedWidth = true)
48+
classPathHeaders, classPathRow, appEnv.classpathEntries, fixedWidth = true)
4049
val content =
4150
<span>
4251
<h4>Runtime Information</h4> {runtimeInformationTable}
@@ -54,3 +63,9 @@ private[ui] class EnvironmentPage(parent: EnvironmentTab) extends WebUIPage("")
5463
private def propertyRow(kv: (String, String)) = <tr><td>{kv._1}</td><td>{kv._2}</td></tr>
5564
private def classPathRow(data: (String, String)) = <tr><td>{data._1}</td><td>{data._2}</td></tr>
5665
}
66+
67+
private[ui] class EnvironmentTab(
68+
parent: SparkUI,
69+
store: AppStatusStore) extends SparkUITab(parent, "environment") {
70+
attachPage(new EnvironmentPage(this, parent.conf, store))
71+
}

core/src/main/scala/org/apache/spark/ui/env/EnvironmentTab.scala

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)