blob: 06763d50707a64d26329dac88009c7f3dc8c120e [file] [log] [blame]
/**
* 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.
*/
package org.apache.hadoop.yarn.server.resourcemanager.webapp;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI._EVEN;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI._ODD;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI._TH;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptReportRequest;
import org.apache.hadoop.yarn.api.protocolrecords.GetContainersRequest;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptReport;
import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ContainerReport;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceRequest;
import org.apache.hadoop.yarn.api.records.YarnApplicationAttemptState;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptMetrics;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo;
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceRequestInfo;
import org.apache.hadoop.yarn.server.webapp.AppAttemptBlock;
import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo;
import org.apache.hadoop.yarn.util.Times;
import org.apache.hadoop.yarn.util.resource.Resources;
import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet;
import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet.DIV;
import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet.TABLE;
import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet.TBODY;
import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
import org.apache.hadoop.yarn.webapp.view.InfoBlock;
import com.google.inject.Inject;
public class RMAppAttemptBlock extends AppAttemptBlock{
private final ResourceManager rm;
protected Configuration conf;
private final static String DIAGNOSTICS_SCRIPT_BODY = new StringBuilder()
.append("var refresh = false;")
.append("var haveGotAppDiagnostic = false;")
.append("function getArray(objOrArray) {")
.append(" if(Array.isArray(objOrArray)){")
.append(" return objOrArray;")
.append(" } else {")
.append(" return [objOrArray];")
.append(" }")
.append("}")
.append("function getTableDataFromObjectArray(objectArray, fields) {")
.append(" if (objectArray == undefined) {")
.append(" return [];")
.append(" }")
.append(" var data = [];")
.append(" $.each(objectArray, function(i, object) {")
.append(" var dataItem = [];")
.append(" for (var i=0; i<fields.length; i++) {")
.append(" dataItem.push(object[fields[i]] != undefined ? ")
.append("object[fields[i]] : '');")
.append(" }")
.append(" data.push(dataItem);")
.append(" });")
.append(" return data;")
.append("}")
.append("function sendRequest(requestURL, doneCallBackFunc,")
.append(" failCallBackFunc) {")
.append(" $.ajax({")
.append(" type: 'GET',")
.append(" url: requestURL,")
.append(" contentType: 'text/plain'")
.append(" }).done(doneCallBackFunc).fail(failCallBackFunc);")
.append("}")
.append("function parseQueryAppActResponse(responseObj) {")
.append(" var requestDiagnostics = [], dateTime, appDiagnostic;")
.append(" responseObj = responseObj['appActivities'];")
.append(" if(responseObj.hasOwnProperty('allocations')){")
.append(" var allocations = getArray(responseObj['allocations']);")
.append(" var allocation = allocations[0];")
.append(" dateTime = allocation['dateTime'];")
.append(" if(allocation.hasOwnProperty('diagnostic')){")
.append(" appDiagnostic = allocation['diagnostic'];")
.append(" }")
.append(" if(allocation.hasOwnProperty('children')){")
.append(" var requestAllocations = ")
.append(" getArray(allocation['children']);")
.append(" $.each(requestAllocations, function (i, requestAllocation) {")
.append(" if(requestAllocation.hasOwnProperty('children')){")
.append(" var allocationAttempts = ")
.append(" getArray(requestAllocation['children']);")
.append(" var diagnosticSummary = requestAllocation.hasOwnProperty(")
.append(" 'diagnostic')? requestAllocation['diagnostic']+'. ':'';")
.append(" $.each(allocationAttempts, function(i,allocationAttempt) {")
.append(" if (i > 0) {")
.append(" diagnosticSummary += ', ';")
.append(" }")
.append(" diagnosticSummary += allocationAttempt['count'] + ' ' +")
.append(" (allocationAttempt['count']=='1' ? 'node ' : 'nodes ')")
.append(" + allocationAttempt['allocationState'];")
.append(" if (allocationAttempt.hasOwnProperty('diagnostic')) {")
.append(" diagnosticSummary += ' with diagnostic:' + ")
.append(" allocationAttempt['diagnostic'];")
.append(" }")
.append(" });")
.append(" delete requestAllocation['children'];")
.append(" requestAllocation['diagnostic']=diagnosticSummary;")
.append(" }")
.append(" requestDiagnostics.push(requestAllocation);")
.append(" });")
.append(" }")
.append(" }")
.append(" return [requestDiagnostics, dateTime, appDiagnostic];")
.append("}")
.append("function handleQueryAppActDone(data){")
.append(" console.log('App activities:', data);")
.append(" var results = parseQueryAppActResponse(data);")
.append(" console.log('parsed results:', results);")
.append(" var requestDiagnostics = results[0];")
.append(" var dateTime = results[1];")
.append(" var appDiagnostic = results[2];")
.append(" haveGotAppDiagnostic = false;")
.append(" if (appDiagnostic != undefined) {")
.append(" haveGotAppDiagnostic = true;")
.append(" $('#appDiagnostic').html('App diagnostic: '")
.append(" + appDiagnostic);")
.append(" }")
.append(" $('#diagnosticsTableDiv').empty();")
.append(" if (requestDiagnostics.length > 0) {")
.append(" haveGotAppDiagnostic = true;")
.append(" tableData = getTableDataFromObjectArray(requestDiagnostics,")
.append(" ['requestPriority', 'allocationRequestId', 'allocationState',")
.append(" 'diagnostic']);")
.append(" $('#diagnosticsTableDiv').append('<table ")
.append(" id=\"diagnosticsTable\"></table>');")
.append(" $('#diagnosticsTable').dataTable( {")
.append(" 'aaData': tableData,")
.append(" 'aoColumns': [")
.append(" { 'sTitle': 'Priority' },")
.append(" { 'sTitle': 'AllocationRequestId' },")
.append(" { 'sTitle': 'AllocationState' },")
.append(" { 'sTitle': 'DiagnosticSummary' }")
.append(" ],")
.append(" bJQueryUI:true, sPaginationType: 'full_numbers',")
.append(" iDisplayLength:20, aLengthMenu:[20, 40, 60, 80, 100]")
.append(" });")
.append(" }")
.append(" if (haveGotAppDiagnostic) {")
.append(" $('#refreshDiagnosticsBtn').attr('disabled',false);")
.append(" $('#diagnosticsUpdateTime').html('Updated at ' + dateTime);")
.append(" } else {")
.append(" $('#diagnosticsUpdateTime').html('');")
.append(" if (refresh) {")
.append(" refreshSchedulerDiagnostics();")
.append(" }")
.append(" }")
.append("}")
.append("function handleRequestFailure(data){")
.append(" alert('Request app activities REST API failed.');")
.append(" console.log(data);")
.append("}")
.append("function handleRefreshAppActDone(data){")
.append(" refresh = true;")
.append(" setTimeout(function(){")
.append(" queryAppDiagnostics();")
.append(" }, 2000);")
.append("}")
.append("function refreshAppDiagnostics() {")
.append(" $('#refreshDiagnosticsBtn').attr('disabled',true);")
.append(" sendRequest(refreshAppActivitiesURL,handleRefreshAppActDone,")
.append(" handleRequestFailure);")
.append("}")
.append("function queryAppDiagnostics() {")
.append(" sendRequest(getAppActivitiesURL,handleQueryAppActDone,")
.append(" handleRequestFailure);")
.append("}")
.append("function parseHierarchicalQueue(node, nodeInfos,")
.append(" parentNodePath, partition) {")
.append(" var nodePath = parentNodePath + '/' + node['name'];")
.append(" if (node.hasOwnProperty('name')){")
.append(" if (node['diagnostic'] == undefined || node['diagnostic']")
.append(" .indexOf(ignoreActivityContent) == -1){")
.append(" var nodeInfo = {};")
.append(" nodeInfo['partition'] = partition;")
.append(" nodeInfo['path'] = nodePath;")
.append(" nodeInfo['allocationState'] = node['allocationState'];")
.append(" nodeInfo['diagnostic'] = ")
.append(" node['diagnostic'] == undefined ? '':node['diagnostic'];")
.append(" nodeInfos.push(nodeInfo);")
.append(" }")
.append(" }")
.append(" if (node.hasOwnProperty('children')){")
.append(" var children = getArray(node['children']);")
.append(" $.each(children, function (i, child) {")
.append(" parseHierarchicalQueue(child, nodeInfos, nodePath,")
.append(" partition);")
.append(" });")
.append(" }")
.append("}")
.append("function parseQueueDiagnostics(data) {")
.append(" var nodeInfos = [], dateTime;")
.append(" if(data.hasOwnProperty('dateTime')){")
.append(" dateTime = data['dateTime'];")
.append(" }")
.append(" if(data.hasOwnProperty('allocations')){")
.append(" var allocations = getArray(data['allocations']);")
.append(" $.each(allocations, function (i, allocation) {")
.append(" if (allocation.hasOwnProperty('root')) {")
.append(" var root = allocation['root'];")
.append(" var partition = allocation['partition'];")
.append(" parseHierarchicalQueue(root, nodeInfos, '', partition);")
.append(" }")
.append(" });")
.append(" }")
.append(" return [nodeInfos, dateTime];")
.append("}")
.append("function handleRefreshSchedulerActDone(data){")
.append(" console.log('handleRefreshSchedulerActDone', data);")
.append(" setTimeout(function(){")
.append(" querySchedulerDiagnostics();")
.append(" $('#refreshDiagnosticsBtn').attr('disabled',false);")
.append(" }, 100);")
.append("}")
.append("function handleQuerySchedulerActDone(data){")
.append(" console.log('Scheduler activities:', data);")
.append(" data = data['activities'];")
.append(" var results = parseQueueDiagnostics(data);")
.append(" var nodeInfos = results[0];")
.append(" var dateTime = results[1];")
.append(" $('#diagnosticsTableDiv').empty();")
.append(" if(dateTime != undefined){")
.append(" $('#diagnosticsUpdateTime').html('App diagnostics not found!")
.append(" Got useful scheduler activities updated at '+dateTime);")
.append(" tableData = getTableDataFromObjectArray(nodeInfos, ")
.append(" ['partition', 'path', 'allocationState', 'diagnostic']);")
.append(" $('#diagnosticsTableDiv').append('<table ")
.append(" id=\"diagnosticsTable\"></table>');")
.append(" $('#diagnosticsTable').dataTable({")
.append(" 'aaData': tableData,")
.append(" 'aoColumns': [")
.append(" { 'sTitle': 'Partition' },")
.append(" { 'sTitle': 'SchedulingNode' },")
.append(" { 'sTitle': 'AllocationState' },")
.append(" { 'sTitle': 'Diagnostic' }")
.append(" ],")
.append(" bJQueryUI:true, sPaginationType: 'full_numbers',")
.append(" iDisplayLength:20, aLengthMenu:[20, 40, 60, 80, 100]")
.append(" });")
.append(" } else if(data.hasOwnProperty('diagnostic')){")
.append(" $('#diagnosticsUpdateTime').html(data['diagnostic']);")
.append(" }")
.append(" $('#refreshDiagnosticsBtn').attr('disabled',false);")
.append("}")
.append("function refreshSchedulerDiagnostics() {")
.append(" $('#refreshDiagnosticsBtn').attr('disabled',true);")
.append(" sendRequest(schedulerActivitiesURL,")
.append(" handleRefreshSchedulerActDone,handleRequestFailure);")
.append("}")
.append("function querySchedulerDiagnostics() {")
.append(" sendRequest(schedulerActivitiesURL,")
.append(" handleQuerySchedulerActDone,handleRequestFailure);")
.append("}")
.append("queryAppDiagnostics();").toString();
@Inject
RMAppAttemptBlock(ViewContext ctx, ResourceManager rm, Configuration conf) {
super(null, ctx);
this.rm = rm;
this.conf = conf;
}
private void createResourceRequestsTable(Block html) {
AppInfo app =
new AppInfo(rm, rm.getRMContext().getRMApps()
.get(this.appAttemptId.getApplicationId()), true,
WebAppUtils.getHttpSchemePrefix(conf));
List<ResourceRequestInfo> resourceRequests = app.getResourceRequests();
if (resourceRequests == null || resourceRequests.isEmpty()) {
return;
}
DIV<Hamlet> div = html.div(_INFO_WRAP);
// Requests Table
TBODY<TABLE<DIV<Hamlet>>> tbody = div
.h3("Total Outstanding Resource Requests: "
+ getTotalResource(resourceRequests))
.table("#resourceRequests").thead().tr().th(".priority", "Priority")
.th(".allocationRequestId", "AllocationRequestId")
.th(".resource", "ResourceName").th(".capacity", "Capability")
.th(".containers", "NumContainers")
.th(".relaxlocality", "RelaxLocality")
.th(".labelexpression", "NodeLabelExpression")
.th(".executiontype", "ExecutionType")
.th(".allocationTags", "AllocationTags")
.th(".placementConstraint", "PlacementConstraint").__().__().tbody();
StringBuilder resourceRequestTableData = new StringBuilder("[\n");
for (ResourceRequestInfo resourceRequest : resourceRequests) {
if (resourceRequest.getNumContainers() == 0) {
continue;
}
resourceRequestTableData.append("[\"")
.append(String.valueOf(resourceRequest.getPriority())).append("\",\"")
.append(String.valueOf(resourceRequest.getAllocationRequestId()))
.append("\",\"")
.append(resourceRequest.getResourceName() == null ? "N/A"
: resourceRequest.getResourceName())
.append("\",\"")
.append(StringEscapeUtils.escapeEcmaScript(StringEscapeUtils
.escapeHtml4(String.valueOf(resourceRequest.getCapability()))))
.append("\",\"")
.append(String.valueOf(resourceRequest.getNumContainers()))
.append("\",\"")
.append(String.valueOf(resourceRequest.getRelaxLocality()))
.append("\",\"")
.append(resourceRequest.getNodeLabelExpression() == null ? "N/A"
: resourceRequest.getNodeLabelExpression())
.append("\",\"")
.append(resourceRequest.getExecutionTypeRequest() == null ? "N/A"
: resourceRequest.getExecutionTypeRequest().getExecutionType())
.append("\",\"")
.append(resourceRequest.getAllocationTags() == null ? "N/A" :
StringUtils.join(resourceRequest.getAllocationTags(), ","))
.append("\",\"")
.append(resourceRequest.getPlacementConstraint() == null ? "N/A"
: resourceRequest.getPlacementConstraint())
.append("\"],\n");
}
if (resourceRequestTableData
.charAt(resourceRequestTableData.length() - 2) == ',') {
resourceRequestTableData.delete(resourceRequestTableData.length() - 2,
resourceRequestTableData.length() - 1);
}
resourceRequestTableData.append("]");
html.script().$type("text/javascript")
.__("var resourceRequestsTableData=" + resourceRequestTableData).__();
tbody.__().__();
// create diagnostics table when CS is enabled
createDiagnosticsTable(html, div);
div.__();
}
private Resource getTotalResource(List<ResourceRequestInfo> requests) {
Resource totalResource = Resource.newInstance(0, 0);
if (requests == null) {
return totalResource;
}
for (ResourceRequestInfo request : requests) {
if (request.getNumContainers() == 0) {
continue;
}
if (request.getResourceName() == null || request.getResourceName()
.equals(ResourceRequest.ANY)) {
Resources.addTo(
totalResource,
Resources.multiply(request.getCapability().getResource(),
request.getNumContainers()));
}
}
return totalResource;
}
private void createContainerLocalityTable(Block html) {
RMAppAttemptMetrics attemptMetrics = null;
RMAppAttempt attempt = getRMAppAttempt();
if (attempt != null) {
attemptMetrics = attempt.getRMAppAttemptMetrics();
}
if (attemptMetrics == null) {
return;
}
DIV<Hamlet> div = html.div(_INFO_WRAP);
TABLE<DIV<Hamlet>> table =
div.h3(
"Total Allocated Containers: "
+ attemptMetrics.getTotalAllocatedContainers()).h3("Each table cell"
+ " represents the number of NodeLocal/RackLocal/OffSwitch containers"
+ " satisfied by NodeLocal/RackLocal/OffSwitch resource requests.").table(
"#containerLocality");
table.
tr().
th(_TH, "").
th(_TH, "Node Local Request").
th(_TH, "Rack Local Request").
th(_TH, "Off Switch Request").
__();
String[] containersType =
{ "Num Node Local Containers (satisfied by)", "Num Rack Local Containers (satisfied by)",
"Num Off Switch Containers (satisfied by)" };
boolean odd = false;
for (int i = 0; i < attemptMetrics.getLocalityStatistics().length; i++) {
table.tr((odd = !odd) ? _ODD : _EVEN).td(containersType[i])
.td(String.valueOf(attemptMetrics.getLocalityStatistics()[i][0]))
.td(i == 0 ? "" : String.valueOf(attemptMetrics.getLocalityStatistics()[i][1]))
.td(i <= 1 ? "" : String.valueOf(attemptMetrics.getLocalityStatistics()[i][2])).__();
}
table.__();
div.__();
}
private boolean isApplicationInFinalState(YarnApplicationAttemptState state) {
return state == YarnApplicationAttemptState.FINISHED
|| state == YarnApplicationAttemptState.FAILED
|| state == YarnApplicationAttemptState.KILLED;
}
@Override
protected void createAttemptHeadRoomTable(Block html) {
RMAppAttempt attempt = getRMAppAttempt();
if (attempt != null) {
if (!isApplicationInFinalState(YarnApplicationAttemptState
.valueOf(attempt.getAppAttemptState().toString()))) {
RMAppAttemptMetrics metrics = attempt.getRMAppAttemptMetrics();
DIV<Hamlet> pdiv = html.__(InfoBlock.class).div(_INFO_WRAP);
info("Application Attempt Overview").clear();
info("Application Attempt Metrics").__(
"Application Attempt Headroom : ", metrics == null ? "N/A" :
metrics.getApplicationAttemptHeadroom());
pdiv.__();
}
}
}
private RMAppAttempt getRMAppAttempt() {
ApplicationId appId = this.appAttemptId.getApplicationId();
RMAppAttempt attempt = null;
RMApp rmApp = rm.getRMContext().getRMApps().get(appId);
if (rmApp != null) {
attempt = rmApp.getAppAttempts().get(appAttemptId);
}
return attempt;
}
protected void generateOverview(ApplicationAttemptReport appAttemptReport,
Collection<ContainerReport> containers, AppAttemptInfo appAttempt,
String node) {
RMAppAttempt rmAppAttempt = getRMAppAttempt();
// nodes which are blacklisted by the application
String appBlacklistedNodes =
getNodeString(rmAppAttempt.getBlacklistedNodes());
// nodes which are blacklisted by the RM for AM launches
String rmBlackListedNodes =
getNodeString(rmAppAttempt.getAMBlacklistManager()
.getBlacklistUpdates().getBlacklistAdditions());
info("Application Attempt Overview")
.__(
"Application Attempt State:",
appAttempt.getAppAttemptState() == null ? UNAVAILABLE : appAttempt
.getAppAttemptState())
.__("Started:", Times.format(appAttempt.getStartedTime()))
.__("Elapsed:",
org.apache.hadoop.util.StringUtils.formatTime(Times.elapsed(
appAttempt.getStartedTime(), appAttempt.getFinishedTime())))
.__(
"AM Container:",
appAttempt.getAmContainerId() == null || containers == null
|| !hasAMContainer(appAttemptReport.getAMContainerId(), containers)
? null : root_url("container", appAttempt.getAmContainerId()),
appAttempt.getAmContainerId() == null ? "N/A" :
String.valueOf(appAttempt.getAmContainerId()))
.__("Node:", node)
.__(
"Tracking URL:",
appAttempt.getTrackingUrl() == null
|| appAttempt.getTrackingUrl().equals(UNAVAILABLE) ? null
: root_url(appAttempt.getTrackingUrl()),
appAttempt.getTrackingUrl() == null
|| appAttempt.getTrackingUrl().equals(UNAVAILABLE)
? "Unassigned"
: appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FINISHED
|| appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FAILED
|| appAttempt.getAppAttemptState() == YarnApplicationAttemptState.KILLED
? "History" : "ApplicationMaster")
.__(
"Diagnostics Info:",
appAttempt.getDiagnosticsInfo() == null ? "" : appAttempt
.getDiagnosticsInfo())
.__("Nodes blacklisted by the application:", appBlacklistedNodes)
.__("Nodes blacklisted by the system:", rmBlackListedNodes);
}
private String getNodeString(Collection<String> nodes) {
String concatinatedString = "-";
if (null != nodes && !nodes.isEmpty()) {
concatinatedString = StringUtils.join(nodes, ", ");
}
return concatinatedString;
}
@Override
protected void createTablesForAttemptMetrics(Block html) {
createContainerLocalityTable(html);
createResourceRequestsTable(html);
}
@Override
protected List<ContainerReport> getContainers(
final GetContainersRequest request) throws YarnException, IOException {
return rm.getClientRMService().getContainers(request).getContainerList();
}
@Override
protected ApplicationAttemptReport getApplicationAttemptReport(
final GetApplicationAttemptReportRequest request)
throws YarnException, IOException {
return rm.getClientRMService().getApplicationAttemptReport(request)
.getApplicationAttemptReport();
}
private void createDiagnosticsTable(Block html, DIV<Hamlet> parentDiv) {
if (!(rm.getResourceScheduler() instanceof CapacityScheduler)) {
return;
}
String appActivitiesURL =
new StringBuilder().append(RMWSConsts.RM_WEB_SERVICE_PATH).append(
RMWSConsts.SCHEDULER_APP_ACTIVITIES.replace("{appid}",
this.appAttemptId.getApplicationId().toString())).append("?")
.toString();
String refreshAppActivitiesURL = appActivitiesURL + "actions=refresh";
String getAppActivitiesURL = appActivitiesURL
+ "actions=get&groupBy=diagnostic&summarize=true";
String refreshAndGetAppActivitiesURL = appActivitiesURL
+ "actions=refresh&actions=get&groupBy=diagnostic&summarize=true";
String schedulerActivitiesURL =
new StringBuilder().append(RMWSConsts.RM_WEB_SERVICE_PATH)
.append(RMWSConsts.SCHEDULER_ACTIVITIES).append("?")
.append(RMWSConsts.GROUP_BY).append("=diagnostic").toString();
DIV<DIV<Hamlet>> div = parentDiv.div();
div.p().__("Diagnostics in cache ").__("(For more details refer to ")
.a(refreshAndGetAppActivitiesURL, "App Activities").__(" or ")
.a(schedulerActivitiesURL, "Scheduler Activities").__(")").__();
div.button().$id("refreshDiagnosticsBtn")
.$style("border-style: solid; border-color: #000000; border-width: 1px;"
+ " cursor: hand; cursor: pointer; border-radius: 4px")
.$onclick("refreshAppDiagnostics()").b("Refresh").__();
div.p().$id("diagnosticsUpdateTime").__();
div.p().$id("appDiagnostic").__();
div.div("#diagnosticsTableDiv").__();
div.__();
StringBuilder script = new StringBuilder();
script
.append("var refreshAppActivitiesURL = '")
.append(refreshAppActivitiesURL).append("';")
.append("var getAppActivitiesURL = '")
.append(getAppActivitiesURL).append("';")
.append("var schedulerActivitiesURL = '")
.append(schedulerActivitiesURL).append("';")
.append("var ignoreActivityContent = '")
.append("does not need more resource';")
.append(DIAGNOSTICS_SCRIPT_BODY);
html.script().$type("text/javascript").__(script.toString()).__();
}
}