You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@storm.apache.org by bo...@apache.org on 2014/06/04 02:33:24 UTC
[01/13] STORM-205. Add REST API to Storm UI.
Repository: incubator-storm
Updated Branches:
refs/heads/master eee8b243c -> 6dae731c8
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/js/mustache.js
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/js/mustache.js b/storm-core/src/ui/public/js/mustache.js
new file mode 100644
index 0000000..3a84b74
--- /dev/null
+++ b/storm-core/src/ui/public/js/mustache.js
@@ -0,0 +1,570 @@
+/*!
+ * mustache.js - Logic-less {{mustache}} templates with JavaScript
+ * http://github.com/janl/mustache.js
+ */
+
+/*global define: false*/
+
+(function (root, factory) {
+ if (typeof exports === "object" && exports) {
+ factory(exports); // CommonJS
+ } else {
+ var mustache = {};
+ factory(mustache);
+ if (typeof define === "function" && define.amd) {
+ define(mustache); // AMD
+ } else {
+ root.Mustache = mustache; // <script>
+ }
+ }
+}(this, function (mustache) {
+
+ var whiteRe = /\s*/;
+ var spaceRe = /\s+/;
+ var nonSpaceRe = /\S/;
+ var eqRe = /\s*=/;
+ var curlyRe = /\s*\}/;
+ var tagRe = /#|\^|\/|>|\{|&|=|!/;
+
+ // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
+ // See https://github.com/janl/mustache.js/issues/189
+ var RegExp_test = RegExp.prototype.test;
+ function testRegExp(re, string) {
+ return RegExp_test.call(re, string);
+ }
+
+ function isWhitespace(string) {
+ return !testRegExp(nonSpaceRe, string);
+ }
+
+ var Object_toString = Object.prototype.toString;
+ var isArray = Array.isArray || function (object) {
+ return Object_toString.call(object) === '[object Array]';
+ };
+
+ function isFunction(object) {
+ return typeof object === 'function';
+ }
+
+ function escapeRegExp(string) {
+ return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
+ }
+
+ var entityMap = {
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ '"': '"',
+ "'": ''',
+ "/": '/'
+ };
+
+ function escapeHtml(string) {
+ return String(string).replace(/[&<>"'\/]/g, function (s) {
+ return entityMap[s];
+ });
+ }
+
+ function escapeTags(tags) {
+ if (!isArray(tags) || tags.length !== 2) {
+ throw new Error('Invalid tags: ' + tags);
+ }
+
+ return [
+ new RegExp(escapeRegExp(tags[0]) + "\\s*"),
+ new RegExp("\\s*" + escapeRegExp(tags[1]))
+ ];
+ }
+
+ /**
+ * Breaks up the given `template` string into a tree of tokens. If the `tags`
+ * argument is given here it must be an array with two string values: the
+ * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
+ * course, the default is to use mustaches (i.e. mustache.tags).
+ *
+ * A token is an array with at least 4 elements. The first element is the
+ * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
+ * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
+ * all template text that appears outside a symbol this element is "text".
+ *
+ * The second element of a token is its "value". For mustache tags this is
+ * whatever else was inside the tag besides the opening symbol. For text tokens
+ * this is the text itself.
+ *
+ * The third and fourth elements of the token are the start and end indices
+ * in the original template of the token, respectively.
+ *
+ * Tokens that are the root node of a subtree contain two more elements: an
+ * array of tokens in the subtree and the index in the original template at which
+ * the closing tag for that section begins.
+ */
+ function parseTemplate(template, tags) {
+ tags = tags || mustache.tags;
+ template = template || '';
+
+ if (typeof tags === 'string') {
+ tags = tags.split(spaceRe);
+ }
+
+ var tagRes = escapeTags(tags);
+ var scanner = new Scanner(template);
+
+ var sections = []; // Stack to hold section tokens
+ var tokens = []; // Buffer to hold the tokens
+ var spaces = []; // Indices of whitespace tokens on the current line
+ var hasTag = false; // Is there a {{tag}} on the current line?
+ var nonSpace = false; // Is there a non-space char on the current line?
+
+ // Strips all whitespace tokens array for the current line
+ // if there was a {{#tag}} on it and otherwise only space.
+ function stripSpace() {
+ if (hasTag && !nonSpace) {
+ while (spaces.length) {
+ delete tokens[spaces.pop()];
+ }
+ } else {
+ spaces = [];
+ }
+
+ hasTag = false;
+ nonSpace = false;
+ }
+
+ var start, type, value, chr, token, openSection;
+ while (!scanner.eos()) {
+ start = scanner.pos;
+
+ // Match any text between tags.
+ value = scanner.scanUntil(tagRes[0]);
+ if (value) {
+ for (var i = 0, len = value.length; i < len; ++i) {
+ chr = value.charAt(i);
+
+ if (isWhitespace(chr)) {
+ spaces.push(tokens.length);
+ } else {
+ nonSpace = true;
+ }
+
+ tokens.push(['text', chr, start, start + 1]);
+ start += 1;
+
+ // Check for whitespace on the current line.
+ if (chr === '\n') {
+ stripSpace();
+ }
+ }
+ }
+
+ // Match the opening tag.
+ if (!scanner.scan(tagRes[0])) break;
+ hasTag = true;
+
+ // Get the tag type.
+ type = scanner.scan(tagRe) || 'name';
+ scanner.scan(whiteRe);
+
+ // Get the tag value.
+ if (type === '=') {
+ value = scanner.scanUntil(eqRe);
+ scanner.scan(eqRe);
+ scanner.scanUntil(tagRes[1]);
+ } else if (type === '{') {
+ value = scanner.scanUntil(new RegExp('\\s*' + escapeRegExp('}' + tags[1])));
+ scanner.scan(curlyRe);
+ scanner.scanUntil(tagRes[1]);
+ type = '&';
+ } else {
+ value = scanner.scanUntil(tagRes[1]);
+ }
+
+ // Match the closing tag.
+ if (!scanner.scan(tagRes[1])) {
+ throw new Error('Unclosed tag at ' + scanner.pos);
+ }
+
+ token = [ type, value, start, scanner.pos ];
+ tokens.push(token);
+
+ if (type === '#' || type === '^') {
+ sections.push(token);
+ } else if (type === '/') {
+ // Check section nesting.
+ openSection = sections.pop();
+
+ if (!openSection) {
+ throw new Error('Unopened section "' + value + '" at ' + start);
+ }
+ if (openSection[1] !== value) {
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
+ }
+ } else if (type === 'name' || type === '{' || type === '&') {
+ nonSpace = true;
+ } else if (type === '=') {
+ // Set the tags for the next time around.
+ tagRes = escapeTags(tags = value.split(spaceRe));
+ }
+ }
+
+ // Make sure there are no open sections when we're done.
+ openSection = sections.pop();
+ if (openSection) {
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
+ }
+
+ return nestTokens(squashTokens(tokens));
+ }
+
+ /**
+ * Combines the values of consecutive text tokens in the given `tokens` array
+ * to a single token.
+ */
+ function squashTokens(tokens) {
+ var squashedTokens = [];
+
+ var token, lastToken;
+ for (var i = 0, len = tokens.length; i < len; ++i) {
+ token = tokens[i];
+
+ if (token) {
+ if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
+ lastToken[1] += token[1];
+ lastToken[3] = token[3];
+ } else {
+ squashedTokens.push(token);
+ lastToken = token;
+ }
+ }
+ }
+
+ return squashedTokens;
+ }
+
+ /**
+ * Forms the given array of `tokens` into a nested tree structure where
+ * tokens that represent a section have two additional items: 1) an array of
+ * all tokens that appear in that section and 2) the index in the original
+ * template that represents the end of that section.
+ */
+ function nestTokens(tokens) {
+ var nestedTokens = [];
+ var collector = nestedTokens;
+ var sections = [];
+
+ var token, section;
+ for (var i = 0, len = tokens.length; i < len; ++i) {
+ token = tokens[i];
+
+ switch (token[0]) {
+ case '#':
+ case '^':
+ collector.push(token);
+ sections.push(token);
+ collector = token[4] = [];
+ break;
+ case '/':
+ section = sections.pop();
+ section[5] = token[2];
+ collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
+ break;
+ default:
+ collector.push(token);
+ }
+ }
+
+ return nestedTokens;
+ }
+
+ /**
+ * A simple string scanner that is used by the template parser to find
+ * tokens in template strings.
+ */
+ function Scanner(string) {
+ this.string = string;
+ this.tail = string;
+ this.pos = 0;
+ }
+
+ /**
+ * Returns `true` if the tail is empty (end of string).
+ */
+ Scanner.prototype.eos = function () {
+ return this.tail === "";
+ };
+
+ /**
+ * Tries to match the given regular expression at the current position.
+ * Returns the matched text if it can match, the empty string otherwise.
+ */
+ Scanner.prototype.scan = function (re) {
+ var match = this.tail.match(re);
+
+ if (match && match.index === 0) {
+ var string = match[0];
+ this.tail = this.tail.substring(string.length);
+ this.pos += string.length;
+ return string;
+ }
+
+ return "";
+ };
+
+ /**
+ * Skips all text until the given regular expression can be matched. Returns
+ * the skipped string, which is the entire tail if no match can be made.
+ */
+ Scanner.prototype.scanUntil = function (re) {
+ var index = this.tail.search(re), match;
+
+ switch (index) {
+ case -1:
+ match = this.tail;
+ this.tail = "";
+ break;
+ case 0:
+ match = "";
+ break;
+ default:
+ match = this.tail.substring(0, index);
+ this.tail = this.tail.substring(index);
+ }
+
+ this.pos += match.length;
+
+ return match;
+ };
+
+ /**
+ * Represents a rendering context by wrapping a view object and
+ * maintaining a reference to the parent context.
+ */
+ function Context(view, parentContext) {
+ this.view = view == null ? {} : view;
+ this.cache = { '.': this.view };
+ this.parent = parentContext;
+ }
+
+ /**
+ * Creates a new context using the given view with this context
+ * as the parent.
+ */
+ Context.prototype.push = function (view) {
+ return new Context(view, this);
+ };
+
+ /**
+ * Returns the value of the given name in this context, traversing
+ * up the context hierarchy if the value is absent in this context's view.
+ */
+ Context.prototype.lookup = function (name) {
+ var value;
+ if (name in this.cache) {
+ value = this.cache[name];
+ } else {
+ var context = this;
+
+ while (context) {
+ if (name.indexOf('.') > 0) {
+ value = context.view;
+
+ var names = name.split('.'), i = 0;
+ while (value != null && i < names.length) {
+ value = value[names[i++]];
+ }
+ } else {
+ value = context.view[name];
+ }
+
+ if (value != null) break;
+
+ context = context.parent;
+ }
+
+ this.cache[name] = value;
+ }
+
+ if (isFunction(value)) {
+ value = value.call(this.view);
+ }
+
+ return value;
+ };
+
+ /**
+ * A Writer knows how to take a stream of tokens and render them to a
+ * string, given a context. It also maintains a cache of templates to
+ * avoid the need to parse the same template twice.
+ */
+ function Writer() {
+ this.cache = {};
+ }
+
+ /**
+ * Clears all cached templates in this writer.
+ */
+ Writer.prototype.clearCache = function () {
+ this.cache = {};
+ };
+
+ /**
+ * Parses and caches the given `template` and returns the array of tokens
+ * that is generated from the parse.
+ */
+ Writer.prototype.parse = function (template, tags) {
+ var cache = this.cache;
+ var tokens = cache[template];
+
+ if (tokens == null) {
+ tokens = cache[template] = parseTemplate(template, tags);
+ }
+
+ return tokens;
+ };
+
+ /**
+ * High-level method that is used to render the given `template` with
+ * the given `view`.
+ *
+ * The optional `partials` argument may be an object that contains the
+ * names and templates of partials that are used in the template. It may
+ * also be a function that is used to load partial templates on the fly
+ * that takes a single argument: the name of the partial.
+ */
+ Writer.prototype.render = function (template, view, partials) {
+ var tokens = this.parse(template);
+ var context = (view instanceof Context) ? view : new Context(view);
+ return this.renderTokens(tokens, context, partials, template);
+ };
+
+ /**
+ * Low-level method that renders the given array of `tokens` using
+ * the given `context` and `partials`.
+ *
+ * Note: The `originalTemplate` is only ever used to extract the portion
+ * of the original template that was contained in a higher-order section.
+ * If the template doesn't use higher-order sections, this argument may
+ * be omitted.
+ */
+ Writer.prototype.renderTokens = function (tokens, context, partials, originalTemplate) {
+ var buffer = '';
+
+ // This function is used to render an arbitrary template
+ // in the current context by higher-order sections.
+ var self = this;
+ function subRender(template) {
+ return self.render(template, context, partials);
+ }
+
+ var token, value;
+ for (var i = 0, len = tokens.length; i < len; ++i) {
+ token = tokens[i];
+
+ switch (token[0]) {
+ case '#':
+ value = context.lookup(token[1]);
+ if (!value) continue;
+
+ if (isArray(value)) {
+ for (var j = 0, jlen = value.length; j < jlen; ++j) {
+ buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
+ }
+ } else if (typeof value === 'object' || typeof value === 'string') {
+ buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
+ } else if (isFunction(value)) {
+ if (typeof originalTemplate !== 'string') {
+ throw new Error('Cannot use higher-order sections without the original template');
+ }
+
+ // Extract the portion of the original template that the section contains.
+ value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
+
+ if (value != null) buffer += value;
+ } else {
+ buffer += this.renderTokens(token[4], context, partials, originalTemplate);
+ }
+
+ break;
+ case '^':
+ value = context.lookup(token[1]);
+
+ // Use JavaScript's definition of falsy. Include empty arrays.
+ // See https://github.com/janl/mustache.js/issues/186
+ if (!value || (isArray(value) && value.length === 0)) {
+ buffer += this.renderTokens(token[4], context, partials, originalTemplate);
+ }
+
+ break;
+ case '>':
+ if (!partials) continue;
+ value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
+ if (value != null) buffer += this.renderTokens(this.parse(value), context, partials, value);
+ break;
+ case '&':
+ value = context.lookup(token[1]);
+ if (value != null) buffer += value;
+ break;
+ case 'name':
+ value = context.lookup(token[1]);
+ if (value != null) buffer += mustache.escape(value);
+ break;
+ case 'text':
+ buffer += token[1];
+ break;
+ }
+ }
+
+ return buffer;
+ };
+
+ mustache.name = "mustache.js";
+ mustache.version = "0.8.1";
+ mustache.tags = [ "{{", "}}" ];
+
+ // All high-level mustache.* functions use this writer.
+ var defaultWriter = new Writer();
+
+ /**
+ * Clears all cached templates in the default writer.
+ */
+ mustache.clearCache = function () {
+ return defaultWriter.clearCache();
+ };
+
+ /**
+ * Parses and caches the given template in the default writer and returns the
+ * array of tokens it contains. Doing this ahead of time avoids the need to
+ * parse templates on the fly as they are rendered.
+ */
+ mustache.parse = function (template, tags) {
+ return defaultWriter.parse(template, tags);
+ };
+
+ /**
+ * Renders the `template` with the given `view` and `partials` using the
+ * default writer.
+ */
+ mustache.render = function (template, view, partials) {
+ return defaultWriter.render(template, view, partials);
+ };
+
+ // This is here for backwards compatibility with 0.4.x.
+ mustache.to_html = function (template, view, partials, send) {
+ var result = mustache.render(template, view, partials);
+
+ if (isFunction(send)) {
+ send(result);
+ } else {
+ return result;
+ }
+ };
+
+ // Export the escaping function so that the user may override it.
+ // See https://github.com/janl/mustache.js/issues/244
+ mustache.escape = escapeHtml;
+
+ // Export these mainly for testing, but also for advanced usage.
+ mustache.Scanner = Scanner;
+ mustache.Context = Context;
+ mustache.Writer = Writer;
+
+}));
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/js/purl.js
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/js/purl.js b/storm-core/src/ui/public/js/purl.js
new file mode 100644
index 0000000..b5799c6
--- /dev/null
+++ b/storm-core/src/ui/public/js/purl.js
@@ -0,0 +1,267 @@
+/*
+ * Purl (A JavaScript URL parser) v2.3.1
+ * Developed and maintanined by Mark Perkins, mark@allmarkedup.com
+ * Source repository: https://github.com/allmarkedup/jQuery-URL-Parser
+ * Licensed under an MIT-style license. See https://github.com/allmarkedup/jQuery-URL-Parser/blob/master/LICENSE for details.
+ */
+
+;(function(factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(factory);
+ } else {
+ window.purl = factory();
+ }
+})(function() {
+
+ var tag2attr = {
+ a : 'href',
+ img : 'src',
+ form : 'action',
+ base : 'href',
+ script : 'src',
+ iframe : 'src',
+ link : 'href',
+ embed : 'src',
+ object : 'data'
+ },
+
+ key = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'], // keys available to query
+
+ aliases = { 'anchor' : 'fragment' }, // aliases for backwards compatability
+
+ parser = {
+ strict : /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, //less intuitive, more accurate to the specs
+ loose : /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs
+ },
+
+ isint = /^[0-9]+$/;
+
+ function parseUri( url, strictMode ) {
+ var str = decodeURI( url ),
+ res = parser[ strictMode || false ? 'strict' : 'loose' ].exec( str ),
+ uri = { attr : {}, param : {}, seg : {} },
+ i = 14;
+
+ while ( i-- ) {
+ uri.attr[ key[i] ] = res[i] || '';
+ }
+
+ // build query and fragment parameters
+ uri.param['query'] = parseString(uri.attr['query']);
+ uri.param['fragment'] = parseString(uri.attr['fragment']);
+
+ // split path and fragement into segments
+ uri.seg['path'] = uri.attr.path.replace(/^\/+|\/+$/g,'').split('/');
+ uri.seg['fragment'] = uri.attr.fragment.replace(/^\/+|\/+$/g,'').split('/');
+
+ // compile a 'base' domain attribute
+ uri.attr['base'] = uri.attr.host ? (uri.attr.protocol ? uri.attr.protocol+'://'+uri.attr.host : uri.attr.host) + (uri.attr.port ? ':'+uri.attr.port : '') : '';
+
+ return uri;
+ }
+
+ function getAttrName( elm ) {
+ var tn = elm.tagName;
+ if ( typeof tn !== 'undefined' ) return tag2attr[tn.toLowerCase()];
+ return tn;
+ }
+
+ function promote(parent, key) {
+ if (parent[key].length === 0) return parent[key] = {};
+ var t = {};
+ for (var i in parent[key]) t[i] = parent[key][i];
+ parent[key] = t;
+ return t;
+ }
+
+ function parse(parts, parent, key, val) {
+ var part = parts.shift();
+ if (!part) {
+ if (isArray(parent[key])) {
+ parent[key].push(val);
+ } else if ('object' == typeof parent[key]) {
+ parent[key] = val;
+ } else if ('undefined' == typeof parent[key]) {
+ parent[key] = val;
+ } else {
+ parent[key] = [parent[key], val];
+ }
+ } else {
+ var obj = parent[key] = parent[key] || [];
+ if (']' == part) {
+ if (isArray(obj)) {
+ if ('' !== val) obj.push(val);
+ } else if ('object' == typeof obj) {
+ obj[keys(obj).length] = val;
+ } else {
+ obj = parent[key] = [parent[key], val];
+ }
+ } else if (~part.indexOf(']')) {
+ part = part.substr(0, part.length - 1);
+ if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
+ parse(parts, obj, part, val);
+ // key
+ } else {
+ if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
+ parse(parts, obj, part, val);
+ }
+ }
+ }
+
+ function merge(parent, key, val) {
+ if (~key.indexOf(']')) {
+ var parts = key.split('[');
+ parse(parts, parent, 'base', val);
+ } else {
+ if (!isint.test(key) && isArray(parent.base)) {
+ var t = {};
+ for (var k in parent.base) t[k] = parent.base[k];
+ parent.base = t;
+ }
+ if (key !== '') {
+ set(parent.base, key, val);
+ }
+ }
+ return parent;
+ }
+
+ function parseString(str) {
+ return reduce(String(str).split(/&|;/), function(ret, pair) {
+ try {
+ pair = decodeURIComponent(pair.replace(/\+/g, ' '));
+ } catch(e) {
+ // ignore
+ }
+ var eql = pair.indexOf('='),
+ brace = lastBraceInKey(pair),
+ key = pair.substr(0, brace || eql),
+ val = pair.substr(brace || eql, pair.length);
+
+ val = val.substr(val.indexOf('=') + 1, val.length);
+
+ if (key === '') {
+ key = pair;
+ val = '';
+ }
+
+ return merge(ret, key, val);
+ }, { base: {} }).base;
+ }
+
+ function set(obj, key, val) {
+ var v = obj[key];
+ if (typeof v === 'undefined') {
+ obj[key] = val;
+ } else if (isArray(v)) {
+ v.push(val);
+ } else {
+ obj[key] = [v, val];
+ }
+ }
+
+ function lastBraceInKey(str) {
+ var len = str.length,
+ brace,
+ c;
+ for (var i = 0; i < len; ++i) {
+ c = str[i];
+ if (']' == c) brace = false;
+ if ('[' == c) brace = true;
+ if ('=' == c && !brace) return i;
+ }
+ }
+
+ function reduce(obj, accumulator){
+ var i = 0,
+ l = obj.length >> 0,
+ curr = arguments[2];
+ while (i < l) {
+ if (i in obj) curr = accumulator.call(undefined, curr, obj[i], i, obj);
+ ++i;
+ }
+ return curr;
+ }
+
+ function isArray(vArg) {
+ return Object.prototype.toString.call(vArg) === "[object Array]";
+ }
+
+ function keys(obj) {
+ var key_array = [];
+ for ( var prop in obj ) {
+ if ( obj.hasOwnProperty(prop) ) key_array.push(prop);
+ }
+ return key_array;
+ }
+
+ function purl( url, strictMode ) {
+ if ( arguments.length === 1 && url === true ) {
+ strictMode = true;
+ url = undefined;
+ }
+ strictMode = strictMode || false;
+ url = url || window.location.toString();
+
+ return {
+
+ data : parseUri(url, strictMode),
+
+ // get various attributes from the URI
+ attr : function( attr ) {
+ attr = aliases[attr] || attr;
+ return typeof attr !== 'undefined' ? this.data.attr[attr] : this.data.attr;
+ },
+
+ // return query string parameters
+ param : function( param ) {
+ return typeof param !== 'undefined' ? this.data.param.query[param] : this.data.param.query;
+ },
+
+ // return fragment parameters
+ fparam : function( param ) {
+ return typeof param !== 'undefined' ? this.data.param.fragment[param] : this.data.param.fragment;
+ },
+
+ // return path segments
+ segment : function( seg ) {
+ if ( typeof seg === 'undefined' ) {
+ return this.data.seg.path;
+ } else {
+ seg = seg < 0 ? this.data.seg.path.length + seg : seg - 1; // negative segments count from the end
+ return this.data.seg.path[seg];
+ }
+ },
+
+ // return fragment segments
+ fsegment : function( seg ) {
+ if ( typeof seg === 'undefined' ) {
+ return this.data.seg.fragment;
+ } else {
+ seg = seg < 0 ? this.data.seg.fragment.length + seg : seg - 1; // negative segments count from the end
+ return this.data.seg.fragment[seg];
+ }
+ }
+
+ };
+
+ }
+
+ purl.jQuery = function($){
+ if ($ != null) {
+ $.fn.url = function( strictMode ) {
+ var url = '';
+ if ( this.length ) {
+ url = $(this).attr( getAttrName(this[0]) ) || '';
+ }
+ return purl( url, strictMode );
+ };
+
+ $.url = purl;
+ }
+ };
+
+ purl.jQuery(window.jQuery);
+
+ return purl;
+
+});
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/js/script.js
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/js/script.js b/storm-core/src/ui/public/js/script.js
index e9902ab..ab4a825 100644
--- a/storm-core/src/ui/public/js/script.js
+++ b/storm-core/src/ui/public/js/script.js
@@ -71,7 +71,7 @@ function ensureInt(n) {
function confirmAction(id, name, action, wait, defaultWait) {
var opts = {
type:'POST',
- url:'/topology/' + id + '/' + action
+ url:'/api/topology/' + id + '/' + action
};
if (wait) {
var waitSecs = prompt('Do you really want to ' + action + ' topology "' + name + '"? ' +
@@ -91,7 +91,7 @@ function confirmAction(id, name, action, wait, defaultWait) {
$.ajax(opts).always(function () {
window.location.reload();
}).fail(function () {
- alert("Error while communicating with Nimbus.")
+ alert("Error while communicating with Nimbus.");
});
return false;
@@ -106,4 +106,49 @@ $(function () {
delayIn: 1000
});
}
-})
+});
+
+function formatConfigData(data) {
+ var mustacheFormattedData = {'config':[]};
+ for (var prop in data) {
+ if(data.hasOwnProperty(prop)) {
+ mustacheFormattedData['config'].push({
+ 'key': prop,
+ 'value': data[prop]
+ });
+ }
+ }
+ return mustacheFormattedData;
+}
+
+
+function renderToggleSys(div) {
+ var sys = $.cookies.get("sys") || false;
+ if(sys) {
+ div.append("<span data-original-title=\"Use this to toggle inclusion of storm system components.\" class=\"tip right\"><input onclick=\"toggleSys()\" value=\"Hide System Stats\" type=\"button\"></span>");
+ } else {
+ div.append("<span class=\"tip right\" title=\"Use this to toggle inclusion of storm system components.\"><input onclick=\"toggleSys()\" value=\"Show System Stats\" type=\"button\"></span>");
+ }
+}
+
+function topologyActionJson(id,name,status,msgTimeout) {
+ var jsonData = {};
+ jsonData["id"] = id;
+ jsonData["name"] = name;
+ jsonData["msgTimeout"] = msgTimeout;
+ jsonData["activateStatus"] = (status === "ACTIVE") ? "disabled" : "enabled";
+ jsonData["deactivateStatus"] = (status === "ACTIVE") ? "enabled" : "disabled";
+ jsonData["rebalanceStatus"] = (status === "ACTIVE" || status === "INACTIVE" ) ? "enabled" : "disabled";
+ jsonData["killStatus"] = (status !== "KILLED") ? "enabled" : "disabled";
+ return jsonData;
+}
+
+function topologyActionButton(id,name,status,actionLabel,command,wait,defaultWait) {
+ var buttonData = {};
+ buttonData["buttonStatus"] = status ;
+ buttonData["actionLabel"] = actionLabel;
+ buttonData["command"] = command;
+ buttonData["isWait"] = wait;
+ buttonData["defaultWait"] = defaultWait;
+ return buttonData;
+}
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/templates/component-page-template.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/templates/component-page-template.html b/storm-core/src/ui/public/templates/component-page-template.html
new file mode 100644
index 0000000..9275a82
--- /dev/null
+++ b/storm-core/src/ui/public/templates/component-page-template.html
@@ -0,0 +1,152 @@
+<script id="component-summary-template" type="text/html">
+<h2>Component summary</h2>
+<table><thead><tr><th><span class="tip right" title="The ID assigned to a the Component by the Topology.">Id</span></th><th><span class="tip above" title="The name given to the topology by when it was submitted. Click the name to view the Topology's information.">Topology</span></th><th><span class="tip above" title="Executors are threads in a Worker process.">Executors</span></th><th><span class="tip above" title="A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.">Tasks</span></th></tr></thead>
+<tbody>
+<tr>
+<td>{{id}}</td>
+<td><a href="/topology.html?id={{topologyId}}">{{name}}</a></td>
+<td>{{executors}}</td>
+<td>{{tasks}}</td>
+</tbody>
+</table>
+</script>
+<script id="spout-stats-detail-template" type="text/html">
+<h2>Spout stats</h2>
+<table class="zebra-striped" id="spout-stats-table"><thead><tr><th class="header headerSortDown"><span class="tip right" title="The past period of time for which the statistics apply. Click on a value to set the window for this page.">Window</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted.">Emitted</span></th><th class="header"><span data-original-title="The number of Tuples emitted that sent to one or more bolts." class="tip above">Transferred</span></th><th class="header"><span class="tip above" title="The average time a Tuple "tree" takes to be completely processed by the Topology. A value of 0 is expected if no acking is done.">Complete latency (ms)</span></th><th class="header"><span class="tip above" title="The number of Tuple "trees" successfully processed. A value of 0 is expected if no acking is done.">Acked</span></th><th class="header"><span data-original-title="The number of Tuple "trees" that were e
xplicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done." class="tip left">Failed</span></th></tr></thead>
+<tbody>
+{{#spoutSummary}}
+<tr>
+<td><a href="/component.html?id={{id}}&topology_id={{topologyId}}&window={{window}}">{{windowPretty}}</td>
+<td>{{transferred}}</td>
+<td>{{emitted}}</td>
+<td>{{completeLatency}}</td>
+<td>{{acked}}</td>
+<td>{{failed}}</td>
+</tr>
+{{/spoutSummary}}
+</tbody>
+</script>
+<script id="output-stats-template" type="text/html">
+<h2>Output stats ({{windowHint}})</h2>
+<table class="zebra-striped" id="output-stats-table"><thead><tr><th class="header headerSortDown"><span data-original-title="The name of the Tuple stream given in the Topolgy, or "default" if none was given." class="tip right">Stream</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted.">Emitted</span></th><th class="header"><span data-original-title="The number of Tuples emitted that sent to one or more bolts." class="tip above">Transferred</span></th><th class="header"><span data-original-title="The average time a Tuple "tree" takes to be completely processed by the Topology. A value of 0 is expected if no acking is done." class="tip above">Complete latency (ms)</span></th><th class="header"><span data-original-title="The number of Tuple "trees" successfully processed. A value of 0 is expected if no acking is done." class="tip above">Acked</span></th><th class="header"><span data-original-title="The number of Tuple
"trees" that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done." class="tip left">Failed</span></th></tr></thead>
+<tbody>
+{{#outputStats}}
+<tr>
+<td>{{stream}}</td>
+<td>{{emitted}}</td>
+<td>{{transferred}}</td>
+<td>{{completeLatency}}</td>
+<td>{{acked}}</td>
+<td>{{failed}}</td>
+</tr>
+{{/outputStats}}
+</tbody>
+</table>
+</script>
+<script id="executor-stats-template" type="text/html">
+<h2>Executors ({{windowHint}})</h2>
+<table class="zebra-striped" id="executor-stats-table"><thead><tr><th class="header headerSortDown"><span class="tip right" title="The unique executor ID.">Id</span></th><th class="header"><span class="tip right" title="The length of time an Executor (thread) has been alive.">Uptime</span></th><th class="header"><span class="tip above" title="The hostname reported by the remote host. (Note that this hostname is not the result of a reverse lookup at the Nimbus node.)">Host</span></th><th class="header"><span data-original-title="The port number used by the Worker to which an Executor is assigned. Click on the port number to open the logviewer page for this Worker." class="tip above">Port</span></th><th class="header"><span data-original-title="The number of Tuples emitted." class="tip above">Emitted</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted that sent to one or more bolts.">Transferred</span></th><th class="header"><span class="tip above
" title="The average time a Tuple "tree" takes to be completely processed by the Topology. A value of 0 is expected if no acking is done.">Complete latency (ms)</span></th><th class="header"><span class="tip above" title="The number of Tuple "trees" successfully processed. A value of 0 is expected if no acking is done.">Acked</span></th><th class="header"><span data-original-title="The number of Tuple "trees" that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done." class="tip left">Failed</span></th></tr></thead>
+<tbody>
+{{#executorStats}}
+<tr>
+<td>{{id}}</td>
+<td>{{uptime}}</td>
+<td>{{host}}</td>
+<td><a href="{{workerLogLink}}">{{port}}</a></td>
+<td>{{emitted}}</td>
+<td>{{transferred}}</td>
+<td>{{completeLatency}}</td>
+<td>{{acked}}</td>
+<td>{{failed}}</td>
+</tr>
+{{/executorStats}}
+</tbody>
+</table>
+</script>
+<script id="bolt-stats-template" type="text/html">
+<h2>Bolt stats</h2>
+<table class="zebra-striped" id="bolt-stats-table"><thead><tr><th class="header headerSortDown"><span class="tip right" title="The past period of time for which the statistics apply. Click on a value to set the window for this page.">Window</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted.">Emitted</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted that sent to one or more bolts.">Transferred</span></th><th class="header"><span data-original-title="The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple." class="tip above">Execute latency (ms)</span></th><th class="header"><span class="tip above" title="The number of incoming Tuples processed.">Executed</span></th><th class="header"><span data-original-title="The average time it takes to Ack a Tuple after it is first received. Bolts that join, aggregate or batch may not Ack a tuple unti
l a number of other Tuples have been received." class="tip above">Process latency (ms)</span></th><th class="header"><span data-original-title="The number of Tuples acknowledged by this Bolt." class="tip above">Acked</span></th><th class="header"><span data-original-title="The number of tuples Failed by this Bolt." class="tip left">Failed</span></th></tr></thead>
+<tbody>
+{{#boltStats}}
+<tr>
+<td><a href="/component.html?id={{id}}&topology_id={{topologyId}}&window={{window}}">{{windowPretty}}</td>
+<td>{{emitted}}</td>
+<td>{{transferred}}</td>
+<td>{{executeLatency}}</td>
+<td>{{executed}}</td>
+<td>{{processLatency}}</td>
+<td>{{acked}}</td>
+<td>{{failed}}</td>
+</tr>
+{{/boltStats}}
+</tbody>
+</script>
+<script id="bolt-input-stats-template" type="text/html">
+<h2>Input stats ({{windowHint}})</h2>
+<table class="zebra-striped" id="bolt-input-stats-table"><thead><tr><th class="header headerSortDown"><span class="tip right" title="The ID assigned to a the Component by the Topology.">Component</span></th><th class="header"><span class="tip right" title="The name of the Tuple stream given in the Topolgy, or "default" if none was given.">Stream</span></th><th class="header"><span class="tip above" title="The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple.">Execute latency (ms)</span></th><th class="header"><span class="tip above" title="The number of incoming Tuples processed.">Executed</span></th><th class="header"><span data-original-title="The average time it takes to Ack a Tuple after it is first received. Bolts that join, aggregate or batch may not Ack a tuple until a number of other Tuples have been received." class="tip above">Process latency (ms)</span></th><th class="header"><span class="ti
p above" title="The number of Tuples acknowledged by this Bolt.">Acked</span></th><th class="header"><span data-original-title="The number of tuples Failed by this Bolt." class="tip left">Failed</span></th></tr></thead>
+<tbody>
+{{#inputStats}}
+<tr>
+<td>{{component}}</td>
+<td>{{stream}}</td>
+<td>{{executeLatency}}</td>
+<td>{{executed}}</td>
+<td>{{processLatency}}</td>
+<td>{{acked}}</td>
+<td>{{failed}}</td>
+</tr>
+{{/inputStats}}
+</tbody>
+</table>
+</script>
+<script id="bolt-output-stats-template" type="text/html">
+<h2>Output stats ({{windowHint}})</h2>
+<table class="zebra-striped" id="bolt-output-stats-table"><thead><tr><th class="header headerSortDown"><span class="tip right" title="The name of the Tuple stream given in the Topolgy, or "default" if none was given.">Stream</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted.">Emitted</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted that sent to one or more bolts.">Transferred</span></th></tr></thead>
+<tbody>
+{{#outputStats}}
+<tr>
+<td>{{stream}}</td>
+<td>{{emitted}}</td>
+<td>{{transferred}}</td>
+</tr>
+{{/outputStats}}
+</tbody>
+</table>
+</script>
+<script id="bolt-executor-template" type="text/html">
+<h2>Executors</h2>
+<table class="zebra-striped" id="bolt-executor-table"><thead><tr><th class="header headerSortDown"><span class="tip right" title="The unique executor ID.">Id</span></th><th class="header"><span data-original-title="The length of time an Executor (thread) has been alive." class="tip right">Uptime</span></th><th class="header"><span class="tip above" title="The hostname reported by the remote host. (Note that this hostname is not the result of a reverse lookup at the Nimbus node.)">Host</span></th><th class="header"><span class="tip above" title="The port number used by the Worker to which an Executor is assigned. Click on the port number to open the logviewer page for this Worker.">Port</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted.">Emitted</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted that sent to one or more bolts.">Transferred</span></th><th class="header"><span class="tip above" title="If thi
s is around 1.0, the corresponding Bolt is running as fast as it can, so you may want to increase the Bolt's parallelism. This is (number executed * average execute latency) / measurement time.">Capacity (last 10m)</span></th><th class="header"><span data-original-title="The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple." class="tip above">Execute latency (ms)</span></th><th class="header"><span class="tip above" title="The number of incoming Tuples processed.">Executed</span></th><th class="header"><span data-original-title="The average time it takes to Ack a Tuple after it is first received. Bolts that join, aggregate or batch may not Ack a tuple until a number of other Tuples have been received." class="tip above">Process latency (ms)</span></th><th class="header"><span data-original-title="The number of Tuples acknowledged by this Bolt." class="tip above">Acked</span></th><th class="header"><span data-ori
ginal-title="The number of tuples Failed by this Bolt." class="tip left">Failed</span></th></tr></thead>
+<tbody>
+{{#executorStats}}
+<tr>
+<td>{{id}}}</td>
+<td>{{uptime}}</td>
+<td>{{host}}</td>
+<td><a href="{{workerLogLink}}">{{port}}</a></td>
+<td>{{emitted}}</td>
+<td>{{transferred}}</td>
+<td>{{capacity}}</td>
+<td>{{executeLatency}}</td>
+<td>{{executed}}</td>
+<td>{{processLatency}}</td>
+<td>{{acked}}</td>
+<td>{{failed}}</td>
+</tr>
+{{/executorStats}}
+</tbody>
+</table>
+</script>
+
+<script id="errors-template" type="text/html">
+<h2>Errors</h2>
+<table class="zebra-striped" id="errors-table"><thead><tr><th>Time</th><th>Error</th></tr></thead>
+<tbody>
+{{#errors}}
+<tr>
+<td>{{time}}</td>
+<td>{{error}}</td>
+</tr>
+{{/errors}}
+</tbody>
+</table>
+</script>
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/templates/error-template.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/templates/error-template.html b/storm-core/src/ui/public/templates/error-template.html
new file mode 100644
index 0000000..09f3b76
--- /dev/null
+++ b/storm-core/src/ui/public/templates/error-template.html
@@ -0,0 +1,4 @@
+<script id="error-template" type="text/html">
+<h2>{{error}}</h2>
+<pre>{{errorMessage}}</pre>
+</script>
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/templates/index-page-template.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/templates/index-page-template.html b/storm-core/src/ui/public/templates/index-page-template.html
new file mode 100644
index 0000000..128f2d0
--- /dev/null
+++ b/storm-core/src/ui/public/templates/index-page-template.html
@@ -0,0 +1,62 @@
+<script id="cluster-summary-template" type="text/html">
+<table id="cluster-summary-table"><thead><tr><th><span class="tip right" title="The version of storm installed on the UI node. (Hopefully, this is the same on all storm nodes!)">Version</span></th><th><span class="tip right" title="The duration the current Nimbus instance has been running. (Note that the storm cluster may have been deployed and available for a much longer period than the current Nimbus process has been running.)">Nimbus uptime</span></th><th><span class="tip above" title="The number of nodes in the cluster currently.">Supervisors</span></th><th><span class="tip above" title="Slots are Workers (processes).">Used slots</span></th><th><span class="tip above" title="Slots are Workers (processes).">Free slots</span></th><th><span class="tip above" title="Slots are Workers (processes).">Total slots</span></th><th><span class="tip above" title="Executors are threads in a Worker process.">Executors</span></th><th><span class="tip left" title="A Task is an instance of a Bolt
or Spout. The number of Tasks is almost always equal to the number of Executors.">Tasks</span></th></tr></thead>
+<tbody>
+<tr>
+ <td>{{stormVersion}}</td>
+ <td>{{nimbusUptime}}</td>
+ <td>{{supervisors}}</td>
+ <td>{{slotsUsed}}</td>
+ <td>{{slotsFree}}</td>
+ <td>{{slotsTotal}}</td>
+ <td>{{executorsTotal}}</td>
+ <td>{{tasksTotal}}</td>
+</tr>
+</tbody>
+</table>
+</script>
+<script id="topology-summary-template" type="text/html">
+<table class="zebra-striped" id="topology-summary-table">
+<thead><tr><th><span class="tip right" title="The name given to the topology by when it was submitted. Click the name to view the Topology's information.">Name</span></th><th><span class="tip right" title="The unique ID given to a Topology each time it is launched.">Id</span></th><th><span class="tip above" title="The status can be one of ACTIVE, INACTIVE, KILLED, or REBALANCING.">Status</span></th><th><span class="tip above" title="The time since the Topology was submitted.">Uptime</span></th><th><span class="tip above" title="The number of Workers (processes).">Num workers</span></th><th><span class="tip above" title="Executors are threads in a Worker process.">Num executors</span></th><th><span class="tip above" title="A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.">Num tasks</span></th></tr></thead>
+<tbody>
+{{#topologies}}
+<tr>
+ <td><a href="/topology.html?id={{id}}">{{name}}</a></td>
+ <td>{{id}}</td>
+ <td>{{status}}</td>
+ <td>{{uptime}}</td>
+ <td>{{tasksTotal}}</td>
+ <td>{{workersTotal}}</td>
+ <td>{{executorsTotal}}</td>
+</tr>
+{{/topologies}}
+</tbody>
+</table>
+</script>
+<script id="supervisor-summary-template" type="text/html">
+<table class="zebra-striped" id="supervisor-summary-table"><thead><tr><th><span class="tip right" title="A unique identifier given to a Supervisor when it joins the cluster.">Id</span></th><th><span class="tip above" title="The hostname reported by the remote host. (Note that this hostname is not the result of a reverse lookup at the Nimbus node.)">Host</span></th><th><span class="tip above" title="The length of time a Supervisor has been registered to the cluster.">Uptime</span></th><th><span class="tip above" title="Slots are Workers (processes).">Slots</span></th><th><span class="tip left" title="Slots are Workers (processes).">Used slots</span></th></tr></thead>
+<tbody>
+{{#supervisors}}
+<tr>
+ <td>{{id}}</td>
+ <td>{{host}}</td>
+ <td>{{uptime}}</td>
+ <td>{{slotsTotal}}</td>
+ <td>{{slotsUsed}}</td>
+</tr>
+{{/supervisors}}
+</tbody>
+</table>
+</script>
+
+<script id="configuration-template" type="text/html">
+<table class="zebra-striped" id="nimbus-configuration-table"><thead><tr><th>Key</th><th>Value</th></tr></thead>
+<tbody>
+{{#config}}
+<tr>
+<td>{{key}}</td>
+<td>{{value}}</td>
+</tr>
+{{/config}}
+</tbody>
+</table>
+</script>
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/templates/topology-page-template.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/templates/topology-page-template.html b/storm-core/src/ui/public/templates/topology-page-template.html
new file mode 100644
index 0000000..abe82ee
--- /dev/null
+++ b/storm-core/src/ui/public/templates/topology-page-template.html
@@ -0,0 +1,97 @@
+<script id="topology-summary-template" type="text/html">
+<table id="topology-summary-table">
+<thead><tr><th><span class="tip right" title="The name given to the topology by when it was submitted.">Name</span></th><th><span class="tip right" title="The unique ID given to a Topology each time it is launched.">Id</span></th><th><span class="tip above" title="The status can be one of ACTIVE, INACTIVE, KILLED, or REBALANCING.">Status</span></th><th><span class="tip above" title="The time since the Topology was submitted.">Uptime</span></th><th><span class="tip above" title="The number of Workers (processes).">Num workers</span></th><th><span class="tip above" title="Executors are threads in a Worker process.">Num executors</span></th><th><span class="tip above" title="A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.">Num tasks</span></th></tr></thead>
+<tbody>
+<tr>
+ <td>{{name}}</td>
+ <td>{{id}}</td>
+ <td>{{status}}</td>
+ <td>{{uptime}}</td>
+ <td>{{tasksTotal}}</td>
+ <td>{{workersTotal}}</td>
+ <td>{{executorsTotal}}</td>
+</tr>
+</tbody>
+</table>
+</script>
+<script id="topology-stats-template" type="text/html">
+<h2>Topology stats</h2>
+<table class="zebra-striped" id="topology-stats-table">
+<thead><tr><th><span class="tip right" title="The past period of time for which the statistics apply. Click on a value to set the window for this page.">Window</span></th><th><span class="tip above" title="The number of Tuples emitted.">Emitted</span></th><th><span class="tip above" title="The number of Tuples emitted that sent to one or more bolts.">Transferred</span></th><th><span class="tip above" title="The average time a Tuple "tree" takes to be completely processed by the Topology. A value of 0 is expected if no acking is done.">Complete latency (ms)</span></th><th><span class="tip above" title="The number of Tuple "trees" successfully processed. A value of 0 is expected if no acking is done.">Acked</span></th><th><span class="tip left" title="The number of Tuple "trees" that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done.">Failed</span></th></tr></thead>
+<tbody>
+{{#topologyStats}}
+<tr>
+ <td><a href="/topology.html?id={{id}}&window={{window}}">{{windowPretty}}</td>
+ <td>{{emitted}}</td>
+ <td>{{transferred}}</td>
+ <td>{{completeLatency}}</td>
+ <td>{{acked}}</td>
+ <td>{{failed}}</td>
+</tr>
+{{/topologyStats}}
+</tbody>
+</table>
+</script>
+<script id="topology-configuration-template" type="text/html">
+<h2>Topology Configuration</h2>
+<table class="zebra-striped" id="topology-configuration-table"><thead><tr><th>Key</th><th>Value</th></tr></thead>
+<tbody>
+{{#config}}
+<tr>
+<td>{{key}}</td>
+<td>{{value}}</td>
+</tr>
+{{/config}}
+</tbody>
+</table>
+</script>
+<script id="spout-stats-template" type="text/html">
+<h2>Spouts ({{windowHint}})</h2>
+<table class="zebra-striped" id="spout-stats-table">
+<thead>
+<tr><th class="header headerSortDown"><span data-original-title="The ID assigned to a the Component by the Topology. Click on the name to view the Component's page." class="tip right">Id</span></th><th class="header"><span data-original-title="Executors are threads in a Worker process." class="tip right">Executors</span></th><th class="header"><span class="tip above" title="A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.">Tasks</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted.">Emitted</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted that sent to one or more bolts.">Transferred</span></th><th class="header"><span class="tip above" title="The average time a Tuple "tree" takes to be completely processed by the Topology. A value of 0 is expected if no acking is done.">Complete latency (ms)</span></th><th class="header"><span class=
"tip above" title="The number of Tuple "trees" successfully processed. A value of 0 is expected if no acking is done.">Acked</span></th><th class="header"><span class="tip above" title="The number of Tuple "trees" that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done.">Failed</span></th><th class="header">Last error</th>
+</tr>
+</thead>
+<tbody>
+{{#spouts}}
+<tr>
+<td><a href="/component.html?id={{spoutId}}&topology_id={{id}}">{{spoutId}}</a></td>
+<td>{{executors}}</td>
+<td>{{tasks}}</td>
+<td>{{emitted}}<td>
+<td>{{transferred}}</td>
+<td>{{completeLatency}}</td>
+<td>{{acked}}</td>
+<td>{{failed}}</td>
+<td>{{lastError}}</td>
+{{/spouts}}
+</tbody>
+</table>
+</script>
+<script id="bolt-stats-template" type="text/html">
+<h2>Bolts ({{windowHint}})</h2>
+<table class="zebra-striped" id="bolt-stats-table"><thead>
+<tr><th class="header headerSortDown"><span class="tip right" title="The ID assigned to a the Component by the Topology. Click on the name to view the Component's page.">Id</span></th><th class="header"><span data-original-title="Executors are threads in a Worker process." class="tip right">Executors</span></th><th class="header"><span class="tip above" title="A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.">Tasks</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted.">Emitted</span></th><th class="header"><span class="tip above" title="The number of Tuples emitted that sent to one or more bolts.">Transferred</span></th><th class="header"><span data-original-title="If this is around 1.0, the corresponding Bolt is running as fast as it can, so you may want to increase the Bolt's parallelism. This is (number executed * average execute latency) / measurement time." class="tip above">Cap
acity (last 10m)</span></th><th class="header"><span class="tip above" title="The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple.">Execute latency (ms)</span></th><th class="header"><span class="tip above" title="The number of incoming Tuples processed.">Executed</span></th><th class="header"><span class="tip above" title="The average time it takes to Ack a Tuple after it is first received. Bolts that join, aggregate or batch may not Ack a tuple until a number of other Tuples have been received.">Process latency (ms)</span></th><th class="header"><span class="tip above" title="The number of Tuples acknowledged by this Bolt.">Acked</span></th><th class="header"><span class="tip left" title="The number of tuples Failed by this Bolt.">Failed</span></th><th class="header">Last error</th>
+</tr></thead>
+<tbody>
+{{#bolts}}
+<tr>
+<td><a href="/component.html?id={{boltId}}&topology_id={{id}}">{{boltId}}</a></td>
+<td>{{executors}}</td>
+<td>{{tasks}}</td>
+<td>{{emitted}}</td>
+<td>{{transferred}}</td>
+<td>{{capacity}}</td>
+<td>{{executeLatency}}</td>
+<td>{{executed}}</td>
+<td>{{processLatency}}</td>
+<td>{{acked}}</td>
+<td>{{failed}}</td>
+<td>{{lastError}}</td>
+{{/bolts}}
+</tbody>
+</script>
+
+<script id="topology-actions-template" type="text/html">
+<input {{activateStatus}} onclick="confirmAction('{{id}}', '{{name}}', 'activate', false, 0)" type="button" value="Activate"><input {{deactivateStatus}} onclick="confirmAction('{{id}}', '{{name}}', 'deactivate', false, 0)" type="button" value="Deactivate"><input {{rebalanceStatus}} onclick="confirmAction('{{id}}', '{{name}}', 'rebalance', true, {{msgTimeout}})" type="button" value="Rebalance"><input {{killStatus}} onclick="confirmAction('{{id}}', '{{name}}', 'kill', true, 30)" type="button" value="Kill">
+</script>
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/topology.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/topology.html b/storm-core/src/ui/public/topology.html
new file mode 100644
index 0000000..c80bbe5
--- /dev/null
+++ b/storm-core/src/ui/public/topology.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html><head>
+<title>Storm UI</title>
+<link href="/css/bootstrap-1.4.0.css" rel="stylesheet" type="text/css">
+<link href="/css/style.css" rel="stylesheet" type="text/css">
+<script src="/js/jquery-1.6.2.min.js" type="text/javascript"></script>
+<script src="/js/jquery.tablesorter.min.js" type="text/javascript"></script>
+<script src="/js/jquery.cookies.2.2.0.min.js" type="text/javascript"></script>
+<script src="/js/jquery.mustache.js" type="text/javascript"></script>
+<script src="/js/purl.js" type="text/javascript"></script>
+<script src="/js/bootstrap-twipsy.js" type="text/javascript"></script>
+<script src="/js/script.js" type="text/javascript"></script>
+</head>
+<body>
+<h1><a href="/">Storm UI</a></h1>
+<h2>Topology summary</h2>
+<div id="topology-summary">
+</div>
+<div id="topology-actions">
+<h2 class="js-only">Topology actions</h2>
+<p id="topology-actions" class="js-only">
+</p>
+</div>
+<div id="topology-stats"></div>
+<div id="spout-stats">
+</div>
+<div id="bolt-stats">
+</div>
+<div id="topology-configuration">
+</div>
+<p id="toggle-switch" style="display: block;" class="js-only"></p>
+<div id="error">
+</div>
+</body>
+<script>
+$(document).ready(function() {
+ var topologyId = $.url().param("id");
+ var window = $.url().param("window");
+ var sys = $.cookies.get("sys") || "false";
+ var url = "/api/topology/"+topologyId+"?sys="+sys;
+ if(window) url += "&window="+window;
+ renderToggleSys($("#toggle-switch"));
+ $.ajaxSetup({
+ "error":function(jqXHR,textStatus,response) {
+ var errorJson = jQuery.parseJSON(jqXHR.responseText);
+ $.get("/templates/error-template.html", function(template) {
+ $("#error").append(Mustache.render($(template).filter("#error-template").html(),errorJson));
+ });
+ }
+ });
+
+ $.getJSON(url,function(response,status,jqXHR) {
+ var topologySummary = $("#topology-summary");
+ var topologyStats = $("#topology-stats");
+ var spoutStats = $("#spout-stats");
+ var boltStats = $("#bolt-stats");
+ var config = $("#topology-configuration");
+ var topologyActions = $("#topology-actions");
+ var formattedConfig = formatConfigData(response["configuration"]);
+ var buttonJsonData = topologyActionJson(response["id"],response["name"],response["status"],response["msgTimeout"]);
+ $.get("/templates/topology-page-template.html", function(template) {
+ topologySummary.append(Mustache.render($(template).filter("#topology-summary-template").html(),response));
+ topologyActions.append(Mustache.render($(template).filter("#topology-actions-template").html(),buttonJsonData));
+ topologyStats.append(Mustache.render($(template).filter("#topology-stats-template").html(),response));
+ $("#topology-stats-table").tablesorter({ sortList: [[0,0]], headers: {0: { sorter: "stormtimestr"}}});
+ spoutStats.append(Mustache.render($(template).filter("#spout-stats-template").html(),response));
+ if(response["spouts"].length > 0) {
+ $("#spout-stats-table").tablesorter({sortList: [[0,0]], headers:{}});
+ }
+ boltStats.append(Mustache.render($(template).filter("#bolt-stats-template").html(),response));
+ if(response["bolts"].length > 0) {
+ $("#bolt-stats-table").tablesorter({sortList: [[0,0]], headers:{}});
+ }
+ config.append(Mustache.render($(template).filter("#topology-configuration-template").html(),formattedConfig));
+ $("#topology-configuration-table").tablesorter({ sortList: [[0,0]], headers: {}});
+
+ });
+ });
+ });
+</script>
+</html>
[08/13] git commit: STORM-205. Add REST API to Storm UI. undid the
complete-latencies fix with last commit added back
Posted by bo...@apache.org.
STORM-205. Add REST API to Storm UI.
undid the complete-latencies fix with last commit added back
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/2a8f777f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/2a8f777f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/2a8f777f
Branch: refs/heads/master
Commit: 2a8f777f8e49a50e5846bae9eafb5f3512192ebd
Parents: 900490b
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Thu May 29 17:26:07 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Thu May 29 17:26:07 2014 -0700
----------------------------------------------------------------------
storm-core/src/clj/backtype/storm/ui/core.clj | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/2a8f777f/storm-core/src/clj/backtype/storm/ui/core.clj
----------------------------------------------------------------------
diff --git a/storm-core/src/clj/backtype/storm/ui/core.clj b/storm-core/src/clj/backtype/storm/ui/core.clj
index 8bc1f9d..a25327b 100644
--- a/storm-core/src/clj/backtype/storm/ui/core.clj
+++ b/storm-core/src/clj/backtype/storm/ui/core.clj
@@ -284,11 +284,11 @@
(merge-with
(fn [s1 s2]
(merge-with + s1 s2))
- (select-keys agg-bolt-stats [:emitted :transferred :acked :failed])
- (select-keys agg-spout-stats [:emitted :transferred :acked :failed])
+ (select-keys agg-bolt-stats [:emitted :transferred :acked :failed :complete-latencies])
+ (select-keys agg-spout-stats [:emitted :transferred :acked :failed :complete-latencies])
)))
-(defn stats-times [stats-map]
+(Defn stats-times [stats-map]
(sort-by #(Integer/parseInt %)
(-> stats-map
clojurify-structure
[02/13] git commit: STORM-205. Add REST API to Storm UI.
Posted by bo...@apache.org.
STORM-205. Add REST API to Storm UI.
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/a06fc90e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/a06fc90e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/a06fc90e
Branch: refs/heads/master
Commit: a06fc90e5ddb15a62c5e8214c94f0d59333fecc7
Parents: 22215b5
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Sat May 3 20:31:31 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Sat May 3 20:31:31 2014 -0700
----------------------------------------------------------------------
.gitignore | 4 +-
storm-core/src/clj/backtype/storm/ui/core.clj | 1078 ++++++------------
storm-core/src/ui/public/component.html | 88 ++
storm-core/src/ui/public/index.html | 73 ++
storm-core/src/ui/public/js/jquery.mustache.js | 592 ++++++++++
storm-core/src/ui/public/js/mustache.js | 570 +++++++++
storm-core/src/ui/public/js/purl.js | 267 +++++
storm-core/src/ui/public/js/script.js | 51 +-
.../templates/component-page-template.html | 152 +++
.../src/ui/public/templates/error-template.html | 4 +
.../public/templates/index-page-template.html | 62 +
.../templates/topology-page-template.html | 97 ++
storm-core/src/ui/public/topology.html | 81 ++
13 files changed, 2393 insertions(+), 726 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index b2a37f9..b575a02 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,4 +27,6 @@ target
/.lein-plugins/
*.ipr
*.iws
-.idea
\ No newline at end of file
+.idea
+.*
+!/.gitignore
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/clj/backtype/storm/ui/core.clj
----------------------------------------------------------------------
diff --git a/storm-core/src/clj/backtype/storm/ui/core.clj b/storm-core/src/clj/backtype/storm/ui/core.clj
index ad1a038..7943677 100644
--- a/storm-core/src/clj/backtype/storm/ui/core.clj
+++ b/storm-core/src/clj/backtype/storm/ui/core.clj
@@ -48,92 +48,6 @@
(map #(.get_stats ^ExecutorSummary %))
(filter not-nil?)))
-(def tips
- "Defines a mapping of help texts for elements of the UI pages."
- {:sys-stats "Use this to toggle inclusion of storm system components."
- :version (str "The version of storm installed on the UI node. (Hopefully, "
- "this is the same on all storm nodes!)")
- :nimbus-uptime (str "The duration the current Nimbus instance has been "
- "running. (Note that the storm cluster may have been "
- "deployed and available for a much longer period than "
- "the current Nimbus process has been running.)")
- :num-supervisors "The number of nodes in the cluster currently."
- :num-slots "Slots are Workers (processes)."
- :num-execs "Executors are threads in a Worker process."
- :num-tasks (str "A Task is an instance of a Bolt or Spout. The number of "
- "Tasks is almost always equal to the number of Executors.")
- :name "The name given to the topology by when it was submitted."
- :name-link "Click the name to view the Topology's information."
- :topo-id "The unique ID given to a Topology each time it is launched."
- :status "The status can be one of ACTIVE, INACTIVE, KILLED, or REBALANCING."
- :topo-uptime "The time since the Topology was submitted."
- :num-workers "The number of Workers (processes)."
- :sup-id (str "A unique identifier given to a Supervisor when it joins the "
- "cluster.")
- :sup-host (str "The hostname reported by the remote host. (Note that this "
- "hostname is not the result of a reverse lookup at the "
- "Nimbus node.)")
- :sup-uptime (str "The length of time a Supervisor has been registered to the "
- "cluster.")
- :window (str "The past period of time for which the statistics apply. "
- "Click on a value to set the window for this page.")
- :emitted "The number of Tuples emitted."
- :transferred "The number of Tuples emitted that sent to one or more bolts."
- :complete-lat (str "The average time a Tuple \"tree\" takes to be completely "
- "processed by the Topology. A value of 0 is expected "
- "if no acking is done.")
- :spout-acked (str "The number of Tuple \"trees\" successfully processed. A "
- "value of 0 is expected if no acking is done.")
- :spout-failed (str "The number of Tuple \"trees\" that were explicitly "
- "failed or timed out before acking was completed. A value "
- "of 0 is expected if no acking is done.")
- :comp-id "The ID assigned to a the Component by the Topology."
- :comp-id-link "Click on the name to view the Component's page."
- :capacity (str "If this is around 1.0, the corresponding Bolt is running as "
- "fast as it can, so you may want to increase the Bolt's "
- "parallelism. This is (number executed * average execute "
- "latency) / measurement time.")
- :exec-lat (str "The average time a Tuple spends in the execute method. The "
- "execute method may complete without sending an Ack for the "
- "tuple.")
- :num-executed "The number of incoming Tuples processed."
- :proc-lat (str "The average time it takes to Ack a Tuple after it is first "
- "received. Bolts that join, aggregate or batch may not Ack a "
- "tuple until a number of other Tuples have been received.")
- :bolt-acked "The number of Tuples acknowledged by this Bolt."
- :bolt-failed "The number of tuples Failed by this Bolt."
- :stream (str "The name of the Tuple stream given in the Topolgy, or \""
- Utils/DEFAULT_STREAM_ID "\" if none was given.")
- :exec-id "The unique executor ID."
- :exec-uptime "The length of time an Executor (thread) has been alive."
- :port (str "The port number used by the Worker to which an Executor is "
- "assigned. Click on the port number to open the logviewer page "
- "for this Worker.")})
-
-(defn mk-system-toggle-button [include-sys?]
- [:p {:class "js-only"}
- [:span.tip.right {:title (:sys-stats tips)}
- [:input {:type "button"
- :value (str (if include-sys? "Hide" "Show") " System Stats")
- :onclick "toggleSys()"}]]])
-
-(defn ui-template [body]
- (html4
- [:head
- [:title "Storm UI"]
- (include-css "/css/bootstrap-1.4.0.css")
- (include-css "/css/style.css")
- (include-js "/js/jquery-1.6.2.min.js")
- (include-js "/js/jquery.tablesorter.min.js")
- (include-js "/js/jquery.cookies.2.2.0.min.js")
- (include-js "/js/bootstrap-twipsy.js")
- (include-js "/js/script.js")
- ]
- [:body
- [:h1 (link-to "/" "Storm UI")]
- (seq body)
- ]))
-
(defn read-storm-version []
(let [storm-home (System/getProperty "storm.home")
release-path (format "%s/RELEASE" storm-home)
@@ -142,115 +56,6 @@
(trim (slurp release-path))
"Unknown")))
-(defn cluster-summary-table [^ClusterSummary summ]
- (let [sups (.get_supervisors summ)
- used-slots (reduce + (map #(.get_num_used_workers ^SupervisorSummary %) sups))
- total-slots (reduce + (map #(.get_num_workers ^SupervisorSummary %) sups))
- free-slots (- total-slots used-slots)
- total-tasks (->> (.get_topologies summ)
- (map #(.get_num_tasks ^TopologySummary %))
- (reduce +))
- total-executors (->> (.get_topologies summ)
- (map #(.get_num_executors ^TopologySummary %))
- (reduce +))]
- (table [{:text "Version" :attr {:class "tip right"
- :title (:version tips)}}
- {:text "Nimbus uptime" :attr {:class "tip right"
- :title (:nimbus-uptime tips)}}
- {:text "Supervisors" :attr {:class "tip above"
- :title (:num-supervisors tips)}}
- {:text "Used slots" :attr {:class "tip above"
- :title (:num-slots tips)}}
- {:text "Free slots" :attr {:class "tip above"
- :title (:num-slots tips)}}
- {:text "Total slots" :attr {:class "tip above"
- :title (:num-slots tips)}}
- {:text "Executors" :attr {:class "tip above"
- :title (:num-execs tips)}}
- {:text "Tasks" :attr {:class "tip left"
- :title (:num-tasks tips)}}]
- [[(read-storm-version)
- (pretty-uptime-sec (.get_nimbus_uptime_secs summ))
- (count sups)
- used-slots
- free-slots
- total-slots
- total-executors
- total-tasks]])
- ))
-
-(defn topology-link
- ([id] (topology-link id id))
- ([id content]
- (link-to (url-format "/topology/%s" id) (escape-html content))))
-
-(defn main-topology-summary-table [summs]
- (sorted-table
- [{:text "Name" :attr {:class "tip right"
- :title (str (:name tips) " " (:name-link tips))}}
- {:text "Id" :attr {:class "tip right"
- :title (:topo-id tips)}}
- {:text "Status" :attr {:class "tip above"
- :title (:status tips)}}
- {:text "Uptime" :attr {:class "tip above"
- :title (:topo-uptime tips)}}
- {:text "Num workers" :attr {:class "tip above"
- :title (:num-workers tips)}}
- {:text "Num executors" :attr {:class "tip above"
- :title (:num-execs tips)}}
- {:text "Num tasks" :attr {:class "tip above"
- :title (:num-tasks tips)}}]
- (for [^TopologySummary t summs]
- [(topology-link (.get_id t) (.get_name t))
- (escape-html (.get_id t))
- (.get_status t)
- (pretty-uptime-sec (.get_uptime_secs t))
- (.get_num_workers t)
- (.get_num_executors t)
- (.get_num_tasks t)
- ])
- :time-cols [3]
- :sort-list "[[0,0]]"
- ))
-
-(defn supervisor-summary-table [summs]
- (sorted-table
- [{:text "Id" :attr {:class "tip right"
- :title (:sup-id tips)}}
- {:text "Host" :attr {:class "tip above"
- :title (:sup-host tips)}}
- {:text "Uptime" :attr {:class "tip above"
- :title (:sup-uptime tips)}}
- {:text "Slots" :attr {:class "tip above"
- :title (:num-slots tips)}}
- {:text "Used slots" :attr {:class "tip left"
- :title (:num-slots tips)}}]
- (for [^SupervisorSummary s summs]
- [(.get_supervisor_id s)
- (.get_host s)
- (pretty-uptime-sec (.get_uptime_secs s))
- (.get_num_workers s)
- (.get_num_used_workers s)])
- :time-cols [2]))
-
-(defn configuration-table [conf]
- (sorted-table ["Key" "Value"]
- (map #(vector (key %) (str (val %))) conf)))
-
-(defn main-page []
- (with-nimbus nimbus
- (let [summ (.getClusterInfo ^Nimbus$Client nimbus)]
- (concat
- [[:h2 "Cluster Summary"]]
- [(cluster-summary-table summ)]
- [[:h2 "Topology summary"]]
- (main-topology-summary-table (.get_topologies summ))
- [[:h2 "Supervisor summary"]]
- (supervisor-summary-table (.get_supervisors summ))
- [[:h2 "Nimbus Configuration"]]
- (configuration-table (from-json (.getNimbusConf ^Nimbus$Client nimbus)))
- ))))
-
(defn component-type [^StormTopology topology id]
(let [bolts (.get_bolts topology)
spouts (.get_spouts topology)]
@@ -281,7 +86,6 @@
))]
))))
-
(defn expand-averages-seq [average-seq counts-seq]
(->> (map vector average-seq counts-seq)
(map #(apply expand-averages %))
@@ -414,88 +218,6 @@
(defn bolt-summary? [topology s]
(= :bolt (executor-summary-type topology s)))
-(defn topology-summary-table [^TopologyInfo summ]
- (let [executors (.get_executors summ)
- workers (set (for [^ExecutorSummary e executors] [(.get_host e) (.get_port e)]))]
- (table [{:text "Name" :attr {:class "tip right"
- :title (:name tips)}}
- {:text "Id" :attr {:class "tip right"
- :title (:topo-id tips)}}
- {:text "Status" :attr {:class "tip above"
- :title (:status tips)}}
- {:text "Uptime" :attr {:class "tip above"
- :title (:topo-uptime tips)}}
- {:text "Num workers" :attr {:class "tip above"
- :title (:num-workers tips)}}
- {:text "Num executors" :attr {:class "tip above"
- :title (:num-execs tips)}}
- {:text "Num tasks" :attr {:class "tip above"
- :title (:num-tasks tips)}}]
- [[(escape-html (.get_name summ))
- (escape-html (.get_id summ))
- (.get_status summ)
- (pretty-uptime-sec (.get_uptime_secs summ))
- (count workers)
- (count executors)
- (sum-tasks executors)
- ]]
- )))
-
-(defn total-aggregate-stats [spout-summs bolt-summs include-sys?]
- (let [spout-stats (get-filled-stats spout-summs)
- bolt-stats (get-filled-stats bolt-summs)
- agg-spout-stats (-> spout-stats
- (aggregate-spout-stats include-sys?)
- aggregate-spout-streams)
- agg-bolt-stats (-> bolt-stats
- (aggregate-bolt-stats include-sys?)
- aggregate-bolt-streams)]
- (merge-with
- (fn [s1 s2]
- (merge-with + s1 s2))
- (select-keys agg-bolt-stats [:emitted :transferred])
- agg-spout-stats
- )))
-
-(defn stats-times [stats-map]
- (sort-by #(Integer/parseInt %)
- (-> stats-map
- clojurify-structure
- (dissoc ":all-time")
- keys)))
-
-(defn topology-stats-table [id window stats]
- (let [times (stats-times (:emitted stats))
- display-map (into {} (for [t times] [t pretty-uptime-sec]))
- display-map (assoc display-map ":all-time" (fn [_] "All time"))]
- (sorted-table
- [{:text "Window" :attr {:class "tip right"
- :title (:window tips)}}
- {:text "Emitted" :attr {:class "tip above"
- :title (:emitted tips)}}
- {:text "Transferred" :attr {:class "tip above"
- :title (:transferred tips)}}
- {:text "Complete latency (ms)" :attr {:class "tip above"
- :title (:complete-lat tips)}}
- {:text "Acked" :attr {:class "tip above"
- :title (:spout-acked tips)}}
- {:text "Failed" :attr {:class "tip left"
- :title (:spout-failed tips)}}]
- (for [k (concat times [":all-time"])
- :let [disp ((display-map k) k)]]
- [(link-to (if (= k window) {:class "red"} {})
- (url-format "/topology/%s?window=%s" id k)
- (escape-html disp))
- (get-in stats [:emitted k])
- (get-in stats [:transferred k])
- (float-str (get-in stats [:complete-latencies k]))
- (get-in stats [:acked k])
- (get-in stats [:failed k])
- ]
- )
- :time-cols [0]
- )))
-
(defn group-by-comp [summs]
(let [ret (group-by #(.get_component_id ^ExecutorSummary %) summs)]
(into (sorted-map) ret )))
@@ -516,19 +238,20 @@
(error-subset (.get_error ^ErrorInfo error))]
)))
-(defn component-link [storm-id id]
- (link-to (url-format "/topology/%s/component/%s" storm-id id) (escape-html id)))
+(defn component-task-summs [^TopologyInfo summ topology id]
+ (let [spout-summs (filter (partial spout-summary? topology) (.get_executors summ))
+ bolt-summs (filter (partial bolt-summary? topology) (.get_executors summ))
+ spout-comp-summs (group-by-comp spout-summs)
+ bolt-comp-summs (group-by-comp bolt-summs)
+ ret (if (contains? spout-comp-summs id)
+ (spout-comp-summs id)
+ (bolt-comp-summs id))]
+ (sort-by #(-> ^ExecutorSummary % .get_executor_info .get_task_start) ret)
+ ))
(defn worker-log-link [host port]
- (link-to (url-format "http://%s:%s/log?file=worker-%s.log"
- host (*STORM-CONF* LOGVIEWER-PORT) port) (str port)))
-
-(defn render-capacity [capacity]
- (let [capacity (nil-to-zero capacity)]
- [:span (if (> capacity 0.9)
- {:class "red"}
- {})
- (float-str capacity)]))
+ (url-format "http://%s:%s/log?file=worker-%s.log"
+ host (*STORM-CONF* LOGVIEWER-PORT) port))
(defn compute-executor-capacity [^ExecutorSummary e]
(let [stats (.get_stats e)
@@ -553,87 +276,28 @@
(map nil-to-zero)
(apply max)))
-(defn spout-comp-table [top-id summ-map errors window include-sys?]
- (sorted-table
- [{:text "Id" :attr {:class "tip right"
- :title (str (:comp-id tips) " " (:comp-id-link tips))}}
- {:text "Executors" :attr {:class "tip right"
- :title (:num-execs tips)}}
- {:text "Tasks" :attr {:class "tip above"
- :title (:num-tasks tips)}}
- {:text "Emitted" :attr {:class "tip above"
- :title (:emitted tips)}}
- {:text "Transferred" :attr {:class "tip above"
- :title (:transferred tips)}}
- {:text "Complete latency (ms)" :attr {:class "tip above"
- :title (:complete-lat tips)}}
- {:text "Acked" :attr {:class "tip above"
- :title (:spout-acked tips)}}
- {:text "Failed" :attr {:class "tip above"
- :title (:spout-failed tips)}}
- "Last error"]
- (for [[id summs] summ-map
- :let [stats-seq (get-filled-stats summs)
- stats (aggregate-spout-streams
- (aggregate-spout-stats
- stats-seq include-sys?))]]
- [(component-link top-id id)
- (count summs)
- (sum-tasks summs)
- (get-in stats [:emitted window])
- (get-in stats [:transferred window])
- (float-str (get-in stats [:complete-latencies window]))
- (get-in stats [:acked window])
- (get-in stats [:failed window])
- (most-recent-error (get errors id))
- ]
+(defn total-aggregate-stats [spout-summs bolt-summs include-sys?]
+ (let [spout-stats (get-filled-stats spout-summs)
+ bolt-stats (get-filled-stats bolt-summs)
+ agg-spout-stats (-> spout-stats
+ (aggregate-spout-stats include-sys?)
+ aggregate-spout-streams)
+ agg-bolt-stats (-> bolt-stats
+ (aggregate-bolt-stats include-sys?)
+ aggregate-bolt-streams)]
+ (merge-with
+ (fn [s1 s2]
+ (merge-with + s1 s2))
+ (select-keys agg-bolt-stats [:emitted :transferred])
+ agg-spout-stats
)))
-(defn bolt-comp-table [top-id summ-map errors window include-sys?]
- (sorted-table
- [{:text "Id" :attr {:class "tip right"
- :title (str (:comp-id tips) " " (:comp-id-link tips))}}
- {:text "Executors" :attr {:class "tip right"
- :title (:num-execs tips)}}
- {:text "Tasks" :attr {:class "tip above"
- :title (:num-tasks tips)}}
- {:text "Emitted" :attr {:class "tip above"
- :title (:emitted tips)}}
- {:text "Transferred" :attr {:class "tip above"
- :title (:transferred tips)}}
- {:text "Capacity (last 10m)" :attr {:class "tip above"
- :title (:capacity tips)}}
- {:text "Execute latency (ms)" :attr {:class "tip above"
- :title (:exec-lat tips)}}
- {:text "Executed" :attr {:class "tip above"
- :title (:num-executed tips)}}
- {:text "Process latency (ms)":attr {:class "tip above"
- :title (:proc-lat tips)}}
- {:text "Acked" :attr {:class "tip above"
- :title (:bolt-acked tips)}}
- {:text "Failed" :attr {:class "tip left"
- :title (:bolt-failed tips)}}
- "Last error"]
- (for [[id summs] summ-map
- :let [stats-seq (get-filled-stats summs)
- stats (aggregate-bolt-streams
- (aggregate-bolt-stats
- stats-seq include-sys?))
- ]]
- [(component-link top-id id)
- (count summs)
- (sum-tasks summs)
- (get-in stats [:emitted window])
- (get-in stats [:transferred window])
- (render-capacity (compute-bolt-capacity summs))
- (float-str (get-in stats [:execute-latencies window]))
- (get-in stats [:executed window])
- (float-str (get-in stats [:process-latencies window]))
- (get-in stats [:acked window])
- (get-in stats [:failed window])
- (most-recent-error (get errors id))
- ]
- )))
+(defn stats-times [stats-map]
+ (sort-by #(Integer/parseInt %)
+ (-> stats-map
+ clojurify-structure
+ (dissoc ":all-time")
+ keys)))
(defn window-hint [window]
(if (= window ":all-time")
@@ -644,11 +308,153 @@
[:input {:type "button"
:value action
(if enabled :enabled :disabled) ""
- :onclick (str "confirmAction('"
- (StringEscapeUtils/escapeJavaScript id) "', '"
+ :onclick (str "confirmAction('"
+ (StringEscapeUtils/escapeJavaScript id) "', '"
(StringEscapeUtils/escapeJavaScript name) "', '"
command "', " is-wait ", " default-wait ")")}])
+(defn cluster-configuration []
+ (with-nimbus nimbus
+ (.getNimbusConf ^Nimbus$Client nimbus)))
+
+(defn cluster-summary
+ ([]
+ (with-nimbus nimbus
+ (cluster-summary (.getClusterInfo ^Nimbus$Client nimbus))))
+ ([^ClusterSummary summ]
+ (let [sups (.get_supervisors summ)
+ used-slots (reduce + (map #(.get_num_used_workers ^SupervisorSummary %) sups))
+ total-slots (reduce + (map #(.get_num_workers ^SupervisorSummary %) sups))
+ free-slots (- total-slots used-slots)
+ total-tasks (->> (.get_topologies summ)
+ (map #(.get_num_tasks ^TopologySummary %))
+ (reduce +))
+ total-executors (->> (.get_topologies summ)
+ (map #(.get_num_executors ^TopologySummary %))
+ (reduce +))]
+ { "stormVersion" (read-storm-version)
+ "nimbusUptime" (pretty-uptime-sec (.get_nimbus_uptime_secs summ))
+ "supervisors" (count sups)
+ "topologies" ""
+ "slotsTotal" total-slots
+ "slotsUsed" used-slots
+ "slotsFree" free-slots
+ "executorsTotal" total-executors
+ "tasksTotal" total-tasks })))
+
+(defn supervisor-summary
+ ([]
+ (with-nimbus nimbus
+ (supervisor-summary (.get_supervisors (.getClusterInfo ^Nimbus$Client nimbus)))
+ ))
+ ([summs]
+ {"supervisors"
+ (for [^SupervisorSummary s summs]
+ {"id" (.get_supervisor_id s)
+ "host" (.get_host s)
+ "uptime" (pretty-uptime-sec (.get_uptime_secs s))
+ "slotsTotal" (.get_num_workers s)
+ "slotsUsed" (.get_num_used_workers s)})}))
+
+(defn all-topologies-summary
+ ([]
+ (with-nimbus nimbus
+ (all-topologies-summary (.get_topologies (.getClusterInfo ^Nimbus$Client nimbus)))))
+ ([summs]
+ {"topologies"
+ (for [^TopologySummary t summs]
+ {"id" (.get_id t)
+ "name" (.get_name t)
+ "status" (.get_status t)
+ "uptime" (.get_uptime_secs t)
+ "tasksTotal" (.get_num_tasks t)
+ "workersTotal" (.get_num_workers t)
+ "executorsTotal" (.get_num_executors t)})
+ }))
+
+(defn topology-stats [id window stats]
+ (let [times (stats-times (:emitted stats))
+ display-map (into {} (for [t times] [t pretty-uptime-sec]))
+ display-map (assoc display-map ":all-time" (fn [_] "All time"))]
+ (for [k (concat times [":all-time"])
+ :let [disp ((display-map k) k)]]
+ { "windowPretty" disp
+ "window" k
+ "emitted" (get-in stats [:emitted k])
+ "transferred" (get-in stats [:transferred k])
+ "completeLatency" (float-str (get-in stats [:complete-latencies k]))
+ "acked" (get-in stats [:acked k])
+ "failed" (get-in stats [:failed k])
+ }
+ )))
+
+(defn spout-comp [top-id summ-map errors window include-sys?]
+ (for [[id summs] summ-map
+ :let [stats-seq (get-filled-stats summs)
+ stats (aggregate-spout-streams
+ (aggregate-spout-stats
+ stats-seq include-sys?))]]
+ {"spoutId" id
+ "executors" (count summs)
+ "tasks" (sum-tasks summs)
+ "emitted" (get-in stats [:emitted window])
+ "transferred" (get-in stats [:transferred window])
+ "complete_latency" (float-str (get-in stats [:complete-latencies window]))
+ "acked" (get-in stats [:acked window])
+ "failed" (get-in stats [:failed window])
+ "last_error" (most-recent-error (get errors id))
+ }))
+
+(defn bolt-comp [top-id summ-map errors window include-sys?]
+ (for [[id summs] summ-map
+ :let [stats-seq (get-filled-stats summs)
+ stats (aggregate-bolt-streams
+ (aggregate-bolt-stats
+ stats-seq include-sys?))
+ ]]
+ {"boltId" id
+ "executors" (count summs)
+ "tasks" (sum-tasks summs)
+ "emitted" (get-in stats [:emitted window])
+ "trasnferred" (get-in stats [:transferred window])
+ "capacity" (compute-bolt-capacity summs)
+ "execute_latency" (float-str (get-in stats [:execute-latencies window]))
+ "executed" (get-in stats [:executed window])
+ "process_latency" (float-str (get-in stats [:process-latencies window]))
+ "acked" (get-in stats [:acked window])
+ "failed" (get-in stats [:failed window])
+ "last_error" (most-recent-error (get errors id))
+ }
+ ))
+
+(defn topology-summary [^TopologyInfo summ]
+ (let [executors (.get_executors summ)
+ workers (set (for [^ExecutorSummary e executors] [(.get_host e) (.get_port e)]))]
+ {"id" (.get_id summ)
+ "name" (.get_name summ)
+ "status" (.get_status summ)
+ "uptime" (pretty-uptime-sec (.get_uptime_secs summ))
+ "tasksTotal" (sum-tasks executors)
+ "workersTotal" (count workers)
+ "executorsTotal" (count executors)}
+ ))
+
+(defn spout-summary [topology-id id stats window]
+ (let [times (stats-times (:emitted stats))
+ display-map (into {} (for [t times] [t pretty-uptime-sec]))
+ display-map (assoc display-map ":all-time" (fn [_] "All time"))]
+ (for [k (concat times [":all-time"])
+ :let [disp ((display-map k) k)]]
+ {"windowPretty" disp
+ "window" k
+ "emitted" (get-in stats [:emitted k])
+ "transferred" (get-in stats [:transferred k])
+ "completeLatency" (float-str (get-in stats [:complete-latencies k]))
+ "acked" (get-in stats [:acked k])
+ "failed" (get-in stats [:failed k])
+ }
+ )))
+
(defn topology-page [id window include-sys?]
(with-nimbus nimbus
(let [window (if window window ":all-time")
@@ -665,317 +471,150 @@
status (.get_status summ)
msg-timeout (topology-conf TOPOLOGY-MESSAGE-TIMEOUT-SECS)
]
- (concat
- [[:h2 "Topology summary"]]
- [(topology-summary-table summ)]
- [[:h2 {:class "js-only"} "Topology actions"]]
- [[:p {:class "js-only"} (concat
- [(topology-action-button id name "Activate" "activate" false 0 (= "INACTIVE" status))]
- [(topology-action-button id name "Deactivate" "deactivate" false 0 (= "ACTIVE" status))]
- [(topology-action-button id name "Rebalance" "rebalance" true msg-timeout (or (= "ACTIVE" status) (= "INACTIVE" status)))]
- [(topology-action-button id name "Kill" "kill" true msg-timeout (not= "KILLED" status))]
- )]]
- [[:h2 "Topology stats"]]
- (topology-stats-table id window (total-aggregate-stats spout-summs bolt-summs include-sys?))
- [[:h2 "Spouts (" window-hint ")"]]
- (spout-comp-table id spout-comp-summs (.get_errors summ) window include-sys?)
- [[:h2 "Bolts (" window-hint ")"]]
- (bolt-comp-table id bolt-comp-summs (.get_errors summ) window include-sys?)
- [[:h2 "Topology Configuration"]]
- (configuration-table topology-conf)
- ))))
-
-(defn component-task-summs [^TopologyInfo summ topology id]
- (let [spout-summs (filter (partial spout-summary? topology) (.get_executors summ))
- bolt-summs (filter (partial bolt-summary? topology) (.get_executors summ))
- spout-comp-summs (group-by-comp spout-summs)
- bolt-comp-summs (group-by-comp bolt-summs)
- ret (if (contains? spout-comp-summs id)
- (spout-comp-summs id)
- (bolt-comp-summs id))]
- (sort-by #(-> ^ExecutorSummary % .get_executor_info .get_task_start) ret)
- ))
+ (merge
+ (topology-summary summ)
+ {"window" window
+ "windowHint" window-hint
+ "msgTimeout" msg-timeout
+ "topologyStats" (topology-stats id window (total-aggregate-stats spout-summs bolt-summs include-sys?))
+ "spouts" (spout-comp id spout-comp-summs (.get_errors summ) window include-sys?)
+ "bolts" (bolt-comp id bolt-comp-summs (.get_errors summ) window include-sys?)
+ "configuration" topology-conf})
+ )))
-(defn spout-summary-table [topology-id id stats window]
- (let [times (stats-times (:emitted stats))
- display-map (into {} (for [t times] [t pretty-uptime-sec]))
- display-map (assoc display-map ":all-time" (fn [_] "All time"))]
- (sorted-table
- [{:text "Window" :attr {:class "tip right"
- :title (:window tips)}}
- {:text "Emitted" :attr {:class "tip above"
- :title (:emitted tips)}}
- {:text "Transferred" :attr {:class "tip above"
- :title (:transferred tips)}}
- {:text "Complete latency (ms)" :attr {:class "tip above"
- :title (:complete-lat tips)}}
- {:text "Acked" :attr {:class "tip above"
- :title (:spout-acked tips)}}
- {:text "Failed" :attr {:class "tip left"
- :title (:spout-failed tips)}}]
- (for [k (concat times [":all-time"])
- :let [disp ((display-map k) k)]]
- [(link-to (if (= k window) {:class "red"} {})
- (url-format "/topology/%s/component/%s?window=%s" topology-id id k)
- (escape-html disp))
- (get-in stats [:emitted k])
- (get-in stats [:transferred k])
- (float-str (get-in stats [:complete-latencies k]))
- (get-in stats [:acked k])
- (get-in stats [:failed k])
- ])
- :time-cols [0])))
-
-(defn spout-output-summary-table [stream-summary window]
+(defn spout-output-stats [stream-summary window]
(let [stream-summary (map-val swap-map-order (swap-map-order stream-summary))]
- (sorted-table
- [{:text "Stream" :attr {:class "tip right"
- :title (:stream tips)}}
- {:text "Emitted" :attr {:class "tip above"
- :title (:emitted tips)}}
- {:text "Transferred" :attr {:class "tip above"
- :title (:transferred tips)}}
- {:text "Complete latency (ms)" :attr {:class "tip above"
- :title (:complete-lat tips)}}
- {:text "Acked" :attr {:class "tip above"
- :title (:spout-acked tips)}}
- {:text "Failed" :attr {:class "tip left"
- :title (:spout-failed tips)}}]
- (for [[s stats] (stream-summary window)]
- [s
- (nil-to-zero (:emitted stats))
- (nil-to-zero (:transferred stats))
- (float-str (:complete-latencies stats))
- (nil-to-zero (:acked stats))
- (nil-to-zero (:failed stats))])
- )))
+ (for [[s stats] (stream-summary window)]
+ {"stream" s
+ "emitted" (nil-to-zero (:emitted stats))
+ "transferred" (nil-to-zero (:transferred stats))
+ "complete_latency" (float-str (:complete-latencies stats))
+ "acked" (nil-to-zero (:acked stats))
+ "failed" (nil-to-zero (:failed stats))
+ }
+ )))
-(defn spout-executor-table [topology-id executors window include-sys?]
- (sorted-table
- [{:text "Id" :attr {:class "tip right"
- :title (:exec-id tips)}}
- {:text "Uptime" :attr {:class "tip right"
- :title (:exec-uptime tips)}}
- {:text "Host" :attr {:class "tip above"
- :title (:sup-host tips)}}
- {:text "Port" :attr {:class "tip above"
- :title (:port tips)}}
- {:text "Emitted" :attr {:class "tip above"
- :title (:emitted tips)}}
- {:text "Transferred" :attr {:class "tip above"
- :title (:transferred tips)}}
- {:text "Complete latency (ms)" :attr {:class "tip above"
- :title (:complete-lat tips)}}
- {:text "Acked" :attr {:class "tip above"
- :title (:spout-acked tips)}}
- {:text "Failed" :attr {:class "tip left"
- :title (:spout-failed tips)}}]
- (for [^ExecutorSummary e executors
- :let [stats (.get_stats e)
- stats (if stats
- (-> stats
- (aggregate-spout-stats include-sys?)
- aggregate-spout-streams
- swap-map-order
- (get window)))]]
- [(pretty-executor-info (.get_executor_info e))
- (pretty-uptime-sec (.get_uptime_secs e))
- (.get_host e)
- (worker-log-link (.get_host e) (.get_port e))
- (nil-to-zero (:emitted stats))
- (nil-to-zero (:transferred stats))
- (float-str (:complete-latencies stats))
- (nil-to-zero (:acked stats))
- (nil-to-zero (:failed stats))
- ]
- )
- :time-cols [1]
- ))
-
-(defn spout-page [window ^TopologyInfo topology-info component executors include-sys?]
+(defn spout-executor-stats [topology-id executors window include-sys?]
+ (for [^ExecutorSummary e executors
+ :let [stats (.get_stats e)
+ stats (if stats
+ (-> stats
+ (aggregate-spout-stats include-sys?)
+ aggregate-spout-streams
+ swap-map-order
+ (get window)))]]
+ {"id" (pretty-executor-info (.get_executor_info e))
+ "uptime" (pretty-uptime-sec (.get_uptime_secs e))
+ "host" (.get_host e)
+ "port" (.get_port e)
+ "emitted" (nil-to-zero (:emitted stats))
+ "transferred" (nil-to-zero (:transferred stats))
+ "completeLatency" (float-str (:complete-latencies stats))
+ "acked" (nil-to-zero (:acked stats))
+ "failed" (nil-to-zero (:failed stats))
+ "workerLogLink" (worker-log-link (.get_host e) (.get_port e))
+ }
+ ))
+
+(defn component-errors [errors-list]
+ (let [errors (->> errors-list
+ (sort-by #(.get_error_time_secs ^ErrorInfo %))
+ reverse)]
+ {"errors"
+ (for [^ErrorInfo e errors]
+ [{"time" (date-str (.get_error_time_secs e))
+ "error" (.get_error e)
+ }])}
+ ))
+
+(defn spout-stats [window ^TopologyInfo topology-info component executors include-sys?]
(let [window-hint (str " (" (window-hint window) ")")
stats (get-filled-stats executors)
stream-summary (-> stats (aggregate-spout-stats include-sys?))
summary (-> stream-summary aggregate-spout-streams)]
- (concat
- [[:h2 "Spout stats"]]
- (spout-summary-table (.get_id topology-info) component summary window)
- [[:h2 "Output stats" window-hint]]
- (spout-output-summary-table stream-summary window)
- [[:h2 "Executors" window-hint]]
- (spout-executor-table (.get_id topology-info) executors window include-sys?)
- ;; task id, task uptime, stream aggregated stats, last error
- )))
+ {"spoutSummary" (spout-summary (.get_id topology-info) component summary window)
+ "outputStats" (spout-output-stats stream-summary window)
+ "executorStats" (spout-executor-stats (.get_id topology-info) executors window include-sys?)}
+ ))
-(defn bolt-output-summary-table [stream-summary window]
+(defn bolt-summary [topology-id id stats window]
+ (let [times (stats-times (:emitted stats))
+ display-map (into {} (for [t times] [t pretty-uptime-sec]))
+ display-map (assoc display-map ":all-time" (fn [_] "All time"))]
+ (for [k (concat times [":all-time"])
+ :let [disp ((display-map k) k)]]
+ {"window" k
+ "windowPretty" disp
+ "emitted" (get-in stats [:emitted k])
+ "transferred" (get-in stats [:transferred k])
+ "executeLatency" (float-str (get-in stats [:execute-latencies k]))
+ "executed" (get-in stats [:executed k])
+ "processLatency" (float-str (get-in stats [:process-latencies k]))
+ "acked" (get-in stats [:acked k])
+ "failed" (get-in stats [:failed k])})))
+
+(defn bolt-output-stats [stream-summary window]
(let [stream-summary (-> stream-summary
swap-map-order
(get window)
(select-keys [:emitted :transferred])
swap-map-order)]
- (sorted-table
- [{:text "Stream" :attr {:class "tip right"
- :title (:stream tips)}}
- {:text "Emitted" :attr {:class "tip above"
- :title (:emitted tips)}}
- {:text "Transferred" :attr {:class "tip above"
- :title (:transferred tips)}}]
- (for [[s stats] stream-summary]
- [s
- (nil-to-zero (:emitted stats))
- (nil-to-zero (:transferred stats))
- ])
- )))
+ (for [[s stats] stream-summary]
+ {"stream" s
+ "emitted" (nil-to-zero (:emitted stats))
+ "transferred" (nil-to-zero (:transferred stats))}
+ )))
-(defn bolt-input-summary-table [stream-summary window]
+(defn bolt-input-stats [stream-summary window]
(let [stream-summary (-> stream-summary
swap-map-order
(get window)
(select-keys [:acked :failed :process-latencies :executed :execute-latencies])
swap-map-order)]
- (sorted-table
- [{:text "Component" :attr {:class "tip right"
- :title (:comp-id tips)}}
- {:text "Stream" :attr {:class "tip right"
- :title (:stream tips)}}
- {:text "Execute latency (ms)" :attr {:class "tip above"
- :title (:exec-lat tips)}}
- {:text "Executed" :attr {:class "tip above"
- :title (:num-executed tips)}}
- {:text "Process latency (ms)":attr {:class "tip above"
- :title (:proc-lat tips)}}
- {:text "Acked" :attr {:class "tip above"
- :title (:bolt-acked tips)}}
- {:text "Failed" :attr {:class "tip left"
- :title (:bolt-failed tips)}}]
- (for [[^GlobalStreamId s stats] stream-summary]
- [(escape-html (.get_componentId s))
- (.get_streamId s)
- (float-str (:execute-latencies stats))
- (nil-to-zero (:executed stats))
- (float-str (:process-latencies stats))
- (nil-to-zero (:acked stats))
- (nil-to-zero (:failed stats))
- ])
- )))
-
-(defn bolt-executor-table [topology-id executors window include-sys?]
- (sorted-table
- [{:text "Id" :attr {:class "tip right"
- :title (:exec-id tips)}}
- {:text "Uptime" :attr {:class "tip right"
- :title (:exec-uptime tips)}}
- {:text "Host" :attr {:class "tip above"
- :title (:sup-host tips)}}
- {:text "Port" :attr {:class "tip above"
- :title (:port tips)}}
- {:text "Emitted" :attr {:class "tip above"
- :title (:emitted tips)}}
- {:text "Transferred" :attr {:class "tip above"
- :title (:transferred tips)}}
- {:text "Capacity (last 10m)" :attr {:class "tip above"
- :title (:capacity tips)}}
- {:text "Execute latency (ms)" :attr {:class "tip above"
- :title (:exec-lat tips)}}
- {:text "Executed" :attr {:class "tip above"
- :title (:num-executed tips)}}
- {:text "Process latency (ms)":attr {:class "tip above"
- :title (:proc-lat tips)}}
- {:text "Acked" :attr {:class "tip above"
- :title (:bolt-acked tips)}}
- {:text "Failed" :attr {:class "tip left"
- :title (:bolt-failed tips)}}]
- (for [^ExecutorSummary e executors
- :let [stats (.get_stats e)
- stats (if stats
- (-> stats
- (aggregate-bolt-stats include-sys?)
- (aggregate-bolt-streams)
- swap-map-order
- (get window)))]]
- [(pretty-executor-info (.get_executor_info e))
- (pretty-uptime-sec (.get_uptime_secs e))
- (.get_host e)
- (worker-log-link (.get_host e) (.get_port e))
- (nil-to-zero (:emitted stats))
- (nil-to-zero (:transferred stats))
- (render-capacity (compute-executor-capacity e))
- (float-str (:execute-latencies stats))
- (nil-to-zero (:executed stats))
- (float-str (:process-latencies stats))
- (nil-to-zero (:acked stats))
- (nil-to-zero (:failed stats))
- ]
- )
- :time-cols [1]
- ))
-
-(defn bolt-summary-table [topology-id id stats window]
- (let [times (stats-times (:emitted stats))
- display-map (into {} (for [t times] [t pretty-uptime-sec]))
- display-map (assoc display-map ":all-time" (fn [_] "All time"))]
- (sorted-table
- [{:text "Window" :attr {:class "tip right"
- :title (:window tips)}}
- {:text "Emitted" :attr {:class "tip above"
- :title (:emitted tips)}}
- {:text "Transferred" :attr {:class "tip above"
- :title (:transferred tips)}}
- {:text "Execute latency (ms)" :attr {:class "tip above"
- :title (:exec-lat tips)}}
- {:text "Executed" :attr {:class "tip above"
- :title (:num-executed tips)}}
- {:text "Process latency (ms)":attr {:class "tip above"
- :title (:proc-lat tips)}}
- {:text "Acked" :attr {:class "tip above"
- :title (:bolt-acked tips)}}
- {:text "Failed" :attr {:class "tip left"
- :title (:bolt-failed tips)}}]
- (for [k (concat times [":all-time"])
- :let [disp ((display-map k) k)]]
- [(link-to (if (= k window) {:class "red"} {})
- (url-format "/topology/%s/component/%s?window=%s" topology-id id k)
- (escape-html disp))
- (get-in stats [:emitted k])
- (get-in stats [:transferred k])
- (float-str (get-in stats [:execute-latencies k]))
- (get-in stats [:executed k])
- (float-str (get-in stats [:process-latencies k]))
- (get-in stats [:acked k])
- (get-in stats [:failed k])
- ])
- :time-cols [0])))
-
-(defn bolt-page [window ^TopologyInfo topology-info component executors include-sys?]
+ (for [[^GlobalStreamId s stats] stream-summary]
+ {"component" (.get_componentId s)
+ "stream" (.get_streamId s)
+ "executeLatency" (float-str (:execute-latencies stats))
+ "processLatency" (float-str (:execute-latencies stats))
+ "executed" (nil-to-zero (:executed stats))
+ "acked" (nil-to-zero (:acked stats))
+ "failed" (nil-to-zero (:failed stats))
+ })))
+
+(defn bolt-executor-stats [topology-id executors window include-sys?]
+ (for [^ExecutorSummary e executors
+ :let [stats (.get_stats e)
+ stats (if stats
+ (-> stats
+ (aggregate-bolt-stats include-sys?)
+ (aggregate-bolt-streams)
+ swap-map-order
+ (get window)))]]
+ {"id" (pretty-executor-info (.get_executor_info e))
+ "uptime" (pretty-uptime-sec (.get_uptime_secs e))
+ "host" (.get_host e)
+ "port" (.get_port e)
+ "emitted" (nil-to-zero (:emitted stats))
+ "transferred" (nil-to-zero (:transferred stats))
+ "capacity" (compute-executor-capacity e)
+ "executeLatency" (float-str (:execute-latencies stats))
+ "executed" (nil-to-zero (:executed stats))
+ "processLatency" (float-str (:process-latencies stats))
+ "acked" (nil-to-zero (:acked stats))
+ "failed" (nil-to-zero (:failed stats))
+ "workerLogLink" (worker-log-link (.get_host e) (.get_port e))
+ }))
+
+(defn bolt-stats [window ^TopologyInfo topology-info component executors include-sys?]
(let [window-hint (str " (" (window-hint window) ")")
stats (get-filled-stats executors)
stream-summary (-> stats (aggregate-bolt-stats include-sys?))
summary (-> stream-summary aggregate-bolt-streams)]
- (concat
- [[:h2 "Bolt stats"]]
- (bolt-summary-table (.get_id topology-info) component summary window)
-
- [[:h2 "Input stats" window-hint]]
- (bolt-input-summary-table stream-summary window)
-
- [[:h2 "Output stats" window-hint]]
- (bolt-output-summary-table stream-summary window)
-
- [[:h2 "Executors"]]
- (bolt-executor-table (.get_id topology-info) executors window include-sys?)
- )))
-
-(defn errors-table [errors-list]
- (let [errors (->> errors-list
- (sort-by #(.get_error_time_secs ^ErrorInfo %))
- reverse)]
- (sorted-table
- ["Time" "Error"]
- (for [^ErrorInfo e errors]
- [(date-str (.get_error_time_secs e))
- [:pre (.get_error e)]])
- :sort-list "[[0,1]]"
- )))
+ {"boltStats" (bolt-summary (.get_id topology-info) component summary window)
+ "inputStats" (bolt-input-stats stream-summary window)
+ "outputStats" (bolt-output-stats stream-summary window)
+ "executorStats" (bolt-executor-stats (.get_id topology-info) executors window include-sys?)}
+ ))
(defn component-page [topology-id component window include-sys?]
(with-nimbus nimbus
@@ -984,106 +623,101 @@
topology (.getTopology ^Nimbus$Client nimbus topology-id)
type (component-type topology component)
summs (component-task-summs summ topology component)
- spec (cond (= type :spout) (spout-page window summ component summs include-sys?)
- (= type :bolt) (bolt-page window summ component summs include-sys?))]
- (concat
- [[:h2 "Component summary"]
- (table [{:text "Id" :attr {:class "tip right"
- :title (:comp-id tips)}}
- {:text "Topology" :attr {:class "tip above"
- :title (str (:name tips) " " (:name-link tips))}}
- {:text "Executors" :attr {:class "tip above"
- :title (:num-execs tips)}}
- {:text "Tasks" :attr {:class "tip above"
- :title (:num-tasks tips)}}]
- [[(escape-html component)
- (topology-link (.get_id summ) (.get_name summ))
- (count summs)
- (sum-tasks summs)
- ]])]
- spec
- [[:h2 "Errors"]
- (errors-table (get (.get_errors summ) component))]
- ))))
-
-(defn get-include-sys? [cookies]
- (let [sys? (get cookies "sys")
- sys? (if (or (nil? sys?) (= "false" (:value sys?))) false true)]
- sys?))
+ spec (cond (= type :spout) (spout-stats window summ component summs include-sys?)
+ (= type :bolt) (bolt-stats window summ component summs include-sys?))
+ errors (component-errors (get (.get_errors summ) component))]
+ (merge
+ {"id" component
+ "name" (.get_name summ)
+ "executors" (count summs)
+ "tasks" (sum-tasks summs)
+ "topologyId" topology-id
+ "window" window
+ "componentType" (name type)
+ "windowHint" (window-hint window)
+ } spec errors))))
+
+(defn check-include-sys? [sys?]
+ (if (or (nil? sys?) (= "false" sys?)) false true))
+
+(defn json-response [data & [status]]
+ {:status (or status 200)
+ :headers {"Content-Type" "application/json"}
+ :body (to-json data)
+ })
(defroutes main-routes
- (GET "/" [:as {cookies :cookies}]
- (-> (main-page)
- ui-template))
- (GET "/topology/:id" [:as {cookies :cookies} id & m]
- (let [include-sys? (get-include-sys? cookies)
- id (url-decode id)]
- (try
- (-> (topology-page (url-decode id) (:window m) include-sys?)
- (concat [(mk-system-toggle-button include-sys?)])
- ui-template)
- (catch Exception e (resp/redirect "/")))))
- (GET "/topology/:id/component/:component" [:as {cookies :cookies} id component & m]
- (let [include-sys? (get-include-sys? cookies)
- id (url-decode id)
- component (url-decode component)]
- (-> (component-page id component (:window m) include-sys?)
- (concat [(mk-system-toggle-button include-sys?)])
- ui-template)))
- (POST "/topology/:id/activate" [id]
+ (GET "/api/cluster/configuration" []
+ (cluster-configuration))
+ (GET "/api/cluster/summary" []
+ (json-response (cluster-summary)))
+ (GET "/api/supervisor/summary" []
+ (json-response (supervisor-summary)))
+ (GET "/api/topology/summary" []
+ (json-response (all-topologies-summary)))
+ (GET "/api/topology/:id" [id & m]
+ (let [id (java.net.URLDecoder/decode id)]
+ (json-response (topology-page id (:window m) (check-include-sys? (:sys m))))))
+ (GET "/api/topology/:id/component/:component" [id component & m]
+ (let [id (java.net.URLDecoder/decode id)
+ component (java.net.URLDecoder/decode component)]
+ (json-response (component-page id component (:window m) (check-include-sys? (:sys m))))))
+ (POST "/api/topology/:id/activate" [id]
(with-nimbus nimbus
- (let [id (url-decode id)
+ (let [id (java.net.URLDecoder/decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)]
(.activate nimbus name)
(log-message "Activating topology '" name "'")))
- (resp/redirect (str "/topology/" id)))
- (POST "/topology/:id/deactivate" [id]
+ (resp/redirect (str "/api/topology/" id)))
+
+ (POST "/api/topology/:id/deactivate" [id]
(with-nimbus nimbus
- (let [id (url-decode id)
+ (let [id (java.net.URLDecoder/decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)]
(.deactivate nimbus name)
(log-message "Deactivating topology '" name "'")))
- (resp/redirect (str "/topology/" id)))
- (POST "/topology/:id/rebalance/:wait-time" [id wait-time]
+ (resp/redirect (str "/api/topology/" id)))
+ (POST "/api/topology/:id/rebalance/:wait-time" [id wait-time]
(with-nimbus nimbus
- (let [id (url-decode id)
+ (let [id (java.net.URLDecoder/decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)
options (RebalanceOptions.)]
(.set_wait_secs options (Integer/parseInt wait-time))
(.rebalance nimbus name options)
(log-message "Rebalancing topology '" name "' with wait time: " wait-time " secs")))
- (resp/redirect (str "/topology/" id)))
- (POST "/topology/:id/kill/:wait-time" [id wait-time]
+ (resp/redirect (str "/api/topology/" id)))
+ (POST "/api/topology/:id/kill/:wait-time" [id wait-time]
(with-nimbus nimbus
- (let [id (url-decode id)
+ (let [id (java.net.URLDecoder/decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)
options (KillOptions.)]
(.set_wait_secs options (Integer/parseInt wait-time))
(.killTopologyWithOpts nimbus name options)
(log-message "Killing topology '" name "' with wait time: " wait-time " secs")))
- (resp/redirect (str "/topology/" id)))
+ (resp/redirect (str "/api/topology/" id)))
+
+ (GET "/" [:as {cookies :cookies}]
+ (resp/redirect "/index.html"))
(route/resources "/")
(route/not-found "Page not found"))
-(defn exception->html [ex]
- (concat
- [[:h2 "Internal Server Error"]]
- [[:pre (let [sw (java.io.StringWriter.)]
+(defn exception->json [ex]
+ { "error" "Internal Server Error"
+ "errorMessage" (let [sw (java.io.StringWriter.)]
(.printStackTrace ex (java.io.PrintWriter. sw))
- (.toString sw))]]))
+ (.toString sw))
+ })
(defn catch-errors [handler]
(fn [request]
(try
(handler request)
(catch Exception ex
- (-> (resp/response (ui-template (exception->html ex)))
- (resp/status 500)
- (resp/content-type "text/html"))
+ (json-response (exception->json ex) 500)
))))
(def app
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/component.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/component.html b/storm-core/src/ui/public/component.html
new file mode 100644
index 0000000..1286e45
--- /dev/null
+++ b/storm-core/src/ui/public/component.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html><head>
+<title>Storm UI</title>
+<link href="/css/bootstrap-1.4.0.css" rel="stylesheet" type="text/css">
+<link href="/css/style.css" rel="stylesheet" type="text/css">
+<script src="/js/jquery-1.6.2.min.js" type="text/javascript"></script>
+<script src="/js/jquery.tablesorter.min.js" type="text/javascript"></script>
+<script src="/js/jquery.cookies.2.2.0.min.js" type="text/javascript"></script>
+<script src="/js/jquery.mustache.js" type="text/javascript"></script>
+<script src="/js/purl.js" type="text/javascript"></script>
+<script src="/js/bootstrap-twipsy.js" type="text/javascript"></script>
+<script src="/js/script.js" type="text/javascript"></script>
+</head>
+<body>
+<h1><a href="/">Storm UI</a></h1>
+<div id="component-summary">
+</div>
+<div id="component-stats-detail">
+</div>
+<div id="component-input-stats">
+</div>
+<div id="component-output-stats">
+</div>
+<div id="component-executor-stats">
+</div>
+<div id="component-errors">
+</div>
+<div id="error">
+</div>
+<p id="toggle-switch" style="display: block;" class="js-only"></p>
+<script>
+$(document).ready(function() {
+ var componentId = $.url().param("id");
+ var topologyId = $.url().param("topology_id");
+ var window = $.url().param("window");
+ var sys = $.cookies.get("sys") || "false";
+ var url = "/api/topology/"+topologyId+"/component/"+componentId+"?sys="+sys;
+ if(window) url += "&window="+window;
+ renderToggleSys($("#toggle-switch"));
+ $.ajaxSetup({
+ "error":function(jqXHR,textStatus,response) {
+ var errorJson = jQuery.parseJSON(jqXHR.responseText);
+ $.get("/templates/error-template.html", function(template) {
+ $("#error").append(Mustache.render($(template).filter("#error-template").html(),errorJson));
+ });
+ }
+ });
+
+ $.getJSON(url,function(response,status,jqXHR) {
+ var componentSummary = $("#component-summary");
+ var componentStatsDetail = $("#component-stats-detail")
+ var inputStats = $("#component-input-stats");
+ var outputStats = $("#component-output-stats");
+ var executorStats = $("#component-executor-stats");
+ var errors = $("#component-errors");
+ $.get("/templates/component-page-template.html", function(template) {
+ componentSummary.append(Mustache.render($(template).filter("#component-summary-template").html(),response));
+ if(response["componentType"] == "spout") {
+ componentStatsDetail.append(Mustache.render($(template).filter("#spout-stats-detail-template").html(),response));
+ $("#spout-stats-table").tablesorter({ sortList: [[0,0]], headers: {0: { sorter: "stormtimestr"}}});
+ outputStats.append(Mustache.render($(template).filter("#output-stats-template").html(),response));
+ $("#output-stats-table").tablesorter({ sortList: [[0,0]], headers: {0: { sorter: "stormtimestr"}}});
+ executorStats.append(Mustache.render($(template).filter("#executor-stats-template").html(),response));
+ $("#executor-stats-table").tablesorter({ sortList: [[0,0]], headers: {1: { sorter: "stormtimestr"}}});
+ } else {
+ componentStatsDetail.append(Mustache.render($(template).filter("#bolt-stats-template").html(),response));
+ $("#bolt-stats-table").tablesorter({ sortList: [[0,0]], headers: {0: { sorter: "stormtimestr"}}});
+ inputStats.append(Mustache.render($(template).filter("#bolt-input-stats-template").html(),response));
+ if (response["inputStats"].length > 0) {
+ $("#bolt-input-stats-table").tablesorter({ sortList: [[0,0]], headers: {}});
+ }
+ outputStats.append(Mustache.render($(template).filter("#bolt-output-stats-template").html(),response));
+ $("#bolt-output-stats-table").tablesorter({ sortList: [[0,0]], headers: {}});
+ executorStats.append(Mustache.render($(template).filter("#bolt-executor-template").html(),response));
+ if(response["outputStats"].length > 0) {
+ $("#bolt-executor-table").tablesorter({ sortList: [[0,0]], headers: {}});
+ }
+ }
+ errors.append(Mustache.render($(template).filter("#errors-template").html(),response));
+ if(response["errors"].length > 0) {
+ $("#errors-table").tablesorter({ sortList: [[0,0]], headers: {1: { sorter: "stormtimestr"}}});
+ }
+ });
+ });
+});
+</script>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/index.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/index.html b/storm-core/src/ui/public/index.html
new file mode 100644
index 0000000..dc20645
--- /dev/null
+++ b/storm-core/src/ui/public/index.html
@@ -0,0 +1,73 @@
+<html><head>
+<title>Storm UI</title>
+<link href="/css/bootstrap-1.4.0.css" rel="stylesheet" type="text/css">
+<link href="/css/style.css" rel="stylesheet" type="text/css">
+<script src="/js/jquery-1.6.2.min.js" type="text/javascript"></script>
+<script src="/js/jquery.tablesorter.min.js" type="text/javascript"></script>
+<script src="/js/jquery.cookies.2.2.0.min.js" type="text/javascript"></script>
+<script src="/js/jquery.mustache.js" type="text/javascript"></script>
+<script src="/js/bootstrap-twipsy.js" type="text/javascript"></script>
+<script src="/js/script.js" type="text/javascript"></script>
+</head>
+<body>
+<h1><a href="/">Storm UI</a></h1>
+<h2>Cluster Summary</h2>
+<div id="cluster-summary">
+</div>
+<h2>Topology summary</h2>
+<div id="topology-summary">
+</div>
+<h2>Supervisor summary</h2>
+<div id="supervisor-summary">
+</div>
+<h2>Nimbus Configuration</h2>
+<div id="nimbus-configuration"></div>
+<div id="error"></div>
+</body>
+<script>
+$(document).ready(function() {
+ $.ajaxSetup({
+ "error":function(jqXHR,textStatus,response) {
+ var errorJson = jQuery.parseJSON(jqXHR.responseText);
+ $.get("/templates/error-template.html", function(template) {
+ $("#error").append(Mustache.render($(template).filter("#error-template").html(),errorJson));
+ });
+ }
+ });
+ var template = $.get("/templates/index-page-template.html");
+ var clusterSummary = $("#cluster-summary");
+ var topologySummary = $("#topology-summary");
+ var supervisorSummary = $("#supervisor-summary");
+ var config = $("#nimbus-configuration");
+
+ $.getJSON("/api/cluster/summary",function(response,status,jqXHR) {
+ $.get("/templates/index-page-template.html", function(template) {
+ clusterSummary.append(Mustache.render($(template).filter("#cluster-summary-template").html(),response));
+ });
+ });
+ $.getJSON("/api/topology/summary",function(response,status,jqXHR) {
+ $.get("/templates/index-page-template.html", function(template) {
+ topologySummary.append(Mustache.render($(template).filter("#topology-summary-template").html(),response));
+ if(response["topologies"].length > 0) {
+ $("#topology-summary-table").tablesorter({ sortList: [[0,0]], headers: {3: { sorter: "stormtimestr"}}});
+ }
+ });
+ });
+ $.getJSON("/api/supervisor/summary",function(response,status,jqXHR) {
+ $.get("/templates/index-page-template.html", function(template) {
+ supervisorSummary.append(Mustache.render($(template).filter("#supervisor-summary-template").html(),response));
+ if(response["supervisors"].length > 0) {
+ $("#supervisor-summary-table").tablesorter({ sortList: [[0,0]], headers: {3: { sorter: "stormtimestr"}}});
+ }
+ });
+ });
+ $.getJSON("/api/cluster/configuration",function(response,status,jqXHR) {
+ var formattedResponse = formatConfigData(response);
+ $.get("/templates/index-page-template.html", function(template) {
+ config.append(Mustache.render($(template).filter("#configuration-template").html(),formattedResponse));
+ $("#nimbus-configuration-table").tablesorter({ sortList: [[0,0]], headers: {}});
+ });
+ });
+ });
+</script>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/a06fc90e/storm-core/src/ui/public/js/jquery.mustache.js
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/js/jquery.mustache.js b/storm-core/src/ui/public/js/jquery.mustache.js
new file mode 100644
index 0000000..14925bf
--- /dev/null
+++ b/storm-core/src/ui/public/js/jquery.mustache.js
@@ -0,0 +1,592 @@
+/*
+Shameless port of a shameless port
+@defunkt => @janl => @aq
+
+See http://github.com/defunkt/mustache for more info.
+*/
+
+;(function($) {
+
+/*!
+ * mustache.js - Logic-less {{mustache}} templates with JavaScript
+ * http://github.com/janl/mustache.js
+ */
+
+/*global define: false*/
+
+(function (root, factory) {
+ if (typeof exports === "object" && exports) {
+ factory(exports); // CommonJS
+ } else {
+ var mustache = {};
+ factory(mustache);
+ if (typeof define === "function" && define.amd) {
+ define(mustache); // AMD
+ } else {
+ root.Mustache = mustache; // <script>
+ }
+ }
+}(this, function (mustache) {
+
+ var whiteRe = /\s*/;
+ var spaceRe = /\s+/;
+ var nonSpaceRe = /\S/;
+ var eqRe = /\s*=/;
+ var curlyRe = /\s*\}/;
+ var tagRe = /#|\^|\/|>|\{|&|=|!/;
+
+ // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
+ // See https://github.com/janl/mustache.js/issues/189
+ var RegExp_test = RegExp.prototype.test;
+ function testRegExp(re, string) {
+ return RegExp_test.call(re, string);
+ }
+
+ function isWhitespace(string) {
+ return !testRegExp(nonSpaceRe, string);
+ }
+
+ var Object_toString = Object.prototype.toString;
+ var isArray = Array.isArray || function (object) {
+ return Object_toString.call(object) === '[object Array]';
+ };
+
+ function isFunction(object) {
+ return typeof object === 'function';
+ }
+
+ function escapeRegExp(string) {
+ return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
+ }
+
+ var entityMap = {
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ '"': '"',
+ "'": ''',
+ "/": '/'
+ };
+
+ function escapeHtml(string) {
+ return String(string).replace(/[&<>"'\/]/g, function (s) {
+ return entityMap[s];
+ });
+ }
+
+ function escapeTags(tags) {
+ if (!isArray(tags) || tags.length !== 2) {
+ throw new Error('Invalid tags: ' + tags);
+ }
+
+ return [
+ new RegExp(escapeRegExp(tags[0]) + "\\s*"),
+ new RegExp("\\s*" + escapeRegExp(tags[1]))
+ ];
+ }
+
+ /**
+ * Breaks up the given `template` string into a tree of tokens. If the `tags`
+ * argument is given here it must be an array with two string values: the
+ * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
+ * course, the default is to use mustaches (i.e. mustache.tags).
+ *
+ * A token is an array with at least 4 elements. The first element is the
+ * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
+ * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
+ * all template text that appears outside a symbol this element is "text".
+ *
+ * The second element of a token is its "value". For mustache tags this is
+ * whatever else was inside the tag besides the opening symbol. For text tokens
+ * this is the text itself.
+ *
+ * The third and fourth elements of the token are the start and end indices
+ * in the original template of the token, respectively.
+ *
+ * Tokens that are the root node of a subtree contain two more elements: an
+ * array of tokens in the subtree and the index in the original template at which
+ * the closing tag for that section begins.
+ */
+ function parseTemplate(template, tags) {
+ tags = tags || mustache.tags;
+ template = template || '';
+
+ if (typeof tags === 'string') {
+ tags = tags.split(spaceRe);
+ }
+
+ var tagRes = escapeTags(tags);
+ var scanner = new Scanner(template);
+
+ var sections = []; // Stack to hold section tokens
+ var tokens = []; // Buffer to hold the tokens
+ var spaces = []; // Indices of whitespace tokens on the current line
+ var hasTag = false; // Is there a {{tag}} on the current line?
+ var nonSpace = false; // Is there a non-space char on the current line?
+
+ // Strips all whitespace tokens array for the current line
+ // if there was a {{#tag}} on it and otherwise only space.
+ function stripSpace() {
+ if (hasTag && !nonSpace) {
+ while (spaces.length) {
+ delete tokens[spaces.pop()];
+ }
+ } else {
+ spaces = [];
+ }
+
+ hasTag = false;
+ nonSpace = false;
+ }
+
+ var start, type, value, chr, token, openSection;
+ while (!scanner.eos()) {
+ start = scanner.pos;
+
+ // Match any text between tags.
+ value = scanner.scanUntil(tagRes[0]);
+ if (value) {
+ for (var i = 0, len = value.length; i < len; ++i) {
+ chr = value.charAt(i);
+
+ if (isWhitespace(chr)) {
+ spaces.push(tokens.length);
+ } else {
+ nonSpace = true;
+ }
+
+ tokens.push(['text', chr, start, start + 1]);
+ start += 1;
+
+ // Check for whitespace on the current line.
+ if (chr === '\n') {
+ stripSpace();
+ }
+ }
+ }
+
+ // Match the opening tag.
+ if (!scanner.scan(tagRes[0])) break;
+ hasTag = true;
+
+ // Get the tag type.
+ type = scanner.scan(tagRe) || 'name';
+ scanner.scan(whiteRe);
+
+ // Get the tag value.
+ if (type === '=') {
+ value = scanner.scanUntil(eqRe);
+ scanner.scan(eqRe);
+ scanner.scanUntil(tagRes[1]);
+ } else if (type === '{') {
+ value = scanner.scanUntil(new RegExp('\\s*' + escapeRegExp('}' + tags[1])));
+ scanner.scan(curlyRe);
+ scanner.scanUntil(tagRes[1]);
+ type = '&';
+ } else {
+ value = scanner.scanUntil(tagRes[1]);
+ }
+
+ // Match the closing tag.
+ if (!scanner.scan(tagRes[1])) {
+ throw new Error('Unclosed tag at ' + scanner.pos);
+ }
+
+ token = [ type, value, start, scanner.pos ];
+ tokens.push(token);
+
+ if (type === '#' || type === '^') {
+ sections.push(token);
+ } else if (type === '/') {
+ // Check section nesting.
+ openSection = sections.pop();
+
+ if (!openSection) {
+ throw new Error('Unopened section "' + value + '" at ' + start);
+ }
+ if (openSection[1] !== value) {
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
+ }
+ } else if (type === 'name' || type === '{' || type === '&') {
+ nonSpace = true;
+ } else if (type === '=') {
+ // Set the tags for the next time around.
+ tagRes = escapeTags(tags = value.split(spaceRe));
+ }
+ }
+
+ // Make sure there are no open sections when we're done.
+ openSection = sections.pop();
+ if (openSection) {
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
+ }
+
+ return nestTokens(squashTokens(tokens));
+ }
+
+ /**
+ * Combines the values of consecutive text tokens in the given `tokens` array
+ * to a single token.
+ */
+ function squashTokens(tokens) {
+ var squashedTokens = [];
+
+ var token, lastToken;
+ for (var i = 0, len = tokens.length; i < len; ++i) {
+ token = tokens[i];
+
+ if (token) {
+ if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
+ lastToken[1] += token[1];
+ lastToken[3] = token[3];
+ } else {
+ squashedTokens.push(token);
+ lastToken = token;
+ }
+ }
+ }
+
+ return squashedTokens;
+ }
+
+ /**
+ * Forms the given array of `tokens` into a nested tree structure where
+ * tokens that represent a section have two additional items: 1) an array of
+ * all tokens that appear in that section and 2) the index in the original
+ * template that represents the end of that section.
+ */
+ function nestTokens(tokens) {
+ var nestedTokens = [];
+ var collector = nestedTokens;
+ var sections = [];
+
+ var token, section;
+ for (var i = 0, len = tokens.length; i < len; ++i) {
+ token = tokens[i];
+
+ switch (token[0]) {
+ case '#':
+ case '^':
+ collector.push(token);
+ sections.push(token);
+ collector = token[4] = [];
+ break;
+ case '/':
+ section = sections.pop();
+ section[5] = token[2];
+ collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
+ break;
+ default:
+ collector.push(token);
+ }
+ }
+
+ return nestedTokens;
+ }
+
+ /**
+ * A simple string scanner that is used by the template parser to find
+ * tokens in template strings.
+ */
+ function Scanner(string) {
+ this.string = string;
+ this.tail = string;
+ this.pos = 0;
+ }
+
+ /**
+ * Returns `true` if the tail is empty (end of string).
+ */
+ Scanner.prototype.eos = function () {
+ return this.tail === "";
+ };
+
+ /**
+ * Tries to match the given regular expression at the current position.
+ * Returns the matched text if it can match, the empty string otherwise.
+ */
+ Scanner.prototype.scan = function (re) {
+ var match = this.tail.match(re);
+
+ if (match && match.index === 0) {
+ var string = match[0];
+ this.tail = this.tail.substring(string.length);
+ this.pos += string.length;
+ return string;
+ }
+
+ return "";
+ };
+
+ /**
+ * Skips all text until the given regular expression can be matched. Returns
+ * the skipped string, which is the entire tail if no match can be made.
+ */
+ Scanner.prototype.scanUntil = function (re) {
+ var index = this.tail.search(re), match;
+
+ switch (index) {
+ case -1:
+ match = this.tail;
+ this.tail = "";
+ break;
+ case 0:
+ match = "";
+ break;
+ default:
+ match = this.tail.substring(0, index);
+ this.tail = this.tail.substring(index);
+ }
+
+ this.pos += match.length;
+
+ return match;
+ };
+
+ /**
+ * Represents a rendering context by wrapping a view object and
+ * maintaining a reference to the parent context.
+ */
+ function Context(view, parentContext) {
+ this.view = view == null ? {} : view;
+ this.cache = { '.': this.view };
+ this.parent = parentContext;
+ }
+
+ /**
+ * Creates a new context using the given view with this context
+ * as the parent.
+ */
+ Context.prototype.push = function (view) {
+ return new Context(view, this);
+ };
+
+ /**
+ * Returns the value of the given name in this context, traversing
+ * up the context hierarchy if the value is absent in this context's view.
+ */
+ Context.prototype.lookup = function (name) {
+ var value;
+ if (name in this.cache) {
+ value = this.cache[name];
+ } else {
+ var context = this;
+
+ while (context) {
+ if (name.indexOf('.') > 0) {
+ value = context.view;
+
+ var names = name.split('.'), i = 0;
+ while (value != null && i < names.length) {
+ value = value[names[i++]];
+ }
+ } else {
+ value = context.view[name];
+ }
+
+ if (value != null) break;
+
+ context = context.parent;
+ }
+
+ this.cache[name] = value;
+ }
+
+ if (isFunction(value)) {
+ value = value.call(this.view);
+ }
+
+ return value;
+ };
+
+ /**
+ * A Writer knows how to take a stream of tokens and render them to a
+ * string, given a context. It also maintains a cache of templates to
+ * avoid the need to parse the same template twice.
+ */
+ function Writer() {
+ this.cache = {};
+ }
+
+ /**
+ * Clears all cached templates in this writer.
+ */
+ Writer.prototype.clearCache = function () {
+ this.cache = {};
+ };
+
+ /**
+ * Parses and caches the given `template` and returns the array of tokens
+ * that is generated from the parse.
+ */
+ Writer.prototype.parse = function (template, tags) {
+ var cache = this.cache;
+ var tokens = cache[template];
+
+ if (tokens == null) {
+ tokens = cache[template] = parseTemplate(template, tags);
+ }
+
+ return tokens;
+ };
+
+ /**
+ * High-level method that is used to render the given `template` with
+ * the given `view`.
+ *
+ * The optional `partials` argument may be an object that contains the
+ * names and templates of partials that are used in the template. It may
+ * also be a function that is used to load partial templates on the fly
+ * that takes a single argument: the name of the partial.
+ */
+ Writer.prototype.render = function (template, view, partials) {
+ var tokens = this.parse(template);
+ var context = (view instanceof Context) ? view : new Context(view);
+ return this.renderTokens(tokens, context, partials, template);
+ };
+
+ /**
+ * Low-level method that renders the given array of `tokens` using
+ * the given `context` and `partials`.
+ *
+ * Note: The `originalTemplate` is only ever used to extract the portion
+ * of the original template that was contained in a higher-order section.
+ * If the template doesn't use higher-order sections, this argument may
+ * be omitted.
+ */
+ Writer.prototype.renderTokens = function (tokens, context, partials, originalTemplate) {
+ var buffer = '';
+
+ // This function is used to render an arbitrary template
+ // in the current context by higher-order sections.
+ var self = this;
+ function subRender(template) {
+ return self.render(template, context, partials);
+ }
+
+ var token, value;
+ for (var i = 0, len = tokens.length; i < len; ++i) {
+ token = tokens[i];
+
+ switch (token[0]) {
+ case '#':
+ value = context.lookup(token[1]);
+ if (!value) continue;
+
+ if (isArray(value)) {
+ for (var j = 0, jlen = value.length; j < jlen; ++j) {
+ buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
+ }
+ } else if (typeof value === 'object' || typeof value === 'string') {
+ buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
+ } else if (isFunction(value)) {
+ if (typeof originalTemplate !== 'string') {
+ throw new Error('Cannot use higher-order sections without the original template');
+ }
+
+ // Extract the portion of the original template that the section contains.
+ value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
+
+ if (value != null) buffer += value;
+ } else {
+ buffer += this.renderTokens(token[4], context, partials, originalTemplate);
+ }
+
+ break;
+ case '^':
+ value = context.lookup(token[1]);
+
+ // Use JavaScript's definition of falsy. Include empty arrays.
+ // See https://github.com/janl/mustache.js/issues/186
+ if (!value || (isArray(value) && value.length === 0)) {
+ buffer += this.renderTokens(token[4], context, partials, originalTemplate);
+ }
+
+ break;
+ case '>':
+ if (!partials) continue;
+ value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
+ if (value != null) buffer += this.renderTokens(this.parse(value), context, partials, value);
+ break;
+ case '&':
+ value = context.lookup(token[1]);
+ if (value != null) buffer += value;
+ break;
+ case 'name':
+ value = context.lookup(token[1]);
+ if (value != null) buffer += mustache.escape(value);
+ break;
+ case 'text':
+ buffer += token[1];
+ break;
+ }
+ }
+
+ return buffer;
+ };
+
+ mustache.name = "mustache.js";
+ mustache.version = "0.8.1";
+ mustache.tags = [ "{{", "}}" ];
+
+ // All high-level mustache.* functions use this writer.
+ var defaultWriter = new Writer();
+
+ /**
+ * Clears all cached templates in the default writer.
+ */
+ mustache.clearCache = function () {
+ return defaultWriter.clearCache();
+ };
+
+ /**
+ * Parses and caches the given template in the default writer and returns the
+ * array of tokens it contains. Doing this ahead of time avoids the need to
+ * parse templates on the fly as they are rendered.
+ */
+ mustache.parse = function (template, tags) {
+ return defaultWriter.parse(template, tags);
+ };
+
+ /**
+ * Renders the `template` with the given `view` and `partials` using the
+ * default writer.
+ */
+ mustache.render = function (template, view, partials) {
+ return defaultWriter.render(template, view, partials);
+ };
+
+ // This is here for backwards compatibility with 0.4.x.
+ mustache.to_html = function (template, view, partials, send) {
+ var result = mustache.render(template, view, partials);
+
+ if (isFunction(send)) {
+ send(result);
+ } else {
+ return result;
+ }
+ };
+
+ // Export the escaping function so that the user may override it.
+ // See https://github.com/janl/mustache.js/issues/244
+ mustache.escape = escapeHtml;
+
+ // Export these mainly for testing, but also for advanced usage.
+ mustache.Scanner = Scanner;
+ mustache.Context = Context;
+ mustache.Writer = Writer;
+
+}));
+ $.mustache = function (template, view, partials) {
+ return Mustache.render(template, view, partials);
+ };
+
+ $.fn.mustache = function (view, partials) {
+ return $(this).map(function (i, elm) {
+ var template = $.trim($(elm).html());
+ var output = $.mustache(template, view, partials);
+ return $(output).get();
+ });
+ };
+
+})(jQuery);
[05/13] git commit: removing unnecessary helper func print-map
Posted by bo...@apache.org.
removing unnecessary helper func print-map
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/1333d485
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/1333d485
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/1333d485
Branch: refs/heads/master
Commit: 1333d48524eff0f37ecdaef07c8649037eb323e8
Parents: 453a4a3
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Thu May 8 10:42:39 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Thu May 8 10:42:39 2014 -0700
----------------------------------------------------------------------
storm-core/src/clj/backtype/storm/ui/core.clj | 5 -----
1 file changed, 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/1333d485/storm-core/src/clj/backtype/storm/ui/core.clj
----------------------------------------------------------------------
diff --git a/storm-core/src/clj/backtype/storm/ui/core.clj b/storm-core/src/clj/backtype/storm/ui/core.clj
index 505adb0..1e71923 100644
--- a/storm-core/src/clj/backtype/storm/ui/core.clj
+++ b/storm-core/src/clj/backtype/storm/ui/core.clj
@@ -309,11 +309,6 @@
(StringEscapeUtils/escapeJavaScript name) "', '"
command "', " is-wait ", " default-wait ")")}])
-(defn print-map [t]
- (doseq [[k v] t]
- (log-message "key " k " value " v)
- ))
-
(defn cluster-configuration []
(with-nimbus nimbus
(.getNimbusConf ^Nimbus$Client nimbus)))
[12/13] git commit: Merge branch 'ui-rest-new' of
https://github.com/harshach/incubator-storm into STORM-205
Posted by bo...@apache.org.
Merge branch 'ui-rest-new' of https://github.com/harshach/incubator-storm into STORM-205
STORM-205. Add Rest API to Storm.
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/baee2f4d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/baee2f4d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/baee2f4d
Branch: refs/heads/master
Commit: baee2f4d3543315c040756caa6cf9881c44ee803
Parents: eee8b24 71817e7
Author: Robert (Bobby) Evans <bo...@apache.org>
Authored: Tue Jun 3 19:27:45 2014 -0500
Committer: Robert (Bobby) Evans <bo...@apache.org>
Committed: Tue Jun 3 19:27:45 2014 -0500
----------------------------------------------------------------------
.gitignore | 4 +-
storm-core/src/clj/backtype/storm/ui/core.clj | 1076 ++++++------------
storm-core/src/ui/public/component.html | 88 ++
storm-core/src/ui/public/index.html | 73 ++
storm-core/src/ui/public/js/jquery.mustache.js | 592 ++++++++++
storm-core/src/ui/public/js/purl.js | 267 +++++
storm-core/src/ui/public/js/script.js | 51 +-
.../templates/component-page-template.html | 152 +++
.../public/templates/index-page-template.html | 62 +
.../public/templates/json-error-template.html | 4 +
.../templates/topology-page-template.html | 97 ++
storm-core/src/ui/public/topology.html | 80 ++
12 files changed, 1818 insertions(+), 728 deletions(-)
----------------------------------------------------------------------
[09/13] git commit: STORM-205. Add REST API to Storm UI. fixed typo.
Posted by bo...@apache.org.
STORM-205. Add REST API to Storm UI.
fixed typo.
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/e538ffee
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/e538ffee
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/e538ffee
Branch: refs/heads/master
Commit: e538ffee70646a17d2d848e287da84c5098b92e7
Parents: 2a8f777
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Fri May 30 07:55:52 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Fri May 30 07:55:52 2014 -0700
----------------------------------------------------------------------
storm-core/src/clj/backtype/storm/ui/core.clj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/e538ffee/storm-core/src/clj/backtype/storm/ui/core.clj
----------------------------------------------------------------------
diff --git a/storm-core/src/clj/backtype/storm/ui/core.clj b/storm-core/src/clj/backtype/storm/ui/core.clj
index a25327b..be20b51 100644
--- a/storm-core/src/clj/backtype/storm/ui/core.clj
+++ b/storm-core/src/clj/backtype/storm/ui/core.clj
@@ -288,7 +288,7 @@
(select-keys agg-spout-stats [:emitted :transferred :acked :failed :complete-latencies])
)))
-(Defn stats-times [stats-map]
+(defn stats-times [stats-map]
(sort-by #(Integer/parseInt %)
(-> stats-map
clojurify-structure
[06/13] git commit: STORM-205. Add REST API to Storm UI. added
complete-latencies to the topology-stats
Posted by bo...@apache.org.
STORM-205. Add REST API to Storm UI.
added complete-latencies to the topology-stats
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/688444a9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/688444a9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/688444a9
Branch: refs/heads/master
Commit: 688444a96a5b2abf28faa0b7220e1436a0e951e3
Parents: 1333d48
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Wed May 28 20:14:12 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Wed May 28 20:14:12 2014 -0700
----------------------------------------------------------------------
storm-core/src/clj/backtype/storm/ui/core.clj | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/688444a9/storm-core/src/clj/backtype/storm/ui/core.clj
----------------------------------------------------------------------
diff --git a/storm-core/src/clj/backtype/storm/ui/core.clj b/storm-core/src/clj/backtype/storm/ui/core.clj
index 1e71923..d77ccb6 100644
--- a/storm-core/src/clj/backtype/storm/ui/core.clj
+++ b/storm-core/src/clj/backtype/storm/ui/core.clj
@@ -284,8 +284,8 @@
(merge-with
(fn [s1 s2]
(merge-with + s1 s2))
- (select-keys agg-bolt-stats [:emitted :transferred :acked :failed])
- (select-keys agg-spout-stats [:emitted :transferred :acked :failed])
+ (select-keys agg-bolt-stats [:emitted :transferred :acked :failed :complete-latencies])
+ (select-keys agg-spout-stats [:emitted :transferred :acked :failed :complete-latencies])
)))
(defn stats-times [stats-map]
[10/13] git commit: STORM-205. Add REST API to Storm UI. removed
empty topologies element from cluster-summary.
Posted by bo...@apache.org.
STORM-205. Add REST API to Storm UI.
removed empty topologies element from cluster-summary.
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/49a9a92f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/49a9a92f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/49a9a92f
Branch: refs/heads/master
Commit: 49a9a92f79546f8a44e8664e422e26c187b73ee2
Parents: e538ffe
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Sat May 31 14:14:13 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Sat May 31 14:14:13 2014 -0700
----------------------------------------------------------------------
storm-core/src/clj/backtype/storm/ui/core.clj | 1 -
1 file changed, 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/49a9a92f/storm-core/src/clj/backtype/storm/ui/core.clj
----------------------------------------------------------------------
diff --git a/storm-core/src/clj/backtype/storm/ui/core.clj b/storm-core/src/clj/backtype/storm/ui/core.clj
index be20b51..f523d7a 100644
--- a/storm-core/src/clj/backtype/storm/ui/core.clj
+++ b/storm-core/src/clj/backtype/storm/ui/core.clj
@@ -331,7 +331,6 @@
{ "stormVersion" (read-storm-version)
"nimbusUptime" (pretty-uptime-sec (.get_nimbus_uptime_secs summ))
"supervisors" (count sups)
- "topologies" ""
"slotsTotal" total-slots
"slotsUsed" used-slots
"slotsFree" free-slots
[03/13] git commit: fixed td close in topology-page-template.html,
fixed topology stats and bolt stats.
Posted by bo...@apache.org.
fixed td close in topology-page-template.html,
fixed topology stats and bolt stats.
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/7f058e19
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/7f058e19
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/7f058e19
Branch: refs/heads/master
Commit: 7f058e19425ff712d9f8034b3641c06af885535e
Parents: a06fc90
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Tue May 6 17:38:16 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Tue May 6 17:38:16 2014 -0700
----------------------------------------------------------------------
storm-core/src/clj/backtype/storm/ui/core.clj | 55 ++++++++++----------
.../templates/topology-page-template.html | 2 +-
2 files changed, 29 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/7f058e19/storm-core/src/clj/backtype/storm/ui/core.clj
----------------------------------------------------------------------
diff --git a/storm-core/src/clj/backtype/storm/ui/core.clj b/storm-core/src/clj/backtype/storm/ui/core.clj
index 7943677..505adb0 100644
--- a/storm-core/src/clj/backtype/storm/ui/core.clj
+++ b/storm-core/src/clj/backtype/storm/ui/core.clj
@@ -231,12 +231,8 @@
reverse
first)]
(if error
- [:span (if (< (time-delta (.get_error_time_secs ^ErrorInfo error))
- (* 60 30))
- {:class "red"}
- {})
- (error-subset (.get_error ^ErrorInfo error))]
- )))
+ (error-subset (.get_error ^ErrorInfo error))
+ "")))
(defn component-task-summs [^TopologyInfo summ topology id]
(let [spout-summs (filter (partial spout-summary? topology) (.get_executors summ))
@@ -288,8 +284,8 @@
(merge-with
(fn [s1 s2]
(merge-with + s1 s2))
- (select-keys agg-bolt-stats [:emitted :transferred])
- agg-spout-stats
+ (select-keys agg-bolt-stats [:emitted :transferred :acked :failed])
+ (select-keys agg-spout-stats [:emitted :transferred :acked :failed])
)))
(defn stats-times [stats-map]
@@ -313,6 +309,11 @@
(StringEscapeUtils/escapeJavaScript name) "', '"
command "', " is-wait ", " default-wait ")")}])
+(defn print-map [t]
+ (doseq [[k v] t]
+ (log-message "key " k " value " v)
+ ))
+
(defn cluster-configuration []
(with-nimbus nimbus
(.getNimbusConf ^Nimbus$Client nimbus)))
@@ -366,7 +367,7 @@
{"id" (.get_id t)
"name" (.get_name t)
"status" (.get_status t)
- "uptime" (.get_uptime_secs t)
+ "uptime" (pretty-uptime-sec (.get_uptime_secs t))
"tasksTotal" (.get_num_tasks t)
"workersTotal" (.get_num_workers t)
"executorsTotal" (.get_num_executors t)})
@@ -399,10 +400,10 @@
"tasks" (sum-tasks summs)
"emitted" (get-in stats [:emitted window])
"transferred" (get-in stats [:transferred window])
- "complete_latency" (float-str (get-in stats [:complete-latencies window]))
+ "completeLatency" (float-str (get-in stats [:complete-latencies window]))
"acked" (get-in stats [:acked window])
"failed" (get-in stats [:failed window])
- "last_error" (most-recent-error (get errors id))
+ "lastError" (most-recent-error (get errors id))
}))
(defn bolt-comp [top-id summ-map errors window include-sys?]
@@ -416,14 +417,14 @@
"executors" (count summs)
"tasks" (sum-tasks summs)
"emitted" (get-in stats [:emitted window])
- "trasnferred" (get-in stats [:transferred window])
- "capacity" (compute-bolt-capacity summs)
- "execute_latency" (float-str (get-in stats [:execute-latencies window]))
+ "transferred" (get-in stats [:transferred window])
+ "capacity" (float-str (nil-to-zero (compute-bolt-capacity summs)))
+ "executeLatency" (float-str (get-in stats [:execute-latencies window]))
"executed" (get-in stats [:executed window])
- "process_latency" (float-str (get-in stats [:process-latencies window]))
+ "processLatency" (float-str (get-in stats [:process-latencies window]))
"acked" (get-in stats [:acked window])
"failed" (get-in stats [:failed window])
- "last_error" (most-recent-error (get errors id))
+ "lastError" (most-recent-error (get errors id))
}
))
@@ -439,7 +440,7 @@
"executorsTotal" (count executors)}
))
-(defn spout-summary [topology-id id stats window]
+(defn spout-summary-json [topology-id id stats window]
(let [times (stats-times (:emitted stats))
display-map (into {} (for [t times] [t pretty-uptime-sec]))
display-map (assoc display-map ":all-time" (fn [_] "All time"))]
@@ -488,7 +489,7 @@
{"stream" s
"emitted" (nil-to-zero (:emitted stats))
"transferred" (nil-to-zero (:transferred stats))
- "complete_latency" (float-str (:complete-latencies stats))
+ "completeLatency" (float-str (:complete-latencies stats))
"acked" (nil-to-zero (:acked stats))
"failed" (nil-to-zero (:failed stats))
}
@@ -532,7 +533,7 @@
stats (get-filled-stats executors)
stream-summary (-> stats (aggregate-spout-stats include-sys?))
summary (-> stream-summary aggregate-spout-streams)]
- {"spoutSummary" (spout-summary (.get_id topology-info) component summary window)
+ {"spoutSummary" (spout-summary-json (.get_id topology-info) component summary window)
"outputStats" (spout-output-stats stream-summary window)
"executorStats" (spout-executor-stats (.get_id topology-info) executors window include-sys?)}
))
@@ -596,7 +597,7 @@
"port" (.get_port e)
"emitted" (nil-to-zero (:emitted stats))
"transferred" (nil-to-zero (:transferred stats))
- "capacity" (compute-executor-capacity e)
+ "capacity" (float-str (nil-to-zero (compute-executor-capacity e)))
"executeLatency" (float-str (:execute-latencies stats))
"executed" (nil-to-zero (:executed stats))
"processLatency" (float-str (:process-latencies stats))
@@ -656,15 +657,15 @@
(GET "/api/topology/summary" []
(json-response (all-topologies-summary)))
(GET "/api/topology/:id" [id & m]
- (let [id (java.net.URLDecoder/decode id)]
+ (let [id (url-decode id)]
(json-response (topology-page id (:window m) (check-include-sys? (:sys m))))))
(GET "/api/topology/:id/component/:component" [id component & m]
- (let [id (java.net.URLDecoder/decode id)
- component (java.net.URLDecoder/decode component)]
+ (let [id (url-decode id)
+ component (url-decode component)]
(json-response (component-page id component (:window m) (check-include-sys? (:sys m))))))
(POST "/api/topology/:id/activate" [id]
(with-nimbus nimbus
- (let [id (java.net.URLDecoder/decode id)
+ (let [id (url-decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)]
(.activate nimbus name)
@@ -673,7 +674,7 @@
(POST "/api/topology/:id/deactivate" [id]
(with-nimbus nimbus
- (let [id (java.net.URLDecoder/decode id)
+ (let [id (url-decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)]
(.deactivate nimbus name)
@@ -681,7 +682,7 @@
(resp/redirect (str "/api/topology/" id)))
(POST "/api/topology/:id/rebalance/:wait-time" [id wait-time]
(with-nimbus nimbus
- (let [id (java.net.URLDecoder/decode id)
+ (let [id (url-decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)
options (RebalanceOptions.)]
@@ -691,7 +692,7 @@
(resp/redirect (str "/api/topology/" id)))
(POST "/api/topology/:id/kill/:wait-time" [id wait-time]
(with-nimbus nimbus
- (let [id (java.net.URLDecoder/decode id)
+ (let [id (url-decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)
options (KillOptions.)]
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/7f058e19/storm-core/src/ui/public/templates/topology-page-template.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/templates/topology-page-template.html b/storm-core/src/ui/public/templates/topology-page-template.html
index abe82ee..cbeb8fd 100644
--- a/storm-core/src/ui/public/templates/topology-page-template.html
+++ b/storm-core/src/ui/public/templates/topology-page-template.html
@@ -58,7 +58,7 @@
<td><a href="/component.html?id={{spoutId}}&topology_id={{id}}">{{spoutId}}</a></td>
<td>{{executors}}</td>
<td>{{tasks}}</td>
-<td>{{emitted}}<td>
+<td>{{emitted}}</td>
<td>{{transferred}}</td>
<td>{{completeLatency}}</td>
<td>{{acked}}</td>
[04/13] git commit: jquery.mustache.js is being used instead of
mustache.js deleting unnecessary file
Posted by bo...@apache.org.
jquery.mustache.js is being used instead of mustache.js deleting
unnecessary file
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/453a4a35
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/453a4a35
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/453a4a35
Branch: refs/heads/master
Commit: 453a4a3516166978d1ca298386613ab88e2cc1a0
Parents: 7f058e1
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Wed May 7 08:12:01 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Wed May 7 08:12:01 2014 -0700
----------------------------------------------------------------------
storm-core/src/ui/public/js/mustache.js | 570 ---------------------------
1 file changed, 570 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/453a4a35/storm-core/src/ui/public/js/mustache.js
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/js/mustache.js b/storm-core/src/ui/public/js/mustache.js
deleted file mode 100644
index 3a84b74..0000000
--- a/storm-core/src/ui/public/js/mustache.js
+++ /dev/null
@@ -1,570 +0,0 @@
-/*!
- * mustache.js - Logic-less {{mustache}} templates with JavaScript
- * http://github.com/janl/mustache.js
- */
-
-/*global define: false*/
-
-(function (root, factory) {
- if (typeof exports === "object" && exports) {
- factory(exports); // CommonJS
- } else {
- var mustache = {};
- factory(mustache);
- if (typeof define === "function" && define.amd) {
- define(mustache); // AMD
- } else {
- root.Mustache = mustache; // <script>
- }
- }
-}(this, function (mustache) {
-
- var whiteRe = /\s*/;
- var spaceRe = /\s+/;
- var nonSpaceRe = /\S/;
- var eqRe = /\s*=/;
- var curlyRe = /\s*\}/;
- var tagRe = /#|\^|\/|>|\{|&|=|!/;
-
- // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
- // See https://github.com/janl/mustache.js/issues/189
- var RegExp_test = RegExp.prototype.test;
- function testRegExp(re, string) {
- return RegExp_test.call(re, string);
- }
-
- function isWhitespace(string) {
- return !testRegExp(nonSpaceRe, string);
- }
-
- var Object_toString = Object.prototype.toString;
- var isArray = Array.isArray || function (object) {
- return Object_toString.call(object) === '[object Array]';
- };
-
- function isFunction(object) {
- return typeof object === 'function';
- }
-
- function escapeRegExp(string) {
- return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
- }
-
- var entityMap = {
- "&": "&",
- "<": "<",
- ">": ">",
- '"': '"',
- "'": ''',
- "/": '/'
- };
-
- function escapeHtml(string) {
- return String(string).replace(/[&<>"'\/]/g, function (s) {
- return entityMap[s];
- });
- }
-
- function escapeTags(tags) {
- if (!isArray(tags) || tags.length !== 2) {
- throw new Error('Invalid tags: ' + tags);
- }
-
- return [
- new RegExp(escapeRegExp(tags[0]) + "\\s*"),
- new RegExp("\\s*" + escapeRegExp(tags[1]))
- ];
- }
-
- /**
- * Breaks up the given `template` string into a tree of tokens. If the `tags`
- * argument is given here it must be an array with two string values: the
- * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
- * course, the default is to use mustaches (i.e. mustache.tags).
- *
- * A token is an array with at least 4 elements. The first element is the
- * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
- * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
- * all template text that appears outside a symbol this element is "text".
- *
- * The second element of a token is its "value". For mustache tags this is
- * whatever else was inside the tag besides the opening symbol. For text tokens
- * this is the text itself.
- *
- * The third and fourth elements of the token are the start and end indices
- * in the original template of the token, respectively.
- *
- * Tokens that are the root node of a subtree contain two more elements: an
- * array of tokens in the subtree and the index in the original template at which
- * the closing tag for that section begins.
- */
- function parseTemplate(template, tags) {
- tags = tags || mustache.tags;
- template = template || '';
-
- if (typeof tags === 'string') {
- tags = tags.split(spaceRe);
- }
-
- var tagRes = escapeTags(tags);
- var scanner = new Scanner(template);
-
- var sections = []; // Stack to hold section tokens
- var tokens = []; // Buffer to hold the tokens
- var spaces = []; // Indices of whitespace tokens on the current line
- var hasTag = false; // Is there a {{tag}} on the current line?
- var nonSpace = false; // Is there a non-space char on the current line?
-
- // Strips all whitespace tokens array for the current line
- // if there was a {{#tag}} on it and otherwise only space.
- function stripSpace() {
- if (hasTag && !nonSpace) {
- while (spaces.length) {
- delete tokens[spaces.pop()];
- }
- } else {
- spaces = [];
- }
-
- hasTag = false;
- nonSpace = false;
- }
-
- var start, type, value, chr, token, openSection;
- while (!scanner.eos()) {
- start = scanner.pos;
-
- // Match any text between tags.
- value = scanner.scanUntil(tagRes[0]);
- if (value) {
- for (var i = 0, len = value.length; i < len; ++i) {
- chr = value.charAt(i);
-
- if (isWhitespace(chr)) {
- spaces.push(tokens.length);
- } else {
- nonSpace = true;
- }
-
- tokens.push(['text', chr, start, start + 1]);
- start += 1;
-
- // Check for whitespace on the current line.
- if (chr === '\n') {
- stripSpace();
- }
- }
- }
-
- // Match the opening tag.
- if (!scanner.scan(tagRes[0])) break;
- hasTag = true;
-
- // Get the tag type.
- type = scanner.scan(tagRe) || 'name';
- scanner.scan(whiteRe);
-
- // Get the tag value.
- if (type === '=') {
- value = scanner.scanUntil(eqRe);
- scanner.scan(eqRe);
- scanner.scanUntil(tagRes[1]);
- } else if (type === '{') {
- value = scanner.scanUntil(new RegExp('\\s*' + escapeRegExp('}' + tags[1])));
- scanner.scan(curlyRe);
- scanner.scanUntil(tagRes[1]);
- type = '&';
- } else {
- value = scanner.scanUntil(tagRes[1]);
- }
-
- // Match the closing tag.
- if (!scanner.scan(tagRes[1])) {
- throw new Error('Unclosed tag at ' + scanner.pos);
- }
-
- token = [ type, value, start, scanner.pos ];
- tokens.push(token);
-
- if (type === '#' || type === '^') {
- sections.push(token);
- } else if (type === '/') {
- // Check section nesting.
- openSection = sections.pop();
-
- if (!openSection) {
- throw new Error('Unopened section "' + value + '" at ' + start);
- }
- if (openSection[1] !== value) {
- throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
- }
- } else if (type === 'name' || type === '{' || type === '&') {
- nonSpace = true;
- } else if (type === '=') {
- // Set the tags for the next time around.
- tagRes = escapeTags(tags = value.split(spaceRe));
- }
- }
-
- // Make sure there are no open sections when we're done.
- openSection = sections.pop();
- if (openSection) {
- throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
- }
-
- return nestTokens(squashTokens(tokens));
- }
-
- /**
- * Combines the values of consecutive text tokens in the given `tokens` array
- * to a single token.
- */
- function squashTokens(tokens) {
- var squashedTokens = [];
-
- var token, lastToken;
- for (var i = 0, len = tokens.length; i < len; ++i) {
- token = tokens[i];
-
- if (token) {
- if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
- lastToken[1] += token[1];
- lastToken[3] = token[3];
- } else {
- squashedTokens.push(token);
- lastToken = token;
- }
- }
- }
-
- return squashedTokens;
- }
-
- /**
- * Forms the given array of `tokens` into a nested tree structure where
- * tokens that represent a section have two additional items: 1) an array of
- * all tokens that appear in that section and 2) the index in the original
- * template that represents the end of that section.
- */
- function nestTokens(tokens) {
- var nestedTokens = [];
- var collector = nestedTokens;
- var sections = [];
-
- var token, section;
- for (var i = 0, len = tokens.length; i < len; ++i) {
- token = tokens[i];
-
- switch (token[0]) {
- case '#':
- case '^':
- collector.push(token);
- sections.push(token);
- collector = token[4] = [];
- break;
- case '/':
- section = sections.pop();
- section[5] = token[2];
- collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
- break;
- default:
- collector.push(token);
- }
- }
-
- return nestedTokens;
- }
-
- /**
- * A simple string scanner that is used by the template parser to find
- * tokens in template strings.
- */
- function Scanner(string) {
- this.string = string;
- this.tail = string;
- this.pos = 0;
- }
-
- /**
- * Returns `true` if the tail is empty (end of string).
- */
- Scanner.prototype.eos = function () {
- return this.tail === "";
- };
-
- /**
- * Tries to match the given regular expression at the current position.
- * Returns the matched text if it can match, the empty string otherwise.
- */
- Scanner.prototype.scan = function (re) {
- var match = this.tail.match(re);
-
- if (match && match.index === 0) {
- var string = match[0];
- this.tail = this.tail.substring(string.length);
- this.pos += string.length;
- return string;
- }
-
- return "";
- };
-
- /**
- * Skips all text until the given regular expression can be matched. Returns
- * the skipped string, which is the entire tail if no match can be made.
- */
- Scanner.prototype.scanUntil = function (re) {
- var index = this.tail.search(re), match;
-
- switch (index) {
- case -1:
- match = this.tail;
- this.tail = "";
- break;
- case 0:
- match = "";
- break;
- default:
- match = this.tail.substring(0, index);
- this.tail = this.tail.substring(index);
- }
-
- this.pos += match.length;
-
- return match;
- };
-
- /**
- * Represents a rendering context by wrapping a view object and
- * maintaining a reference to the parent context.
- */
- function Context(view, parentContext) {
- this.view = view == null ? {} : view;
- this.cache = { '.': this.view };
- this.parent = parentContext;
- }
-
- /**
- * Creates a new context using the given view with this context
- * as the parent.
- */
- Context.prototype.push = function (view) {
- return new Context(view, this);
- };
-
- /**
- * Returns the value of the given name in this context, traversing
- * up the context hierarchy if the value is absent in this context's view.
- */
- Context.prototype.lookup = function (name) {
- var value;
- if (name in this.cache) {
- value = this.cache[name];
- } else {
- var context = this;
-
- while (context) {
- if (name.indexOf('.') > 0) {
- value = context.view;
-
- var names = name.split('.'), i = 0;
- while (value != null && i < names.length) {
- value = value[names[i++]];
- }
- } else {
- value = context.view[name];
- }
-
- if (value != null) break;
-
- context = context.parent;
- }
-
- this.cache[name] = value;
- }
-
- if (isFunction(value)) {
- value = value.call(this.view);
- }
-
- return value;
- };
-
- /**
- * A Writer knows how to take a stream of tokens and render them to a
- * string, given a context. It also maintains a cache of templates to
- * avoid the need to parse the same template twice.
- */
- function Writer() {
- this.cache = {};
- }
-
- /**
- * Clears all cached templates in this writer.
- */
- Writer.prototype.clearCache = function () {
- this.cache = {};
- };
-
- /**
- * Parses and caches the given `template` and returns the array of tokens
- * that is generated from the parse.
- */
- Writer.prototype.parse = function (template, tags) {
- var cache = this.cache;
- var tokens = cache[template];
-
- if (tokens == null) {
- tokens = cache[template] = parseTemplate(template, tags);
- }
-
- return tokens;
- };
-
- /**
- * High-level method that is used to render the given `template` with
- * the given `view`.
- *
- * The optional `partials` argument may be an object that contains the
- * names and templates of partials that are used in the template. It may
- * also be a function that is used to load partial templates on the fly
- * that takes a single argument: the name of the partial.
- */
- Writer.prototype.render = function (template, view, partials) {
- var tokens = this.parse(template);
- var context = (view instanceof Context) ? view : new Context(view);
- return this.renderTokens(tokens, context, partials, template);
- };
-
- /**
- * Low-level method that renders the given array of `tokens` using
- * the given `context` and `partials`.
- *
- * Note: The `originalTemplate` is only ever used to extract the portion
- * of the original template that was contained in a higher-order section.
- * If the template doesn't use higher-order sections, this argument may
- * be omitted.
- */
- Writer.prototype.renderTokens = function (tokens, context, partials, originalTemplate) {
- var buffer = '';
-
- // This function is used to render an arbitrary template
- // in the current context by higher-order sections.
- var self = this;
- function subRender(template) {
- return self.render(template, context, partials);
- }
-
- var token, value;
- for (var i = 0, len = tokens.length; i < len; ++i) {
- token = tokens[i];
-
- switch (token[0]) {
- case '#':
- value = context.lookup(token[1]);
- if (!value) continue;
-
- if (isArray(value)) {
- for (var j = 0, jlen = value.length; j < jlen; ++j) {
- buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
- }
- } else if (typeof value === 'object' || typeof value === 'string') {
- buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
- } else if (isFunction(value)) {
- if (typeof originalTemplate !== 'string') {
- throw new Error('Cannot use higher-order sections without the original template');
- }
-
- // Extract the portion of the original template that the section contains.
- value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
-
- if (value != null) buffer += value;
- } else {
- buffer += this.renderTokens(token[4], context, partials, originalTemplate);
- }
-
- break;
- case '^':
- value = context.lookup(token[1]);
-
- // Use JavaScript's definition of falsy. Include empty arrays.
- // See https://github.com/janl/mustache.js/issues/186
- if (!value || (isArray(value) && value.length === 0)) {
- buffer += this.renderTokens(token[4], context, partials, originalTemplate);
- }
-
- break;
- case '>':
- if (!partials) continue;
- value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
- if (value != null) buffer += this.renderTokens(this.parse(value), context, partials, value);
- break;
- case '&':
- value = context.lookup(token[1]);
- if (value != null) buffer += value;
- break;
- case 'name':
- value = context.lookup(token[1]);
- if (value != null) buffer += mustache.escape(value);
- break;
- case 'text':
- buffer += token[1];
- break;
- }
- }
-
- return buffer;
- };
-
- mustache.name = "mustache.js";
- mustache.version = "0.8.1";
- mustache.tags = [ "{{", "}}" ];
-
- // All high-level mustache.* functions use this writer.
- var defaultWriter = new Writer();
-
- /**
- * Clears all cached templates in the default writer.
- */
- mustache.clearCache = function () {
- return defaultWriter.clearCache();
- };
-
- /**
- * Parses and caches the given template in the default writer and returns the
- * array of tokens it contains. Doing this ahead of time avoids the need to
- * parse templates on the fly as they are rendered.
- */
- mustache.parse = function (template, tags) {
- return defaultWriter.parse(template, tags);
- };
-
- /**
- * Renders the `template` with the given `view` and `partials` using the
- * default writer.
- */
- mustache.render = function (template, view, partials) {
- return defaultWriter.render(template, view, partials);
- };
-
- // This is here for backwards compatibility with 0.4.x.
- mustache.to_html = function (template, view, partials, send) {
- var result = mustache.render(template, view, partials);
-
- if (isFunction(send)) {
- send(result);
- } else {
- return result;
- }
- };
-
- // Export the escaping function so that the user may override it.
- // See https://github.com/janl/mustache.js/issues/244
- mustache.escape = escapeHtml;
-
- // Export these mainly for testing, but also for advanced usage.
- mustache.Scanner = Scanner;
- mustache.Context = Context;
- mustache.Writer = Writer;
-
-}));
[11/13] git commit: STORM-205. Add REST API to Storm UI. Fixed
component errors response. Changed naming of template ids and div.
Posted by bo...@apache.org.
STORM-205. Add REST API to Storm UI.
Fixed component errors response. Changed naming of template ids and div.
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/71817e7e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/71817e7e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/71817e7e
Branch: refs/heads/master
Commit: 71817e7e14412a29764271ecbb2e59f6e227400e
Parents: 49a9a92
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Mon Jun 2 11:09:25 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Mon Jun 2 11:09:25 2014 -0700
----------------------------------------------------------------------
storm-core/src/clj/backtype/storm/ui/core.clj | 7 +++----
storm-core/src/ui/public/component.html | 14 +++++++-------
storm-core/src/ui/public/index.html | 6 +++---
.../ui/public/templates/component-page-template.html | 8 ++++----
.../src/ui/public/templates/error-template.html | 4 ----
.../src/ui/public/templates/json-error-template.html | 4 ++++
storm-core/src/ui/public/topology.html | 7 +++----
7 files changed, 24 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/71817e7e/storm-core/src/clj/backtype/storm/ui/core.clj
----------------------------------------------------------------------
diff --git a/storm-core/src/clj/backtype/storm/ui/core.clj b/storm-core/src/clj/backtype/storm/ui/core.clj
index f523d7a..ba6827c 100644
--- a/storm-core/src/clj/backtype/storm/ui/core.clj
+++ b/storm-core/src/clj/backtype/storm/ui/core.clj
@@ -515,12 +515,11 @@
(let [errors (->> errors-list
(sort-by #(.get_error_time_secs ^ErrorInfo %))
reverse)]
- {"errors"
+ {"componentErrors"
(for [^ErrorInfo e errors]
- [{"time" (date-str (.get_error_time_secs e))
+ {"time" (date-str (.get_error_time_secs e))
"error" (.get_error e)
- }])}
- ))
+ })}))
(defn spout-stats [window ^TopologyInfo topology-info component executors include-sys?]
(let [window-hint (str " (" (window-hint window) ")")
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/71817e7e/storm-core/src/ui/public/component.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/component.html b/storm-core/src/ui/public/component.html
index 432b33d..90ca630 100644
--- a/storm-core/src/ui/public/component.html
+++ b/storm-core/src/ui/public/component.html
@@ -25,7 +25,7 @@
</div>
<div id="component-errors">
</div>
-<div id="error">
+<div id="json-response-error">
</div>
<p id="toggle-switch" style="display: block;" class="js-only"></p>
<script>
@@ -40,8 +40,8 @@ $(document).ready(function() {
$.ajaxSetup({
"error":function(jqXHR,textStatus,response) {
var errorJson = jQuery.parseJSON(jqXHR.responseText);
- $.get("/templates/error-template.html", function(template) {
- $("#error").append(Mustache.render($(template).filter("#error-template").html(),errorJson));
+ $.get("/templates/json-error-template.html", function(template) {
+ $("#json-response-error").append(Mustache.render($(template).filter("#json-error-template").html(),errorJson));
});
}
});
@@ -52,7 +52,7 @@ $(document).ready(function() {
var inputStats = $("#component-input-stats");
var outputStats = $("#component-output-stats");
var executorStats = $("#component-executor-stats");
- var errors = $("#component-errors");
+ var componentErrors = $("#component-errors");
$.get("/templates/component-page-template.html", function(template) {
componentSummary.append(Mustache.render($(template).filter("#component-summary-template").html(),response));
if(response["componentType"] == "spout") {
@@ -76,9 +76,9 @@ $(document).ready(function() {
$("#bolt-executor-table").tablesorter({ sortList: [[0,0]], headers: {}});
}
}
- errors.append(Mustache.render($(template).filter("#errors-template").html(),response));
- if(response["errors"].length > 0) {
- $("#errors-table").tablesorter({ sortList: [[0,0]], headers: {1: { sorter: "stormtimestr"}}});
+ componentErrors.append(Mustache.render($(template).filter("#component-errors-template").html(),response));
+ if(response["componentErrors"].length > 0) {
+ $("#component-errors-table").tablesorter({ sortList: [[0,0]], headers: {1: { sorter: "stormtimestr"}}});
}
});
});
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/71817e7e/storm-core/src/ui/public/index.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/index.html b/storm-core/src/ui/public/index.html
index 102b3c6..77af159 100644
--- a/storm-core/src/ui/public/index.html
+++ b/storm-core/src/ui/public/index.html
@@ -22,15 +22,15 @@
</div>
<h2>Nimbus Configuration</h2>
<div id="nimbus-configuration"></div>
-<div id="error"></div>
+<div id="json-response-error"></div>
</body>
<script>
$(document).ready(function() {
$.ajaxSetup({
"error":function(jqXHR,textStatus,response) {
var errorJson = jQuery.parseJSON(jqXHR.responseText);
- $.get("/templates/error-template.html", function(template) {
- $("#error").append(Mustache.render($(template).filter("#error-template").html(),errorJson));
+ $.get("/templates/json-error-template.html", function(template) {
+ $("#json-response-error").append(Mustache.render($(template).filter("#json-error-template").html(),errorJson));
});
}
});
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/71817e7e/storm-core/src/ui/public/templates/component-page-template.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/templates/component-page-template.html b/storm-core/src/ui/public/templates/component-page-template.html
index 9275a82..f2a5266 100644
--- a/storm-core/src/ui/public/templates/component-page-template.html
+++ b/storm-core/src/ui/public/templates/component-page-template.html
@@ -137,16 +137,16 @@
</table>
</script>
-<script id="errors-template" type="text/html">
+<script id="component-errors-template" type="text/html">
<h2>Errors</h2>
-<table class="zebra-striped" id="errors-table"><thead><tr><th>Time</th><th>Error</th></tr></thead>
+<table class="zebra-striped" id="component-errors-table"><thead><tr><th>Time</th><th>Error</th></tr></thead>
<tbody>
-{{#errors}}
+{{#componentErrors}}
<tr>
<td>{{time}}</td>
<td>{{error}}</td>
</tr>
-{{/errors}}
+{{/componentErrors}}
</tbody>
</table>
</script>
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/71817e7e/storm-core/src/ui/public/templates/error-template.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/templates/error-template.html b/storm-core/src/ui/public/templates/error-template.html
deleted file mode 100644
index 09f3b76..0000000
--- a/storm-core/src/ui/public/templates/error-template.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<script id="error-template" type="text/html">
-<h2>{{error}}</h2>
-<pre>{{errorMessage}}</pre>
-</script>
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/71817e7e/storm-core/src/ui/public/templates/json-error-template.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/templates/json-error-template.html b/storm-core/src/ui/public/templates/json-error-template.html
new file mode 100644
index 0000000..d797726
--- /dev/null
+++ b/storm-core/src/ui/public/templates/json-error-template.html
@@ -0,0 +1,4 @@
+<script id="json-error-template" type="text/html">
+<h2>{{error}}</h2>
+<pre>{{errorMessage}}</pre>
+</script>
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/71817e7e/storm-core/src/ui/public/topology.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/topology.html b/storm-core/src/ui/public/topology.html
index 55e8ea0..69c09cb 100644
--- a/storm-core/src/ui/public/topology.html
+++ b/storm-core/src/ui/public/topology.html
@@ -29,7 +29,7 @@
<div id="topology-configuration">
</div>
<p id="toggle-switch" style="display: block;" class="js-only"></p>
-<div id="error">
+<div id="json-response-error">
</div>
</body>
<script>
@@ -43,8 +43,8 @@ $(document).ready(function() {
$.ajaxSetup({
"error":function(jqXHR,textStatus,response) {
var errorJson = jQuery.parseJSON(jqXHR.responseText);
- $.get("/templates/error-template.html", function(template) {
- $("#error").append(Mustache.render($(template).filter("#error-template").html(),errorJson));
+ $.get("/templates/json-error-template.html", function(template) {
+ $("#json-response-error").append(Mustache.render($(template).filter("#json-error-template").html(),errorJson));
});
}
});
@@ -73,7 +73,6 @@ $(document).ready(function() {
}
config.append(Mustache.render($(template).filter("#topology-configuration-template").html(),formattedConfig));
$("#topology-configuration-table").tablesorter({ sortList: [[0,0]], headers: {}});
-
});
});
});
[07/13] git commit: STORM-205. Add REST API to Storm UI. added
complete-latencies to the topology-stats changed /api to /api/v1
Posted by bo...@apache.org.
STORM-205. Add REST API to Storm UI. added complete-latencies to the
topology-stats
changed /api to /api/v1
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/900490b9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/900490b9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/900490b9
Branch: refs/heads/master
Commit: 900490b9caf8993ad0beee79fd4139b3bdee6359
Parents: 688444a
Author: Sriharsha Chintalapani <ma...@harsha.io>
Authored: Thu May 29 16:33:17 2014 -0700
Committer: Sriharsha Chintalapani <ma...@harsha.io>
Committed: Thu May 29 16:33:17 2014 -0700
----------------------------------------------------------------------
storm-core/src/clj/backtype/storm/ui/core.clj | 32 +++++++++++-----------
storm-core/src/ui/public/component.html | 2 +-
storm-core/src/ui/public/index.html | 8 +++---
storm-core/src/ui/public/js/script.js | 2 +-
storm-core/src/ui/public/topology.html | 2 +-
5 files changed, 23 insertions(+), 23 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/900490b9/storm-core/src/clj/backtype/storm/ui/core.clj
----------------------------------------------------------------------
diff --git a/storm-core/src/clj/backtype/storm/ui/core.clj b/storm-core/src/clj/backtype/storm/ui/core.clj
index d77ccb6..8bc1f9d 100644
--- a/storm-core/src/clj/backtype/storm/ui/core.clj
+++ b/storm-core/src/clj/backtype/storm/ui/core.clj
@@ -284,8 +284,8 @@
(merge-with
(fn [s1 s2]
(merge-with + s1 s2))
- (select-keys agg-bolt-stats [:emitted :transferred :acked :failed :complete-latencies])
- (select-keys agg-spout-stats [:emitted :transferred :acked :failed :complete-latencies])
+ (select-keys agg-bolt-stats [:emitted :transferred :acked :failed])
+ (select-keys agg-spout-stats [:emitted :transferred :acked :failed])
)))
(defn stats-times [stats-map]
@@ -643,39 +643,39 @@
})
(defroutes main-routes
- (GET "/api/cluster/configuration" []
+ (GET "/api/v1/cluster/configuration" []
(cluster-configuration))
- (GET "/api/cluster/summary" []
+ (GET "/api/v1/cluster/summary" []
(json-response (cluster-summary)))
- (GET "/api/supervisor/summary" []
+ (GET "/api/v1/supervisor/summary" []
(json-response (supervisor-summary)))
- (GET "/api/topology/summary" []
+ (GET "/api/v1/topology/summary" []
(json-response (all-topologies-summary)))
- (GET "/api/topology/:id" [id & m]
+ (GET "/api/v1/topology/:id" [id & m]
(let [id (url-decode id)]
(json-response (topology-page id (:window m) (check-include-sys? (:sys m))))))
- (GET "/api/topology/:id/component/:component" [id component & m]
+ (GET "/api/v1/topology/:id/component/:component" [id component & m]
(let [id (url-decode id)
component (url-decode component)]
(json-response (component-page id component (:window m) (check-include-sys? (:sys m))))))
- (POST "/api/topology/:id/activate" [id]
+ (POST "/api/v1/topology/:id/activate" [id]
(with-nimbus nimbus
(let [id (url-decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)]
(.activate nimbus name)
(log-message "Activating topology '" name "'")))
- (resp/redirect (str "/api/topology/" id)))
+ (resp/redirect (str "/api/v1/topology/" id)))
- (POST "/api/topology/:id/deactivate" [id]
+ (POST "/api/v1/topology/:id/deactivate" [id]
(with-nimbus nimbus
(let [id (url-decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
name (.get_name tplg)]
(.deactivate nimbus name)
(log-message "Deactivating topology '" name "'")))
- (resp/redirect (str "/api/topology/" id)))
- (POST "/api/topology/:id/rebalance/:wait-time" [id wait-time]
+ (resp/redirect (str "/api/v1/topology/" id)))
+ (POST "/api/v1/topology/:id/rebalance/:wait-time" [id wait-time]
(with-nimbus nimbus
(let [id (url-decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
@@ -684,8 +684,8 @@
(.set_wait_secs options (Integer/parseInt wait-time))
(.rebalance nimbus name options)
(log-message "Rebalancing topology '" name "' with wait time: " wait-time " secs")))
- (resp/redirect (str "/api/topology/" id)))
- (POST "/api/topology/:id/kill/:wait-time" [id wait-time]
+ (resp/redirect (str "/api/v1/topology/" id)))
+ (POST "/api/v1/topology/:id/kill/:wait-time" [id wait-time]
(with-nimbus nimbus
(let [id (url-decode id)
tplg (.getTopologyInfo ^Nimbus$Client nimbus id)
@@ -694,7 +694,7 @@
(.set_wait_secs options (Integer/parseInt wait-time))
(.killTopologyWithOpts nimbus name options)
(log-message "Killing topology '" name "' with wait time: " wait-time " secs")))
- (resp/redirect (str "/api/topology/" id)))
+ (resp/redirect (str "/api/v1/topology/" id)))
(GET "/" [:as {cookies :cookies}]
(resp/redirect "/index.html"))
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/900490b9/storm-core/src/ui/public/component.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/component.html b/storm-core/src/ui/public/component.html
index 1286e45..432b33d 100644
--- a/storm-core/src/ui/public/component.html
+++ b/storm-core/src/ui/public/component.html
@@ -34,7 +34,7 @@ $(document).ready(function() {
var topologyId = $.url().param("topology_id");
var window = $.url().param("window");
var sys = $.cookies.get("sys") || "false";
- var url = "/api/topology/"+topologyId+"/component/"+componentId+"?sys="+sys;
+ var url = "/api/v1/topology/"+topologyId+"/component/"+componentId+"?sys="+sys;
if(window) url += "&window="+window;
renderToggleSys($("#toggle-switch"));
$.ajaxSetup({
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/900490b9/storm-core/src/ui/public/index.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/index.html b/storm-core/src/ui/public/index.html
index dc20645..102b3c6 100644
--- a/storm-core/src/ui/public/index.html
+++ b/storm-core/src/ui/public/index.html
@@ -40,12 +40,12 @@ $(document).ready(function() {
var supervisorSummary = $("#supervisor-summary");
var config = $("#nimbus-configuration");
- $.getJSON("/api/cluster/summary",function(response,status,jqXHR) {
+ $.getJSON("/api/v1/cluster/summary",function(response,status,jqXHR) {
$.get("/templates/index-page-template.html", function(template) {
clusterSummary.append(Mustache.render($(template).filter("#cluster-summary-template").html(),response));
});
});
- $.getJSON("/api/topology/summary",function(response,status,jqXHR) {
+ $.getJSON("/api/v1/topology/summary",function(response,status,jqXHR) {
$.get("/templates/index-page-template.html", function(template) {
topologySummary.append(Mustache.render($(template).filter("#topology-summary-template").html(),response));
if(response["topologies"].length > 0) {
@@ -53,7 +53,7 @@ $(document).ready(function() {
}
});
});
- $.getJSON("/api/supervisor/summary",function(response,status,jqXHR) {
+ $.getJSON("/api/v1/supervisor/summary",function(response,status,jqXHR) {
$.get("/templates/index-page-template.html", function(template) {
supervisorSummary.append(Mustache.render($(template).filter("#supervisor-summary-template").html(),response));
if(response["supervisors"].length > 0) {
@@ -61,7 +61,7 @@ $(document).ready(function() {
}
});
});
- $.getJSON("/api/cluster/configuration",function(response,status,jqXHR) {
+ $.getJSON("/api/v1/cluster/configuration",function(response,status,jqXHR) {
var formattedResponse = formatConfigData(response);
$.get("/templates/index-page-template.html", function(template) {
config.append(Mustache.render($(template).filter("#configuration-template").html(),formattedResponse));
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/900490b9/storm-core/src/ui/public/js/script.js
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/js/script.js b/storm-core/src/ui/public/js/script.js
index ab4a825..8f7608e 100644
--- a/storm-core/src/ui/public/js/script.js
+++ b/storm-core/src/ui/public/js/script.js
@@ -71,7 +71,7 @@ function ensureInt(n) {
function confirmAction(id, name, action, wait, defaultWait) {
var opts = {
type:'POST',
- url:'/api/topology/' + id + '/' + action
+ url:'/api/v1/topology/' + id + '/' + action
};
if (wait) {
var waitSecs = prompt('Do you really want to ' + action + ' topology "' + name + '"? ' +
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/900490b9/storm-core/src/ui/public/topology.html
----------------------------------------------------------------------
diff --git a/storm-core/src/ui/public/topology.html b/storm-core/src/ui/public/topology.html
index c80bbe5..55e8ea0 100644
--- a/storm-core/src/ui/public/topology.html
+++ b/storm-core/src/ui/public/topology.html
@@ -37,7 +37,7 @@ $(document).ready(function() {
var topologyId = $.url().param("id");
var window = $.url().param("window");
var sys = $.cookies.get("sys") || "false";
- var url = "/api/topology/"+topologyId+"?sys="+sys;
+ var url = "/api/v1/topology/"+topologyId+"?sys="+sys;
if(window) url += "&window="+window;
renderToggleSys($("#toggle-switch"));
$.ajaxSetup({
[13/13] git commit: Added STORM-205 to changelog.
Posted by bo...@apache.org.
Added STORM-205 to changelog.
Project: http://git-wip-us.apache.org/repos/asf/incubator-storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-storm/commit/6dae731c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-storm/tree/6dae731c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-storm/diff/6dae731c
Branch: refs/heads/master
Commit: 6dae731c89b3756eea3257cee949a493d7590f16
Parents: baee2f4
Author: Robert (Bobby) Evans <bo...@apache.org>
Authored: Tue Jun 3 19:28:50 2014 -0500
Committer: Robert (Bobby) Evans <bo...@apache.org>
Committed: Tue Jun 3 19:28:50 2014 -0500
----------------------------------------------------------------------
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-storm/blob/6dae731c/CHANGELOG.md
----------------------------------------------------------------------
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 134d009..2117367 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
## 0.9.2-incubating (unreleased)
+ * STORM-205: Add REST API To Storm UI
* STORM-326: tasks send duplicate metrics
* STORM-331: Update the Kafka dependency of storm-kafka to 0.8.1.1
* STORM-308: Add support for config_value to {supervisor,nimbus,ui,drpc,logviewer} childopts