blob: c6f9c0527d266ab67ddea0c8040d74798e25356e [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
* The instance view.
*
* In this view, we show detailed data of vanadium services or nginx servers for
* a single GCE instance.
*
* The page is divided into several sections:
* - We first show a large graph for the main metrics we care about the most,
* such as "vanadium services request latency".
* - We then show various "helper" stats that can help people diagnose problems
* in the main metrics, such as "mounted nodes in mounttable".
* - After that, we show metrics for the GCE instance itself, such as CPU usage,
* disk usage, etc. It also has links to let user ssh into the machine and see
* its log.
* - For vanadium services, it will also show a table for services'
* metadata/buildinfo.
*/
var hg = require('mercury');
var h = require('mercury').h;
var dateformat = require('dateformat');
var Consts = require('../../constants');
var fullGraphComponent = require('../full-graph');
var metricsGroupComponent = require('../metrics-group');
var dataTableComponent = require('../data-table');
var Util = require('../../util');
module.exports = create;
module.exports.render = render;
/** Constructor. */
function create(data) {
if (data === null) {
return null;
}
var instance = data.appState.instanceLevelInstance;
var isVanadiumServices = instance.startsWith('vanadium');
// Main metrics.
// For vanadium services, we show request latency as the main metrics.
// For nginx servers, we show its load.
var mainMetrics = isVanadiumServices ?
data.data.CloudServiceLatency : data.data.NginxLoad;
var mainMetricsTitle = isVanadiumServices ? 'REQUEST LATENCY' : 'SERVER LOAD';
var mainMetricKeys = isVanadiumServices ?
Consts.metricKeys.latency : Consts.metricKeys.nginxLoad;
var sortedMainMetrics = mainMetricKeys.map(function(metric) {
return mainMetrics[metric];
});
// Helper metrics.
// For now, we only have helper metrics for vanadium services, which are
// various stats from mounttable.
var helperMetrics = isVanadiumServices ? data.data.CloudServiceStats : null;
var helperMetricsTitle = isVanadiumServices ? 'STATS' : '';
var helperMetricKeys = isVanadiumServices ? Consts.metricKeys.stats : null;
var sortedHelperMetrics = [];
if (isVanadiumServices) {
sortedHelperMetrics = helperMetricKeys.map(function(metric) {
return helperMetrics[metric];
});
}
// GCE metrics.
var gceMetrics = isVanadiumServices ?
data.data.CloudServiceGCE : data.data.NginxGCE;
var gceMetricsTitle = 'GCE';
var gceMetricKeys = Consts.metricKeys.gce;
var sortedGCEMetrics = gceMetricKeys.map(function(metric) {
return gceMetrics[metric];
});
var instanceId = data.data.GCEInfo.Id;
// Data table for showing vanadium services' metadata/buildinfo.
var dataTableData = data.data.CloudServiceBuildInfo;
var rows = [];
if (!Util.isEmptyObj(dataTableData)) {
rows.push(['SERVICE', 'PRISTINE', 'SNAPSHOT', 'TIME', 'USER', 'LINKS']);
Object.keys(dataTableData).sort().forEach(function(serviceName) {
var rowData = dataTableData[serviceName];
var curRow = [
Consts.getDisplayName(serviceName),
rowData.IsPristine, rowData.Snapshot,
dateformat(new Date(rowData.Time * 1000), 'yyyymmdd-HH:MM'),
rowData.User,
h('a', {
href: genLogsLink(instanceId, 'v-' + rowData.ServiceName + '.info'),
target: '_blank'
}, 'log')];
rows.push(curRow);
});
}
// These two observables keep track of which non-main metric the mouse cursor
// is currently hovering over, as well as its relative X position.
//
// When a non-main metric is hovered over, we will overlay its data points in
// the main metrics graph for easier comparison. We also render a "mouse line"
// across all graphs.
var hoveredMetric = hg.struct({});
var mouseOffsetFactor = hg.value(-1);
var state = hg.state({
data: data.data,
appState: hg.struct(data.appState),
mainMetricsGraph: fullGraphComponent({
title: mainMetricsTitle,
collectionTimestamp: data.collectionTimestamp,
metrics: sortedMainMetrics,
mouseOffsetFactor: mouseOffsetFactor,
hoveredMetric: hoveredMetric
}),
helperMetricsGroup: isVanadiumServices ? metricsGroupComponent({
title: helperMetricsTitle,
metrics: sortedHelperMetrics,
mouseOffsetFactor: mouseOffsetFactor,
hoveredMetric: hoveredMetric
}) : null,
gceMetricsGroup: metricsGroupComponent({
title: gceMetricsTitle,
metrics: sortedGCEMetrics,
mouseOffsetFactor: mouseOffsetFactor,
hoveredMetric: hoveredMetric,
links: [
{
name: 'ssh',
link: genCloudSSHLink(data.appState.instanceLevelZone, instance)
},
{
name: 'log',
link: genLogsLink(instanceId, '')
}
],
}),
dataTable: rows.length > 0 ? dataTableComponent({
title: 'BUILD INFO',
rows: rows
}) : null
});
return state;
}
/** The main render function. */
function render(state) {
var items = [
fullGraphComponent.render(state.mainMetricsGraph)
];
if (state.helperMetricsGroup) {
items.push(metricsGroupComponent.render(state.helperMetricsGroup));
}
items.push(metricsGroupComponent.render(state.gceMetricsGroup));
if (state.dataTable) {
items.push(dataTableComponent.render(state.dataTable));
}
return h('div.instance-view', items);
}
function genCloudSSHLink(zone, instance) {
return 'https://cloudssh.developers.google.com/projects/' +
'vanadium-production/zones/' + zone +
'/instances/' + instance + '?authuser=0&hl=en_US';
}
function genLogsLink(instanceId, logName) {
return 'https://pantheon.corp.google.com/project/vanadium-production/logs?' +
'service=compute.googleapis.com&key1=instance&key2=' + instanceId +
'&logName=' + logName +
'&minLogLevel=0&expandAll=false&timezone=America%2FLos_Angeles';
}