From commits-return-6744-archive-asf-public=cust-asf.ponee.io@zookeeper.apache.org Mon Aug 6 14:13:33 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 2F3181807C4 for ; Mon, 6 Aug 2018 14:13:30 +0200 (CEST) Received: (qmail 45775 invoked by uid 500); 6 Aug 2018 12:13:28 -0000 Mailing-List: contact commits-help@zookeeper.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zookeeper.apache.org Delivered-To: mailing list commits@zookeeper.apache.org Received: (qmail 44369 invoked by uid 99); 6 Aug 2018 12:13:27 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 06 Aug 2018 12:13:27 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 07486E1187; Mon, 6 Aug 2018 12:13:27 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: andor@apache.org To: commits@zookeeper.apache.org Date: Mon, 06 Aug 2018 12:13:45 -0000 Message-Id: <16b49d2d28204a25996b2dafd5f0c36d@git.apache.org> In-Reply-To: <13bf07ba1f73429dae991fd13f50d7a5@git.apache.org> References: <13bf07ba1f73429dae991fd13f50d7a5@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [20/45] zookeeper git commit: ZOOKEEPER-3030: MAVEN MIGRATION - Step 1.3 - move contrib directories http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.pie.js ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.pie.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.pie.js new file mode 100644 index 0000000..8d20374 --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.pie.js @@ -0,0 +1,205 @@ +/* + * g.Raphael 0.4 - Charting library, based on Raphaël + * + * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com) + * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. + */ +Raphael.fn.g.piechart = function (cx, cy, r, values, opts) { + opts = opts || {}; + var paper = this, + sectors = [], + covers = this.set(), + chart = this.set(), + series = this.set(), + order = [], + len = values.length, + angle = 0, + total = 0, + others = 0, + cut = 9, + defcut = true; + chart.covers = covers; + if (len == 1) { + series.push(this.circle(cx, cy, r).attr({fill: this.g.colors[0], stroke: opt.stroke || "#fff", "stroke-width": opts.strokewidth == null ? 1 : opts.strokewidth})); + covers.push(this.circle(cx, cy, r).attr(this.g.shim)); + total = values[0]; + values[0] = {value: values[0], order: 0, valueOf: function () { return this.value; }}; + series[0].middle = {x: cx, y: cy}; + series[0].mangle = 180; + } else { + function sector(cx, cy, r, startAngle, endAngle, fill) { + var rad = Math.PI / 180, + x1 = cx + r * Math.cos(-startAngle * rad), + x2 = cx + r * Math.cos(-endAngle * rad), + xm = cx + r / 2 * Math.cos(-(startAngle + (endAngle - startAngle) / 2) * rad), + y1 = cy + r * Math.sin(-startAngle * rad), + y2 = cy + r * Math.sin(-endAngle * rad), + ym = cy + r / 2 * Math.sin(-(startAngle + (endAngle - startAngle) / 2) * rad), + res = ["M", cx, cy, "L", x1, y1, "A", r, r, 0, +(Math.abs(endAngle - startAngle) > 180), 1, x2, y2, "z"]; + res.middle = {x: xm, y: ym}; + return res; + } + for (var i = 0; i < len; i++) { + total += values[i]; + values[i] = {value: values[i], order: i, valueOf: function () { return this.value; }}; + } + values.sort(function (a, b) { + return b.value - a.value; + }); + for (var i = 0; i < len; i++) { + if (defcut && values[i] * 360 / total <= 1.5) { + cut = i; + defcut = false; + } + if (i > cut) { + defcut = false; + values[cut].value += values[i]; + values[cut].others = true; + others = values[cut].value; + } + } + len = Math.min(cut + 1, values.length); + others && values.splice(len) && (values[cut].others = true); + for (var i = 0; i < len; i++) { + var mangle = angle - 360 * values[i] / total / 2; + if (!i) { + angle = 90 - mangle; + mangle = angle - 360 * values[i] / total / 2; + } + if (opts.init) { + var ipath = sector(cx, cy, 1, angle, angle - 360 * values[i] / total).join(","); + } + var path = sector(cx, cy, r, angle, angle -= 360 * values[i] / total); + var p = this.path(opts.init ? ipath : path).attr({fill: opts.colors && opts.colors[i] || this.g.colors[i] || "#666", stroke: opts.stroke || "#fff", "stroke-width": (opts.strokewidth == null ? 1 : opts.strokewidth), "stroke-linejoin": "round"}); + p.value = values[i]; + p.middle = path.middle; + p.mangle = mangle; + sectors.push(p); + series.push(p); + opts.init && p.animate({path: path.join(",")}, (+opts.init - 1) || 1000, ">"); + } + for (var i = 0; i < len; i++) { + var p = paper.path(sectors[i].attr("path")).attr(this.g.shim); + opts.href && opts.href[i] && p.attr({href: opts.href[i]}); + p.attr = function () {}; + covers.push(p); + series.push(p); + } + } + + chart.hover = function (fin, fout) { + fout = fout || function () {}; + var that = this; + for (var i = 0; i < len; i++) { + (function (sector, cover, j) { + var o = { + sector: sector, + cover: cover, + cx: cx, + cy: cy, + mx: sector.middle.x, + my: sector.middle.y, + mangle: sector.mangle, + r: r, + value: values[j], + total: total, + label: that.labels && that.labels[j] + }; + cover.mouseover(function () { + fin.call(o); + }).mouseout(function () { + fout.call(o); + }); + })(series[i], covers[i], i); + } + return this; + }; + // x: where label could be put + // y: where label could be put + // value: value to show + // total: total number to count % + chart.each = function (f) { + var that = this; + for (var i = 0; i < len; i++) { + (function (sector, cover, j) { + var o = { + sector: sector, + cover: cover, + cx: cx, + cy: cy, + x: sector.middle.x, + y: sector.middle.y, + mangle: sector.mangle, + r: r, + value: values[j], + total: total, + label: that.labels && that.labels[j] + }; + f.call(o); + })(series[i], covers[i], i); + } + return this; + }; + chart.click = function (f) { + var that = this; + for (var i = 0; i < len; i++) { + (function (sector, cover, j) { + var o = { + sector: sector, + cover: cover, + cx: cx, + cy: cy, + mx: sector.middle.x, + my: sector.middle.y, + mangle: sector.mangle, + r: r, + value: values[j], + total: total, + label: that.labels && that.labels[j] + }; + cover.click(function () { f.call(o); }); + })(series[i], covers[i], i); + } + return this; + }; + chart.inject = function (element) { + element.insertBefore(covers[0]); + }; + var legend = function (labels, otherslabel, mark, dir) { + var x = cx + r + r / 5, + y = cy, + h = y + 10; + labels = labels || []; + dir = (dir && dir.toLowerCase && dir.toLowerCase()) || "east"; + mark = paper.g.markers[mark && mark.toLowerCase()] || "disc"; + chart.labels = paper.set(); + for (var i = 0; i < len; i++) { + var clr = series[i].attr("fill"), + j = values[i].order, + txt; + values[i].others && (labels[j] = otherslabel || "Others"); + labels[j] = paper.g.labelise(labels[j], values[i], total); + chart.labels.push(paper.set()); + chart.labels[i].push(paper.g[mark](x + 5, h, 5).attr({fill: clr, stroke: "none"})); + chart.labels[i].push(txt = paper.text(x + 20, h, labels[j] || values[j]).attr(paper.g.txtattr).attr({fill: opts.legendcolor || "#000", "text-anchor": "start"})); + covers[i].label = chart.labels[i]; + h += txt.getBBox().height * 1.2; + } + var bb = chart.labels.getBBox(), + tr = { + east: [0, -bb.height / 2], + west: [-bb.width - 2 * r - 20, -bb.height / 2], + north: [-r - bb.width / 2, -r - bb.height - 10], + south: [-r - bb.width / 2, r + 10] + }[dir]; + chart.labels.translate.apply(chart.labels, tr); + chart.push(chart.labels); + }; + if (opts.legend) { + legend(opts.legend, opts.legendothers, opts.legendmark, opts.legendpos); + } + chart.push(series, covers); + chart.series = series; + chart.covers = covers; + return chart; +}; http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.raphael.js ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.raphael.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.raphael.js new file mode 100644 index 0000000..8e94c36 --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/g.raphael.js @@ -0,0 +1,481 @@ +/* + * g.Raphael 0.4 - Charting library, based on Raphaël + * + * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com) + * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. + */ + + +(function () { + Raphael.fn.g = Raphael.fn.g || {}; + Raphael.fn.g.markers = { + disc: "disc", + o: "disc", + flower: "flower", + f: "flower", + diamond: "diamond", + d: "diamond", + square: "square", + s: "square", + triangle: "triangle", + t: "triangle", + star: "star", + "*": "star", + cross: "cross", + x: "cross", + plus: "plus", + "+": "plus", + arrow: "arrow", + "->": "arrow" + }; + Raphael.fn.g.shim = {stroke: "none", fill: "#000", "fill-opacity": 0}; + Raphael.fn.g.txtattr = {font: "12px Arial, sans-serif"}; + Raphael.fn.g.colors = []; + var hues = [.6, .2, .05, .1333, .75, 0]; + for (var i = 0; i < 10; i++) { + if (i < hues.length) { + Raphael.fn.g.colors.push("hsb(" + hues[i] + ", .75, .75)"); + } else { + Raphael.fn.g.colors.push("hsb(" + hues[i - hues.length] + ", 1, .5)"); + } + } + Raphael.fn.g.text = function (x, y, text) { + return this.text(x, y, text).attr(this.g.txtattr); + }; + Raphael.fn.g.labelise = function (label, val, total) { + if (label) { + return (label + "").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g, function (all, value, percent) { + if (value) { + return (+val).toFixed(value.replace(/^#+\.?/g, "").length); + } + if (percent) { + return (val * 100 / total).toFixed(percent.replace(/^%+\.?/g, "").length) + "%"; + } + }); + } else { + return (+val).toFixed(0); + } + }; + + Raphael.fn.g.finger = function (x, y, width, height, dir, ending, isPath) { + // dir 0 for horisontal and 1 for vertical + if ((dir && !height) || (!dir && !width)) { + return isPath ? "" : this.path(); + } + ending = {square: "square", sharp: "sharp", soft: "soft"}[ending] || "round"; + var path; + height = Math.round(height); + width = Math.round(width); + x = Math.round(x); + y = Math.round(y); + switch (ending) { + case "round": + if (!dir) { + var r = Math.floor(height / 2); + if (width < r) { + r = width; + path = ["M", x + .5, y + .5 - Math.floor(height / 2), "l", 0, 0, "a", r, Math.floor(height / 2), 0, 0, 1, 0, height, "l", 0, 0, "z"]; + } else { + path = ["M", x + .5, y + .5 - r, "l", width - r, 0, "a", r, r, 0, 1, 1, 0, height, "l", r - width, 0, "z"]; + } + } else { + var r = Math.floor(width / 2); + if (height < r) { + r = height; + path = ["M", x - Math.floor(width / 2), y, "l", 0, 0, "a", Math.floor(width / 2), r, 0, 0, 1, width, 0, "l", 0, 0, "z"]; + } else { + path = ["M", x - r, y, "l", 0, r - height, "a", r, r, 0, 1, 1, width, 0, "l", 0, height - r, "z"]; + } + } + break; + case "sharp": + if (!dir) { + var half = Math.floor(height / 2); + path = ["M", x, y + half, "l", 0, -height, Math.max(width - half, 0), 0, Math.min(half, width), half, -Math.min(half, width), half + (half * 2 < height), "z"]; + } else { + var half = Math.floor(width / 2); + path = ["M", x + half, y, "l", -width, 0, 0, -Math.max(height - half, 0), half, -Math.min(half, height), half, Math.min(half, height), half, "z"]; + } + break; + case "square": + if (!dir) { + path = ["M", x, y + Math.floor(height / 2), "l", 0, -height, width, 0, 0, height, "z"]; + } else { + path = ["M", x + Math.floor(width / 2), y, "l", 1 - width, 0, 0, -height, width - 1, 0, "z"]; + } + break; + case "soft": + var r; + if (!dir) { + r = Math.min(width, Math.round(height / 5)); + path = ["M", x + .5, y + .5 - Math.floor(height / 2), "l", width - r, 0, "a", r, r, 0, 0, 1, r, r, "l", 0, height - r * 2, "a", r, r, 0, 0, 1, -r, r, "l", r - width, 0, "z"]; + } else { + r = Math.min(Math.round(width / 5), height); + path = ["M", x - Math.floor(width / 2), y, "l", 0, r - height, "a", r, r, 0, 0, 1, r, -r, "l", width - 2 * r, 0, "a", r, r, 0, 0, 1, r, r, "l", 0, height - r, "z"]; + } + } + if (isPath) { + return path.join(","); + } else { + return this.path(path); + } + }; + + // Symbols + Raphael.fn.g.disc = function (cx, cy, r) { + return this.circle(cx, cy, r); + }; + Raphael.fn.g.line = function (cx, cy, r) { + return this.rect(cx - r, cy - r / 5, 2 * r, 2 * r / 5); + }; + Raphael.fn.g.square = function (cx, cy, r) { + r = r * .7; + return this.rect(cx - r, cy - r, 2 * r, 2 * r); + }; + Raphael.fn.g.triangle = function (cx, cy, r) { + r *= 1.75; + return this.path("M".concat(cx, ",", cy, "m0-", r * .58, "l", r * .5, ",", r * .87, "-", r, ",0z")); + }; + Raphael.fn.g.diamond = function (cx, cy, r) { + return this.path(["M", cx, cy - r, "l", r, r, -r, r, -r, -r, r, -r, "z"]); + }; + Raphael.fn.g.flower = function (cx, cy, r, n) { + r = r * 1.25; + var rout = r, + rin = rout * .5; + n = +n < 3 || !n ? 5 : n; + var points = ["M", cx, cy + rin, "Q"], + R; + for (var i = 1; i < n * 2 + 1; i++) { + R = i % 2 ? rout : rin; + points = points.concat([+(cx + R * Math.sin(i * Math.PI / n)).toFixed(3), +(cy + R * Math.cos(i * Math.PI / n)).toFixed(3)]); + } + points.push("z"); + return this.path(points.join(",")); + }; + Raphael.fn.g.star = function (cx, cy, r, r2) { + r2 = r2 || r * .5; + var points = ["M", cx, cy + r2, "L"], + R; + for (var i = 1; i < 10; i++) { + R = i % 2 ? r : r2; + points = points.concat([(cx + R * Math.sin(i * Math.PI * .2)).toFixed(3), (cy + R * Math.cos(i * Math.PI * .2)).toFixed(3)]); + } + points.push("z"); + return this.path(points.join(",")); + }; + Raphael.fn.g.cross = function (cx, cy, r) { + r = r / 2.5; + return this.path("M".concat(cx - r, ",", cy, "l", [-r, -r, r, -r, r, r, r, -r, r, r, -r, r, r, r, -r, r, -r, -r, -r, r, -r, -r, "z"])); + }; + Raphael.fn.g.plus = function (cx, cy, r) { + r = r / 2; + return this.path("M".concat(cx - r / 2, ",", cy - r / 2, "l", [0, -r, r, 0, 0, r, r, 0, 0, r, -r, 0, 0, r, -r, 0, 0, -r, -r, 0, 0, -r, "z"])); + }; + Raphael.fn.g.arrow = function (cx, cy, r) { + return this.path("M".concat(cx - r * .7, ",", cy - r * .4, "l", [r * .6, 0, 0, -r * .4, r, r * .8, -r, r * .8, 0, -r * .4, -r * .6, 0], "z")); + }; + + // Tooltips + Raphael.fn.g.tag = function (x, y, text, angle, r) { + angle = angle || 0; + r = r == null ? 5 : r; + text = text == null ? "$9.99" : text; + var R = .5522 * r, + res = this.set(), + d = 3; + res.push(this.path().attr({fill: "#000", stroke: "none"})); + res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"})); + res.update = function () { + this.rotate(0, x, y); + var bb = this[1].getBBox(); + if (bb.height >= r * 2) { + this[0].attr({path: ["M", x, y + r, "a", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2, "m", 0, -r * 2 -d, "a", r + d, r + d, 0, 1, 0, 0, (r + d) * 2, "L", x + r + d, y + bb.height / 2 + d, "l", bb.width + 2 * d, 0, 0, -bb.height - 2 * d, -bb.width - 2 * d, 0, "L", x, y - r - d].join(",")}); + } else { + var dx = Math.sqrt(Math.pow(r + d, 2) - Math.pow(bb.height / 2 + d, 2)); + // ["c", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r] + // "a", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2, + this[0].attr({path: ["M", x, y + r, "c", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r, "M", x + dx, y - bb.height / 2 - d, "a", r + d, r + d, 0, 1, 0, 0, bb.height + 2 * d, "l", r + d - dx + bb.width + 2 * d, 0, 0, -bb.height - 2 * d, "L", x + dx, y - bb.height / 2 - d].join(",")}); + } + this[1].attr({x: x + r + d + bb.width / 2, y: y}); + angle = (360 - angle) % 360; + this.rotate(angle, x, y); + angle > 90 && angle < 270 && this[1].attr({x: x - r - d - bb.width / 2, y: y, rotation: [180 + angle, x, y]}); + return this; + }; + res.update(); + return res; + }; + Raphael.fn.g.popupit = function (x, y, set, dir, size) { + dir = dir == null ? 2 : dir; + size = size || 5; + x = Math.round(x) + .5; + y = Math.round(y) + .5; + var bb = set.getBBox(), + w = Math.round(bb.width / 2), + h = Math.round(bb.height / 2), + dx = [0, w + size * 2, 0, -w - size * 2], + dy = [-h * 2 - size * 3, -h - size, 0, -h - size], + p = ["M", x - dx[dir], y - dy[dir], "l", -size, (dir == 2) * -size, -Math.max(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size, + "l", 0, -Math.max(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -Math.max(h - size, 0), "a", size, size, 0, 0, 1, size, -size, + "l", Math.max(w - size, 0), 0, size, !dir * -size, size, !dir * size, Math.max(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size, + "l", 0, Math.max(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, Math.max(h - size, 0), "a", size, size, 0, 0, 1, -size, size, + "l", -Math.max(w - size, 0), 0, "z"].join(","), + xy = [{x: x, y: y + size * 2 + h}, {x: x - size * 2 - w, y: y}, {x: x, y: y - size * 2 - h}, {x: x + size * 2 + w, y: y}][dir]; + set.translate(xy.x - w - bb.x, xy.y - h - bb.y); + return this.path(p).attr({fill: "#000", stroke: "none"}).insertBefore(set.node ? set : set[0]); + }; + Raphael.fn.g.popup = function (x, y, text, dir, size) { + dir = dir == null ? 2 : dir; + size = size || 5; + text = text || "$9.99"; + var res = this.set(), + d = 3; + res.push(this.path().attr({fill: "#000", stroke: "none"})); + res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"})); + res.update = function (X, Y, withAnimation) { + X = X || x; + Y = Y || y; + var bb = this[1].getBBox(), + w = bb.width / 2, + h = bb.height / 2, + dx = [0, w + size * 2, 0, -w - size * 2], + dy = [-h * 2 - size * 3, -h - size, 0, -h - size], + p = ["M", X - dx[dir], Y - dy[dir], "l", -size, (dir == 2) * -size, -Math.max(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size, + "l", 0, -Math.max(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -Math.max(h - size, 0), "a", size, size, 0, 0, 1, size, -size, + "l", Math.max(w - size, 0), 0, size, !dir * -size, size, !dir * size, Math.max(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size, + "l", 0, Math.max(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, Math.max(h - size, 0), "a", size, size, 0, 0, 1, -size, size, + "l", -Math.max(w - size, 0), 0, "z"].join(","), + xy = [{x: X, y: Y + size * 2 + h}, {x: X - size * 2 - w, y: Y}, {x: X, y: Y - size * 2 - h}, {x: X + size * 2 + w, y: Y}][dir]; + if (withAnimation) { + this[0].animate({path: p}, 500, ">"); + this[1].animate(xy, 500, ">"); + } else { + this[0].attr({path: p}); + this[1].attr(xy); + } + return this; + }; + return res.update(x, y); + }; + Raphael.fn.g.flag = function (x, y, text, angle) { + angle = angle || 0; + text = text || "$9.99"; + var res = this.set(), + d = 3; + res.push(this.path().attr({fill: "#000", stroke: "none"})); + res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"})); + res.update = function (x, y) { + this.rotate(0, x, y); + var bb = this[1].getBBox(), + h = bb.height / 2; + this[0].attr({path: ["M", x, y, "l", h + d, -h - d, bb.width + 2 * d, 0, 0, bb.height + 2 * d, -bb.width - 2 * d, 0, "z"].join(",")}); + this[1].attr({x: x + h + d + bb.width / 2, y: y}); + angle = 360 - angle; + this.rotate(angle, x, y); + angle > 90 && angle < 270 && this[1].attr({x: x - r - d - bb.width / 2, y: y, rotation: [180 + angle, x, y]}); + return this; + }; + return res.update(x, y); + }; + Raphael.fn.g.label = function (x, y, text) { + var res = this.set(); + res.push(this.rect(x, y, 10, 10).attr({stroke: "none", fill: "#000"})); + res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"})); + res.update = function () { + var bb = this[1].getBBox(), + r = Math.min(bb.width + 10, bb.height + 10) / 2; + this[0].attr({x: bb.x - r / 2, y: bb.y - r / 2, width: bb.width + r, height: bb.height + r, r: r}); + }; + res.update(); + return res; + }; + Raphael.fn.g.labelit = function (set) { + var bb = set.getBBox(), + r = Math.min(20, bb.width + 10, bb.height + 10) / 2; + return this.rect(bb.x - r / 2, bb.y - r / 2, bb.width + r, bb.height + r, r).attr({stroke: "none", fill: "#000"}).insertBefore(set[0]); + }; + Raphael.fn.g.drop = function (x, y, text, size, angle) { + size = size || 30; + angle = angle || 0; + var res = this.set(); + res.push(this.path(["M", x, y, "l", size, 0, "A", size * .4, size * .4, 0, 1, 0, x + size * .7, y - size * .7, "z"]).attr({fill: "#000", stroke: "none", rotation: [22.5 - angle, x, y]})); + angle = (angle + 90) * Math.PI / 180; + res.push(this.text(x + size * Math.sin(angle), y + size * Math.cos(angle), text).attr(this.g.txtattr).attr({"font-size": size * 12 / 30, fill: "#fff"})); + res.drop = res[0]; + res.text = res[1]; + return res; + }; + Raphael.fn.g.blob = function (x, y, text, angle, size) { + angle = (+angle + 1 ? angle : 45) + 90; + size = size || 12; + var rad = Math.PI / 180, + fontSize = size * 12 / 12; + var res = this.set(); + res.push(this.path().attr({fill: "#000", stroke: "none"})); + res.push(this.text(x + size * Math.sin((angle) * rad), y + size * Math.cos((angle) * rad) - fontSize / 2, text).attr(this.g.txtattr).attr({"font-size": fontSize, fill: "#fff"})); + res.update = function (X, Y, withAnimation) { + X = X || x; + Y = Y || y; + var bb = this[1].getBBox(), + w = Math.max(bb.width + fontSize, size * 25 / 12), + h = Math.max(bb.height + fontSize, size * 25 / 12), + x2 = X + size * Math.sin((angle - 22.5) * rad), + y2 = Y + size * Math.cos((angle - 22.5) * rad), + x1 = X + size * Math.sin((angle + 22.5) * rad), + y1 = Y + size * Math.cos((angle + 22.5) * rad), + dx = (x1 - x2) / 2, + dy = (y1 - y2) / 2, + rx = w / 2, + ry = h / 2, + k = -Math.sqrt(Math.abs(rx * rx * ry * ry - rx * rx * dy * dy - ry * ry * dx * dx) / (rx * rx * dy * dy + ry * ry * dx * dx)), + cx = k * rx * dy / ry + (x1 + x2) / 2, + cy = k * -ry * dx / rx + (y1 + y2) / 2; + if (withAnimation) { + this.animate({x: cx, y: cy, path: ["M", x, y, "L", x1, y1, "A", rx, ry, 0, 1, 1, x2, y2, "z"].join(",")}, 500, ">"); + } else { + this.attr({x: cx, y: cy, path: ["M", x, y, "L", x1, y1, "A", rx, ry, 0, 1, 1, x2, y2, "z"].join(",")}); + } + return this; + }; + res.update(x, y); + return res; + }; + + Raphael.fn.g.colorValue = function (value, total, s, b) { + return "hsb(" + [Math.min((1 - value / total) * .4, 1), s || .75, b || .75] + ")"; + }; + + Raphael.fn.g.snapEnds = function (from, to, steps) { + var f = from, + t = to; + if (f == t) { + return {from: f, to: t, power: 0}; + } + function round(a) { + return Math.abs(a - .5) < .25 ? Math.floor(a) + .5 : Math.round(a); + } + var d = (t - f) / steps, + r = Math.floor(d), + R = r, + i = 0; + if (r) { + while (R) { + i--; + R = Math.floor(d * Math.pow(10, i)) / Math.pow(10, i); + } + i ++; + } else { + while (!r) { + i = i || 1; + r = Math.floor(d * Math.pow(10, i)) / Math.pow(10, i); + i++; + } + i && i--; + } + var t = round(to * Math.pow(10, i)) / Math.pow(10, i); + if (t < to) { + t = round((to + .5) * Math.pow(10, i)) / Math.pow(10, i); + } + var f = round((from - (i > 0 ? 0 : .5)) * Math.pow(10, i)) / Math.pow(10, i); + return {from: f, to: t, power: i}; + }; + Raphael.fn.g.axis = function (x, y, length, from, to, steps, orientation, labels, type, dashsize) { + dashsize = dashsize == null ? 3 : dashsize; + type = type || "t"; + steps = steps || 10; + var path = type == "|" || type == " " ? ["M", x + .5, y, "l", 0, .001] : orientation == 1 || orientation == 3 ? ["M", x + .5, y, "l", 0, -length] : ["M", x, y + .5, "l", length, 0], + ends = this.g.snapEnds(from, to, steps), + f = ends.from, + t = ends.to, + i = ends.power, + j = 0, + text = this.set(); + d = (t - f) / steps; + var label = f, + rnd = i > 0 ? i : 0; + dx = length / steps; + if (+orientation == 1 || +orientation == 3) { + var Y = y, + addon = (orientation - 1 ? 1 : -1) * (dashsize + 3 + !!(orientation - 1)); + while (Y >= y - length) { + type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), Y + .5, "l", dashsize * 2 + 1, 0])); + text.push(this.text(x + addon, Y, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr).attr({"text-anchor": orientation - 1 ? "start" : "end"})); + label += d; + Y -= dx; + } + if (Math.round(Y + dx - (y - length))) { + type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), y - length + .5, "l", dashsize * 2 + 1, 0])); + text.push(this.text(x + addon, y - length, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr).attr({"text-anchor": orientation - 1 ? "start" : "end"})); + } + } else { + var X = x, + label = f, + rnd = i > 0 ? i : 0, + addon = (orientation ? -1 : 1) * (dashsize + 9 + !orientation), + dx = length / steps, + txt = 0, + prev = 0; + while (X <= x + length) { + + text.push(txt = this.text(X, y + addon, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr)); + var bb = txt.getBBox(); + var ds = dashsize; + if (prev >= bb.x - 5) { + text.pop(text.length - 1).remove(); + ds = 1; + } else { + prev = bb.x + bb.width; + } + + type != "-" && type != " " && (path = path.concat(["M", X + .5, y - (type == "+" ? ds : !!orientation * ds * 2), "l", 0, ds * 2 + 1])); + + label += d; + X += dx; + } + if (Math.round(X - dx - x - length)) { + type != "-" && type != " " && (path = path.concat(["M", x + length + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1])); + text.push(this.text(x + length, y + addon, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr)); + } + } + var res = this.path(path); + res.text = text; + res.all = this.set([res, text]); + res.remove = function () { + this.text.remove(); + this.constructor.prototype.remove.call(this); + }; + return res; + }; + + Raphael.el.lighter = function (times) { + times = times || 2; + var fs = [this.attrs.fill, this.attrs.stroke]; + this.fs = this.fs || [fs[0], fs[1]]; + fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex); + fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex); + fs[0].b = Math.min(fs[0].b * times, 1); + fs[0].s = fs[0].s / times; + fs[1].b = Math.min(fs[1].b * times, 1); + fs[1].s = fs[1].s / times; + this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"}); + }; + Raphael.el.darker = function (times) { + times = times || 2; + var fs = [this.attrs.fill, this.attrs.stroke]; + this.fs = this.fs || [fs[0], fs[1]]; + fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex); + fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex); + fs[0].s = Math.min(fs[0].s * times, 1); + fs[0].b = fs[0].b / times; + fs[1].s = Math.min(fs[1].s * times, 1); + fs[1].b = fs[1].b / times; + this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"}); + }; + Raphael.el.original = function () { + if (this.fs) { + this.attr({fill: this.fs[0], stroke: this.fs[1]}); + delete this.fs; + } + }; +})(); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/load-big.gif ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/load-big.gif b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/load-big.gif new file mode 100644 index 0000000..ddb7ff1 Binary files /dev/null and b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/load-big.gif differ http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/load.gif ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/load.gif b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/load.gif new file mode 100644 index 0000000..d0bce15 Binary files /dev/null and b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/load.gif differ http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.css ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.css b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.css new file mode 100644 index 0000000..a84d90e --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.css @@ -0,0 +1,54 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +body { font-family: sans-serif; } + +div.fileSelector { border: solid 3px black; position: absolute; background: white; + -moz-border-radius: 10px; border-radius: 10px; + padding: 5px; font-family: sans-serif; + right: 10px; top: 10px; + } +div.fileSelector a { cursor: pointer; } +.fileSelector li.selectedFile { background: lightgreen; } + +div.selector { border: solid 3px black; position: absolute; background: white; + -moz-border-radius: 10px; border-radius: 10px; + padding: 5px; + right: 10px; top: 10px; background: #aaaaaa; opacity: 0.7; + } +div.selector a { cursor: pointer; } +.fileSelector li.selectedFile { background: lightgreen; } + +#fileLoader { -moz-border-radius: 10px; border-radius: 10px; background: #aaaaaa; opacity: 0.7; position: absolute; left: 20px; top: 20px; } +#loadingScreen { position: absolute; top: 100px; margin-left: 40%; margin-right: 40%; width: 500px; background: #aaaaaa; opacity: 0.7; -moz-border-radius: 10px; border-radius: 10px; text-align: center } +#filterinput { width: 500px; height: 100px; } +/* main interface */ +#actions { float: right; } +#views { float: left; } + +.closebutton { position: absolute; right: 5px; float: right; display: block; cursor: pointer; } + +.actionbutton { color: blue; text-decoration: none; padding: 3px; cursor: pointer; } +span:hover.actionbutton { background: lightblue; } + +#status { text-align: center; } + +#canvas { width: 100%; height: 1000px; } + +#logtable { width: 100%; } +.popUp { border: 3px solid black; -moz-border-radius: 10px; border-radius: 10px; position: absolute; background: white; padding: 10px; min-width: 300px; } + +.errorpage { position: absolute; top: 100px; margin-left: 40%; margin-right: 40%; width: 500px; background: #aaaaaa; opacity: 0.7; -moz-border-radius: 10px; border-radius: 10px; padding: 10px; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.js ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.js new file mode 100644 index 0000000..87bb7d8 --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.js @@ -0,0 +1,262 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +LogGraph = function(canvas, status) { + this.canvas = document.getElementById(canvas); + this.status = document.getElementById(status); + this.starttime = 0; + this.endtime = 0; + this.period = 0; + this.numEntries = 0; + this.currentRender = 0; + this.filter = ""; + + this.saveFilters = function () { + localStorage.starttime = this.starttime; + localStorage.endtime = this.endtime; + localStorage.period = this.period; + localStorage.filter = this.filter; + + }; + this.loadFilters = function () { + if (localStorage.starttime) { this.starttime = parseInt(localStorage.starttime); } + if (localStorage.endtime) { this.endtime = parseInt(localStorage.endtime); } + if (localStorage.period) { this.period = parseInt(localStorage.period); } + if (localStorage.filter) { this.filter = localStorage.filter; } + }; + this.loadFilters(); + var self = this; + + var updateStatus = function (starttime, period, filter, numEntries) { + self.starttime = starttime; + self.endtime = starttime + period; + self.period = period; + self.filter = filter; + self.saveFilters(); + + self.status.innerHTML = dateFormat(starttime, "HH:MM:ss,l") + " ⇒ " + dateFormat(self.endtime, "HH:MM:ss,l") + "    |    " + numEntries + " entries    |    " + (filter ? filter : "No filter"); + + if (self.currentRender) { + self.currentRender(); + } + }; + + YUI().use("io-base", function(Y) { + var uri = "/info"; + if (self.starttime) { + var uri = "/info?start=" + self.starttime + "&period=" + self.period + "&filter=" + self.filter; + } + + function complete(id, o, args) { + var data = eval("(" + o.responseText + ")"); // Response data. + var period = data.endTime - data.startTime; + updateStatus(data.startTime, period, self.filter, data.numEntries); + }; + + Y.on('io:complete', complete, Y, []); + var request = Y.io(uri); + }); + + this.addLogs = function() { + new LogGraph.fileSelector(function (files) { new LogGraph.fileLoader(files); }); + }; + + this.editFilters = function() { + new LogGraph.filterSelector(this.starttime, this.period, this.filter, updateStatus); + }; + + this.getCleanCanvas = function () { + this.canvas.innerHTML = ""; + return this.canvas; + }; + + this.showLoadingScreen = function () { + this.loadingScreen = document.createElement("div"); + this.loadingScreen.id = "loadingScreen"; + this.loadingScreen.innerHTML = "

Loading...

"; + document.body.appendChild(this.loadingScreen); + }; + + this.hideLoadingScreen = function () { + document.body.removeChild(this.loadingScreen); + this.loadingScreen.style.visibility = "hidden"; + }; + + + /*** + * TODO: refactor these to load the data first, before handing to a draw funciton. + * We shouldn't pass the async q into the drawing function + */ + this.showLogs = function() { + var self= this; + YUI().use('async-queue', function(Y) { + var q = new Y.AsyncQueue(self.showLoadingScreen, + // The second callback will pause the Queue and send an XHR for data + function () { + q.pause(); + var loggraph = new LogGraph.LogTable(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter); + self.currentRender = self.showLogs; + }, + self.hideLoadingScreen); + q.run(); + } + ); + }; + + this.serverGraph = function() { + var self= this; + YUI().use('async-queue', function(Y) { + var q = new Y.AsyncQueue(self.showLoadingScreen, + // The second callback will pause the Queue and send an XHR for data + function () { + q.pause(); + var servergraph = new LogGraph.ServerGraph(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter); + self.currentRender = self.showLogs; + }, + self.hideLoadingScreen); + q.run(); + } + ); + }; + + this.sessionGraph = function() { + var self= this; + YUI().use('async-queue', function(Y) { + var q = new Y.AsyncQueue(self.showLoadingScreen, + // The second callback will pause the Queue and send an XHR for data + function () { + q.pause(); + var sessiongraph = new LogGraph.SessionGraph(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter); + self.currentRender = self.sessionGraph; + }, + self.hideLoadingScreen); + q.run(); + } + ); + }; + + this.showStats = function() { + var self= this; + YUI().use('async-queue', function(Y) { + var q = new Y.AsyncQueue(self.showLoadingScreen, + // The second callback will pause the Queue and send an XHR for data + function () { + q.pause(); + var statgraph = new LogGraph.StatsGraph(q, self.getCleanCanvas(), self.starttime, self.endtime, self.filter); + self.currentRender = self.showStats; + }, + self.hideLoadingScreen); + q.run(); + } + ); + }; +}; + +LogGraph.error = function(description) { + var errorPage = document.createElement("div"); + errorPage.className = "errorpage"; + var p = document.createElement("p"); + p.innerHTML = description; + errorPage.appendChild(p); + + var span = document.createElement("span"); + p = document.createElement("p"); + span.className = "actionButton"; + span.innerHTML = "OK"; + span.onclick = function (evt) { + document.body.removeChild(errorPage); + delete errorPage; + } + p.appendChild(span); + errorPage.appendChild(p); + + document.body.appendChild(errorPage); +}; + +LogGraph.ticker =function(allow_dups) { + this.ticks = new Array(); + this.current_tick = 0; + this.allow_dups = allow_dups;; + + this.tick = function(time) { + if (time == this.ticks[this.ticks.length - 1] && this.allow_dups == true) + return this.current_tick; + + this.ticks.push(time); + return this.current_tick++; + }; + + this.current = function() { + return this.current_tick; + }; + + this.reset = function() { + while (this.ticks.length) { + this.ticks.pop(); + } + this.current_tick = 0; + }; +}; + + +LogGraph.timescale = function(starttime, endtime) { + this.starttime = starttime; + this.endtime = endtime; + this.millis = endtime - starttime; + + this.draw = function(paper) { + var scale = paper.set(); + scale.push(paper.path("M0 0 L" + paper.width + " 0")); + + for (var i = 0; i < paper.width; i += 100) { + scale.push(paper.path("M" + i + " 0 L" + i + " 5")); + // var time = dateFormat((this.starttime + (i*ms_per_pixel)), "h:MM:ss,l"); + // paper.text(i + 5, 10, time); + } + + scale.attr({"stroke-width": 2}); + }; +}; + +/* + Fetch data from an uri and process it, the process data func returns true if any of the data is useful +*/ +LogGraph.loadData = function (asyncq, uri, processdata) { + YUI().use("io-base", function(Y) { + function success(id, o, args) { + var data = eval("(" + o.responseText + ")"); // Response data. + if (data.error) { + LogGraph.error(data.error); + } else { + if (!processdata(data)) { + LogGraph.error("No data. Perhaps you should loosen your filter criteria."); + } + } + asyncq.run(); + }; + function failure(id, o, args) { + LogGraph.error("Error contacting server: (" + o.status + ") " + o.statusText); + asyncq.run(); + }; + + Y.on('io:success', success, Y, []); + Y.on('io:failure', failure, Y, []); + + var request = Y.io(uri); + }); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.log.js ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.log.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.log.js new file mode 100644 index 0000000..551ea4b --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.log.js @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +LogGraph.LogTable = function (asyncq, canvas, starttime, endtime, filter) { + this.starttime = starttime; + this.endtime = endtime; + this.filter = filter; + + var table = document.createElement("table"); + table.id = "logtable"; + canvas.appendChild(table); + + this.addLogLine = function(time, text) { + var tr = document.createElement("tr"); + table.appendChild(tr); + + var td = document.createElement("td"); + td.innerHTML = dateFormat(time, "h:MM:ss,l"); + tr.appendChild(td); + + td = document.createElement("td"); + td.innerHTML = text; + tr.appendChild(td); + } + + var self = this; + var processdata = function(data) { + var events = data["events"]; + var count = 0; + for (var i in events) { + var e = events[i]; + if (e.type == "text") { + self.addLogLine(e.time, e.text); + count++; + } + } + return count != 0; + }; + + var uri = "/data?start=" + self.starttime + "&end=" + self.endtime + "&filter=" + self.filter; + LogGraph.loadData(asyncq, uri, processdata); +}; http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.server.js ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.server.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.server.js new file mode 100644 index 0000000..0a74b5c --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.server.js @@ -0,0 +1,329 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +LogGraph.ServerGraph = function(asyncq, canvas, starttime, endtime, filter) { + this.starttime = starttime; + this.endtime = endtime; + this.millis = endtime - starttime; + this.nextserverid = 0; + this.serveroffset = 100; + this.filter = filter; + + this.pixels_per_tick = 20; + this.ticker = new LogGraph.ticker(); + + + var paper = Raphael(canvas, 1, 1); + + var self = this; + + this.timescale = new LogGraph.timescale(starttime, endtime); + this.objects = new Array(); + + this.add = function(obj) { + this.objects.push(obj); + } + + this.tick_to_x = function (timestamp) { + var x = timestamp * this.pixels_per_tick; + return x; + }; + + this._drawTime = function(paper, x, time) { + var p = paper.path("M" + x + " 0 L" + x + " " + paper.height); + var t = paper.text(x, 10, dateFormat(time, "h:MM:ss,l")); + + t.hide(); + p.mouseover(function(evt) { + t.show(); + p.attr({stroke: "red"}); + }); + p.mouseout(function(evt) { + t.hide(); + p.attr({stroke: "lightgray"}); + }); + + return p; + }; + + this.draw = function(paper) { + var grid = paper.set(); + for (var i = 0; i < paper.height; i += 20) { + grid.push(paper.path("M0 " + i + " L" + paper.width + " " + i)); + } + var lasttick = this.starttime; + var scale = 500; // 500 ms + + var y = 0; + + for (var t = 0, len = this.ticker.ticks.length; t < len; t++) { + var basex = t * this.pixels_per_tick; + var thistick = this.ticker.ticks[t]; + var nexttick = t + 1 == this.ticker.ticks.length ? this.endtime : this.ticker.ticks[t+1]; + if (nexttick == thistick) { + continue; + } + var time = thistick - lasttick; + var first = scale - (lasttick % scale); + + /* for (var i = 0; (first+scale*i) < time; i++) { + + var toffset = first+scale*i; + var x = basex + LogGraph._pixels_per_tick * toffset/time; + grid.push(this._drawTime(paper, x, lasttick + toffset, grid)); + + }*/ + + + //grid.push(paper.path("M" + i + " 0 L" + i + " " + paper.height)); + lasttick = thistick; + } + grid.attr({stroke: "lightgray"}); + this.timescale.draw(paper); + + for (o in this.objects) { + this.objects[o].draw(paper); + } + }; + + + var processdata = function(data) { + var servermap = {}; + var servers = data.servers; + var count = 0; + for (s in servers) { + var server = new LogGraph.ServerGraph.server(self, "Server " + servers[s]); + servermap[servers[s]] = server; + self.add(server); + count++; + } + + var messages = {}; + var events = data.events; + for (var i in events) { + var e = events[i]; + var t = e.time; + if (e.type == "stateChange") { + servermap[e.server].addState(e.state, self.ticker.tick(e.time)); + } + if (e.type == "postmessage") { + src = servermap[e.src]; + dst = servermap[e.dst]; + var key = "key:s" + e.src + ",d" + e.dst + ",z" + e.zxid; + + var m = new LogGraph.ServerGraph.message(self, src, self.ticker.tick(e.time), dst, e.zxid); + messages[key] = m; + } + if (e.type == "delivermessage") { + var key = "key:s" + e.src + ",d" + e.dst + ",z" + e.zxid; + + var m = messages[key]; + if (m) { + m.dsttime = self.ticker.tick(e.time); + m.name = "Propose"; + self.add(m); + delete messages[key]; + } + } + if (e.type == "exception") { + servermap[e.server].addException(self.ticker.tick(e.time), e.text, e.time); + } + count++; + } + + for (var i in messages) { + var m = messages[i]; + m.markIncomplete(); + self.add(m); + count++; + } + + if (count != 0) { + paper.setSize(self.tick_to_x(self.ticker.current()), 1000); + + var line = paper.path("M0 0 L0 1000"); + line.attr({"stroke": "red", "stroke-dasharray": "- "}); + var base = canvas.offsetLeft;// + ((canvas.offsetWidth - paper.width)/2); + canvas.onmousemove = function (evt) { + var x = evt.screenX - base; + + line.attr({"path": "M" + x + " 0 L"+ x +" 1000"}); + + }; + + self.draw(paper); + return true; + } else { + return false; + } + }; + + var uri = "/data?start=" + self.starttime + "&end=" + self.endtime + "&filter=" + filter; + + LogGraph.loadData(asyncq, uri, processdata); +}; + +LogGraph.ServerGraph.server = function (graph, name) { + this.graph = graph; + this.serverid = graph.nextserverid++; + this.name = name; + this.y = (this.serverid * 300 + graph.serveroffset); + this.states = new Array(); + this.exception = new Array(); + + this.addState = function(state, time) { + this.states.push([state, time]); + } + + this.addException = function(tick, exception, time) { + this.exception.push(new LogGraph.ServerGraph.exception(this.graph, tick, exception, time)); + } + + this.draw = function(paper) { + var st = paper.set(); + st.push(paper.path("M0 " + this.y + " L" + paper.width + " " + this.y)); + st.push(paper.text(20, this.y - 10, this.name)); + st.attr({stroke: "gray"}); + + var numstates = this.states.length; + + for (s = 0; s < numstates; s++) { + var style = {}; + switch (this.states[s][0]) { + case "INIT": style = {stroke: "yellow", "stroke-width":3}; break; + case "FOLLOWING": style = {stroke: "lightgreen", "stroke-width":7}; break; + case "LEADING": style = {stroke: "green", "stroke-width":10}; break; + case "LOOKING": style = {stroke: "orange", "stroke-width":5}; break; + } + var startx = this.graph.tick_to_x(this.states[s][1]); + var endx = s + 1 < numstates ? this.graph.tick_to_x(this.states[(s+1)][1]) : paper.width; + var p = paper.path("M" + startx + " " + this.y + " L" + endx + " " + this.y); + p.attr(style); + } + + for (e in this.exception) { + this.exception[e].draw(paper, this); + } + } +}; + +LogGraph.ServerGraph.message = function(graph, src, srctime, dst, zxid) { + this.graph = graph; + this.src = src; + this.srctime = srctime; + this.dst = dst; + this.dsttime = 0; //dsttime; + this.name = "Unknown"; + this.zxid = zxid; + this.moreinfo = "No extra information"; + this.incomplete = false; + + this.markIncomplete = function() { + this.incomplete = true; + this.dsttime = this.srctime; + } + + this.draw = function(paper) { + var srcx = this.graph.tick_to_x(this.srctime); + var dstx = this.graph.tick_to_x(this.dsttime); + + var arrow = paper.set(); + var p = paper.path("M" + srcx + " " + this.src.y + " L" + dstx + " " + this.dst.y); + arrow.push(p); + + var tx = (srcx + dstx)/2; + var ty = (this.src.y + this.dst.y)/2; + var t = paper.text(tx, ty, this.name); + + var gradiant = (this.dst.y - this.src.y)/(dstx - srcx); + var angle = Math.atan(gradiant) * 57.2958; + t.rotate(angle, true); + + var arrowl = paper.path("M" + dstx + " " + this.dst.y + " L" + (dstx - 10) +" " + this.dst.y); + arrowl.rotate(angle + 20, dstx, this.dst.y); + arrow.push(arrowl); + var arrowr = paper.path("M" + dstx + " " + this.dst.y + " L" + (dstx - 10) +" " + this.dst.y); + arrowr.rotate(angle - 20, dstx, this.dst.y); + arrow.push(arrowr); + + arrow.attr({"stroke-width": 2, stroke: "gray"}); + if (this.incomplete) { + arrow.attr({"stroke-dasharray": "- .", stroke: "pink", "stroke-width": 2}); + } + arrow.mouseover(function(evt) { + t.attr({"font-size": 20}); + arrow.attr({stroke: "red", "stroke-width": 3}); + }); + arrow.mouseout(function(evt) { + t.attr({"font-size": 10}); + + if (this.incomplete) { + arrow.attr({stroke: "pink", "stroke-width": 2}); + } else { + arrow.attr({stroke: "gray", "stroke-width": 2}); + } + }); + + + + arrow.click(function(evt) { + var popup = document.createElement("div"); + popup.className = "popUp"; + popup.innerHTML = "zxid: " + parseInt(this.zxid).toString(16); + + popup.style.top = evt.clientY; + popup.style.left = evt.clientX; + document.body.appendChild(popup); + + popup.onclick = function(evt) { + document.body.removeChild(popup); + }; + }); + } +}; + +LogGraph.ServerGraph.exception = function(graph, tick, exceptiontext, time) { + this.graph = graph; + this.time = time; + this.text = exceptiontext; + this.tick = tick; + + var self = this; + + this.draw = function(paper, server) { + var center = this.graph.tick_to_x(this.tick); + var p = paper.circle(center, server.y, 5); + p.attr({stroke: "orange", fill: "red"}); + + p.mouseover(function(evt) { + p.popup = document.createElement("div"); + p.popup.className = "popUp"; + p.popup.innerHTML = self.text.replace("\n", "
");; + p.popup.style.top = server.y + 50; + p.popup.style.left = center + 25; + document.body.appendChild(p.popup); + + p.animate({r: 10}, 500, "elastic"); + }); + p.mouseout(function(evt) { + document.body.removeChild(p.popup); + p.animate({r: 5}, 100); + }); + } +}; + http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.session.js ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.session.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.session.js new file mode 100644 index 0000000..5a314d8 --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.session.js @@ -0,0 +1,202 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +LogGraph.SessionGraph = function (asyncq, canvas, starttime, endtime, filter) { + this.sessions = new Array(); + this.counter = 0; + this.exceptions = new Array(); + + this.pix_per_ticks = 4; + this.pix_per_session = 7; + + var paper = Raphael(canvas, 1, 1); + this.ticker = new LogGraph.ticker(); + var self = this; + + this.starttime = starttime; + this.endtime = endtime; + this.filter = filter; + + this.findOrCreateSession = function(id) { + if (this.sessions[id] == undefined) { + this.sessions[id] = new LogGraph.SessionGraph.session(this, ++this.counter, id); + } + return this.sessions[id]; + } + + this.height = function () { return this.counter * this.pix_per_session + 10; }; + this.width = function () { return (self.ticker.current() * this.pix_per_ticks); }; + + this.draw = function(paper) { + + + var line = paper.path("M0 0 L0 " + this.height()); + line.attr({"stroke": "red", "stroke-dasharray": "- "}); + var base = canvas.offsetLeft; + var width = this.width(); + canvas.onmousemove = function (evt) { + var x = evt.clientX - base; + + line.attr({"path": "M" + x + " 0 L" + x + " " + self.height() }); + }; + + for (var i in this.sessions) { + var s = this.sessions[i]; + s.draw(paper); + } + }; + + var processdata = function(data) { + var count = 0; + for (var i in data.events) { + var e = data.events[i]; + if (e.type == "transaction") { + e.tick = self.ticker.tick(e.time, true); + var session = self.findOrCreateSession(e.client); + session.addEvent(e); + count++; + } + } + paper.setSize(self.width(), self.height()); + + if (count != 0) { + self.draw(paper); + return true; + } else { + return false; + } + }; + + var uri = "/data?start=" + self.starttime + "&end=" + self.endtime + "&filter=" + filter; + + LogGraph.loadData(asyncq, uri, processdata); +}; + +LogGraph.SessionGraph.sessionevent = function () { + this.time = time; + this.type = type; + this.client = client; + this.cxid = cxid; + this.zxid = zxid; + this.op = op; + this.extra = extra; +}; + +LogGraph.SessionGraph.sessionEventPopup = function (obj, e, x, y) { + obj.click(function(evt) { + var popup = document.createElement("div"); + popup.className = "popUp"; + + var closebutton = document.createElement("div"); + closebutton.className = "closebutton"; + closebutton.title = "Close popup"; + closebutton.innerHTML = "×"; + popup.appendChild(closebutton); + closebutton.onclick= function(evt) { popup.style.visibility = "hidden"; document.body.removeChild(popup) }; + var txt = document.createElement("span"); + txt.innerHTML = "session: " + e.client + "
op: " + e.op + "
zxid: " + e.zxid + "
time: " + e.time + "
extra: " + e.extra; + popup.appendChild(txt); + + popup.style.top = y; + popup.style.left = x; + document.body.appendChild(popup); + + YUI().use('dd-drag', function(Y) { + //Selector of the node to make draggable + var dd = new Y.DD.Drag({ + node: popup + }); + }); + }); +}; + +LogGraph.SessionGraph.session = function (graph, index, id) { + this.index = index; + this.id = id; + this.graph = graph; + + this.events = new Array(); + this.starttick = 0; + this.endtick = undefined; + + this.addEvent = function(e) { + this.events.push(e); + + if (e.op == "createSession") { + // document.write("createSession for " + id.toString(16)); + this.starttick = e.tick; + } else if (e.op == "closeSession") { + this.endtick = e.tick; + } + }, + + this._attach_action = function (sess, label) { + sess.mouseover(function(evt) { + label.show(); + sess.attr({stroke: "gray"}); + }); + + sess.mouseout(function(evt) { + label.hide(); + sess.attr({stroke: "black"}); + }); + }, + + this.drawEvent = function (paper, y, e) { + var x = e.tick * this.graph.pix_per_ticks;; + var s = paper.path("M" + x + " " + (y - 3) + " L" + x + " " + (y + 3)); + s.attr({"stroke-width": 2}); + if (e.op == "error") { + s.attr({"stroke": "red"}); + } + s.mouseover(function(evt) { + s.attr({"stroke-width": 5}); + }); + + s.mouseout(function(evt) { + s.attr({"stroke-width": 2}); + }); + + LogGraph.SessionGraph.sessionEventPopup(s, e, x, y); + }, + + this.draw = function(paper) { + var y = this.index*this.graph.pix_per_session;; + var start = this.starttick * this.graph.pix_per_ticks; + var end = this.endtick * this.graph.pix_per_ticks; + + var sess = paper.set(); + + if (this.endtick == undefined) { + end = this.graph.width(); + } + + sess.push(paper.path("M" + start + " " + y + " L" + end + " " + y)); + for (var i in this.events) { + var e = this.events[i]; + this.drawEvent(paper, y, e); + } + + //sess.attr({"stroke-width": 3}); + label = paper.text(start + 100, y, this.id); + label.attr({"font-size": "14px"}); + label.hide(); + this._attach_action(sess, label); + } +}; + http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.stats.js ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.stats.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.stats.js new file mode 100644 index 0000000..0a8ac4f --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.stats.js @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +LogGraph.StatsGraph = function (asyncq, canvas, starttime, endtime, filter) { + var processdata = function(data) { + var r = Raphael(canvas); + var x = data.map(function (x) { return x.time; }); + var y = data.map(function (x) { return x.count; }); + var xlabels = data.map(function (x) { return dateFormat(x.time, "HH:MM:ss,l"); } ); + var h1 = function () { + this.tags = r.set(); + for (var i = 0, ii = this.y.length; i < ii; i++) { + this.tags.push(r.g.tag(this.x, this.y[i], this.values[i], 160, 10).insertBefore(this).attr([{fill: "#fff"}, {fill: this.symbols[i].attr("fill")}])); + } + }; + var h2 = function () { + this.tags && this.tags.remove(); + }; + r.g.linechart(40, 40, 1000, 500, x, y, {shade: true, axis: "0 0 1 1", symbol: "x", southlabels: xlabels, axisxstep: xlabels.length - 1 , westAxisLabel: "Write requests", southAxisLabel: "Time (min)"}).hoverColumn(h1, h2); + + return true; + //r.g.barchart(0, 0, 1000, 100, y, {shade: true, symbol: "x"}).hoverColumn(h1, h2); + }; + + var uri = "/throughput?scale=minutes"; + LogGraph.loadData(asyncq, uri, processdata); +}; + + http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.ui.js ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.ui.js b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.ui.js new file mode 100644 index 0000000..819765a --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/loggraph.ui.js @@ -0,0 +1,377 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Opens a window to load files into the engine +LogGraph.fileSelector = function(callback) { + var self = this; + this.callback = callback; + this.selectedFiles = new Array(); + + var divTag = document.createElement("div"); + divTag.id = "fileSelector" + Math.round(Math.random()*100000); + // divTag.className = "popUp"; + divTag.className = "selector fileSelector"; + document.body.appendChild(divTag); + + YUI().use('dd-drag', function(Y) { + //Selector of the node to make draggable + var dd = new Y.DD.Drag({ + node: '#' + divTag.id + }); + }); + + var list = document.createElement("ul"); + divTag.appendChild(list); + var selectedList = document.createElement("selectedlist"); + divTag.appendChild(selectedList); + + var clearanchor = document.createElement("span"); + clearanchor.innerHTML = "Remove All"; + clearanchor.className = "actionbutton"; + clearanchor.style.cssFloat = "right"; + clearanchor.onclick = function () { + self.selectedFiles = new Array(); + self.updateSelectedList(); + }; + divTag.appendChild(clearanchor); + + var doneanchor = document.createElement("span"); + doneanchor.innerHTML = "Process Files"; + doneanchor.className = "actionbutton"; + doneanchor.style.cssFloat = "left"; + doneanchor.onclick = function () { + self.callback(self.selectedFiles); + document.body.removeChild(divTag); + delete divTag; + }; + divTag.appendChild(doneanchor); + + var cancelanchor = document.createElement("span"); + cancelanchor.innerHTML = "Cancel"; + cancelanchor.className = "actionbutton"; + cancelanchor.style.cssFloat = "left"; + cancelanchor.onclick = function () { + document.body.removeChild(divTag); + delete divTag; + }; + divTag.appendChild(cancelanchor); + + this.createFileListItem = function (file) { + var li = document.createElement("li"); + var a = document.createElement("a"); + if (file.type == "D") { + a.innerHTML = file.file + "/"; + a.onclick = function () { self.updateList(file.path); }; + } else { + a.innerHTML = file.file; + a.onclick = function () { self.addSelectedFile(file.path); }; + } + + a.fullpath = file.path;; + li.appendChild(a); + return li; + }; + + this.addSelectedFile = function (file) { + if (this.selectedFiles.indexOf(file) == -1) { + this.selectedFiles.push(file); + this.updateSelectedList(); + } + }; + + this.removeSelectedFile = function (file) { + this.selectedFiles = this.selectedFiles.filter(function(f) { return !(file == f); }); + this.updateSelectedList(); + }; + + this.createSelectedListItem = function (file) { + var li = document.createElement("li"); + var a = document.createElement("a"); + li.className = "selectedFile"; + a.onclick = function () { self.removeSelectedFile(file); }; + a.innerHTML = file; + li.appendChild(a); + return li; + }; + + this.updateSelectedList = function () { + while (selectedList.firstChild) { selectedList.removeChild(selectedList.firstChild); } + + for (var i in this.selectedFiles) { + var f = this.selectedFiles[i]; + selectedList.appendChild(this.createSelectedListItem(f)); + } + }; + + this.updateList = function (base) { + while (list.firstChild) list.removeChild(list.firstChild); + + // Create a YUI instance using io-base module. + YUI().use("io-base", function(Y) { + var uri = "/fs?path=" + base; + + // Define a function to handle the response data. + function complete(id, o, args) { + var id = id; // Transaction ID. + var data = eval("(" + o.responseText + ")"); // Response data. + var parts = base.split("/").slice(0,-1); + var parent = "" + if (parts.length < 2) { + parent = "/"; + } else { + parent = parts.join("/"); + } + if (base != "/") { + var li = self.createFileListItem({"file": "..", type: "D", path: parent}); + list.appendChild(li); + } + for (var i in data) { + var f = data[i]; + if (f.file[0] != '.') { + var li = self.createFileListItem(f); + list.appendChild(li); + } + } + }; + + Y.on('io:complete', complete, Y, []); + var request = Y.io(uri); + }); + }; + + this.updateList("/"); +}; + +// Open a window which loads files into the engine +LogGraph.fileLoader = function(files) { + var div = document.createElement("div"); + div.id = "fileLoader"; + + var imgArray = new Array(); + var pArray = new Array(); + for (var index in files) { + var f = files[index]; + var p = document.createElement("p"); + var i = document.createElement("img"); + i.src = "load.gif"; + i.style.visibility = "hidden"; + imgArray.push(i); + pArray.push(p); + var span = document.createElement("span"); + span.innerHTML = f; + + p.appendChild(span); + p.appendChild(i); + + div.appendChild(p); + } + + var loadFile = function (index) { + // Create a YUI instance using io-base module. + YUI().use("io-base", function(Y) { + var file = files[index]; + var uri = "/loadfile?path=" + file; + imgArray[index].style.visibility = "visible"; + + // Define a function to handle the response data. + function complete(id, o, args) { + var id = id; // Transaction ID. + var data = eval("(" + o.responseText + ")"); // Response data. + if (data.status == "ERR") { + var err = document.createElement("div"); + err.innerHTML = data.error; + pArray[index].appendChild(err); + } else if (data.status == "OK") { + var ok = document.createElement("div"); + ok.innerHTML = "OK"; + pArray[index].appendChild(ok); + } + + imgArray[index].style.visibility = "hidden"; + if (index + 1 < files.length) { + loadFile(index + 1); + } else { + //alert("DONE"); + } + }; + + Y.on('io:complete', complete, Y, []); + var request = Y.io(uri); + }); + }; + + var doneanchor = document.createElement("a"); + doneanchor.className = "actionbutton"; + doneanchor.innerHTML = "Done"; + doneanchor.onclick = function () { + document.body.removeChild(div); + delete div; + }; + + document.body.appendChild(div); + if (files.length > 0) { + loadFile(0); + } else { + div.innerHTML ="No files to load"; + } + div.appendChild(doneanchor); +} + +// select a time period +LogGraph.filterSelector = function(starttime, period, filter, callback) { + var self = this; + this.callback = callback; + + // Container other widgets will be in + var container = document.createElement("div"); + container.id = "filterSelector" + Math.round(Math.random()*100000); + container.className = "selector filterSelector"; + document.body.appendChild(container); + + YUI().use('dd-drag', function(Y) { + //Selector of the node to make draggable + var dd = new Y.DD.Drag({ + node: '#' + container.id + }); + }); + + // Temporary loading screen + var loadingp = document.createElement("p"); + loadingp.innerHTML = "Loading..."; + var loadimg = document.createElement("img"); + loadimg.src = "load.gif"; + loadingp.appendChild(loadimg); + container.appendChild(loadingp); + + var addWithLabel = function (container, labeltxt, object) { + var p = document.createElement("p"); + var label = document.createElement("label"); + label.innerHTML = labeltxt + ":"; + p.appendChild(label); + p.appendChild(object); + container.appendChild(p); + }; + var draw = function(minstart, maxstart, entries) { + container.removeChild(loadingp); + var inittime = minstart > starttime ? minstart : starttime; + + var numEntries = 0; + var startspan = document.createElement("span"); + addWithLabel(container, "Start time", startspan); + var startinput = document.createElement("input"); + startinput.type = "hidden"; + startinput.value = inittime; + container.appendChild(startinput); + var sliderspan = document.createElement("span"); + container.appendChild(sliderspan); + + var countspan = document.createElement("p"); + countspan.innerHTML = entries + " entries";; + container.appendChild(countspan); + + var windowinput = document.createElement("input"); + windowinput.type = "text"; + windowinput.value = period; + addWithLabel(container, "Time window (ms)", windowinput); + + var filterinput = document.createElement("textarea"); + filterinput.id = "filterinput"; + filterinput.value = filter; + addWithLabel(container, "Filter", filterinput); + + /* done link, when clicked time is updated, */ + var doneanchor = document.createElement("a"); + doneanchor.className = "actionbutton"; + doneanchor.innerHTML = "Done"; + doneanchor.onclick = function () { + var start = parseInt(startinput.value); + var period = parseInt(windowinput.value); + var filter = filterinput.value; + document.body.removeChild(container); + delete container; + + update(start, period, filter, function() { + callback(start, period, filter, numEntries); + }); + }; + container.appendChild(doneanchor); + + var update = function(start, period, filter, thenrun) { + startspan.innerHTML = dateFormat(start, "HH:MM:ss,l"); + // get the min and max start time + YUI().use("io-base", function(Y) { + var uri = "/info?start=" + start + "&period=" + period + "&filter=" + filter; + function complete(id, o, args) { + var data = eval("(" + o.responseText + ")"); + countspan.innerHTML = data.numEntries + " entries"; + numEntries = data.numEntries; + if (thenrun) { + thenrun(); + } + }; + + Y.on('io:complete', complete, Y, []); + var request = Y.io(uri); + }); + }; + + var updatewindow = function(evt) { + var start = parseInt(startinput.value); + var period = parseInt(windowinput.value); + var filter = filterinput.value; + update(start, period, filter); + }; + windowinput.onkeyup = updatewindow; + + + YUI().use("slider", function (Y) { + var input, slider; + + function updateInput( e ) { + this.set( "value", e.newVal ); + + update(parseInt(startinput.value), parseInt(windowinput.value), filterinput.value); + } + + xSlider = new Y.Slider({min: minstart, max: maxstart, value: inittime, length: "1000px" }); + + // Link the input value to the Slider + xInput = Y.one( startinput ); + xInput.setData( { slider: xSlider } ); + + // Pass the input as the 'this' object inside updateInput + xSlider.after( "valueChange", updateInput, xInput ); + + // Render the Slider next to the input + xSlider.render(sliderspan); + }); + update(inittime, windowinput.value, filterinput); + }; + + // get the min and max start time + YUI().use("io-base", function(Y) { + var uri = "/info"; + function complete(id, o, args) { + var data = eval("(" + o.responseText + ")"); + draw(data.startTime, data.endTime, data.numEntries); + }; + + Y.on('io:complete', complete, Y, []); + var request = Y.io(uri); + }); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zookeeper/blob/b0df8fe1/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/main.html ---------------------------------------------------------------------- diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/main.html b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/main.html new file mode 100644 index 0000000..b9affe6 --- /dev/null +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/webapp/org/apache/zookeeper/graph/resources/main.html @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
+ Edit Filters + Add logs +
+
+ Log view + Servers view + Sessions view + Statistics +
+
+
+
+
+ +