http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/py/storm/ttypes.py ---------------------------------------------------------------------- diff --git a/storm-core/src/py/storm/ttypes.py b/storm-core/src/py/storm/ttypes.py index a14d62d..6d9aa0b 100644 --- a/storm-core/src/py/storm/ttypes.py +++ b/storm-core/src/py/storm/ttypes.py @@ -8579,6 +8579,210 @@ class LSWorkerHeartbeat: def __ne__(self, other): return not (self == other) +class LSTopoHistory: + """ + Attributes: + - topology_id + - time_stamp + - users + - groups + """ + + thrift_spec = ( + None, # 0 + (1, TType.STRING, 'topology_id', None, None, ), # 1 + (2, TType.I64, 'time_stamp', None, None, ), # 2 + (3, TType.LIST, 'users', (TType.STRING,None), None, ), # 3 + (4, TType.LIST, 'groups', (TType.STRING,None), None, ), # 4 + ) + + def __init__(self, topology_id=None, time_stamp=None, users=None, groups=None,): + self.topology_id = topology_id + self.time_stamp = time_stamp + self.users = users + self.groups = groups + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.STRING: + self.topology_id = iprot.readString().decode('utf-8') + else: + iprot.skip(ftype) + elif fid == 2: + if ftype == TType.I64: + self.time_stamp = iprot.readI64(); + else: + iprot.skip(ftype) + elif fid == 3: + if ftype == TType.LIST: + self.users = [] + (_etype590, _size587) = iprot.readListBegin() + for _i591 in xrange(_size587): + _elem592 = iprot.readString().decode('utf-8') + self.users.append(_elem592) + iprot.readListEnd() + else: + iprot.skip(ftype) + elif fid == 4: + if ftype == TType.LIST: + self.groups = [] + (_etype596, _size593) = iprot.readListBegin() + for _i597 in xrange(_size593): + _elem598 = iprot.readString().decode('utf-8') + self.groups.append(_elem598) + iprot.readListEnd() + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('LSTopoHistory') + if self.topology_id is not None: + oprot.writeFieldBegin('topology_id', TType.STRING, 1) + oprot.writeString(self.topology_id.encode('utf-8')) + oprot.writeFieldEnd() + if self.time_stamp is not None: + oprot.writeFieldBegin('time_stamp', TType.I64, 2) + oprot.writeI64(self.time_stamp) + oprot.writeFieldEnd() + if self.users is not None: + oprot.writeFieldBegin('users', TType.LIST, 3) + oprot.writeListBegin(TType.STRING, len(self.users)) + for iter599 in self.users: + oprot.writeString(iter599.encode('utf-8')) + oprot.writeListEnd() + oprot.writeFieldEnd() + if self.groups is not None: + oprot.writeFieldBegin('groups', TType.LIST, 4) + oprot.writeListBegin(TType.STRING, len(self.groups)) + for iter600 in self.groups: + oprot.writeString(iter600.encode('utf-8')) + oprot.writeListEnd() + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + if self.topology_id is None: + raise TProtocol.TProtocolException(message='Required field topology_id is unset!') + if self.time_stamp is None: + raise TProtocol.TProtocolException(message='Required field time_stamp is unset!') + if self.users is None: + raise TProtocol.TProtocolException(message='Required field users is unset!') + if self.groups is None: + raise TProtocol.TProtocolException(message='Required field groups is unset!') + return + + + def __hash__(self): + value = 17 + value = (value * 31) ^ hash(self.topology_id) + value = (value * 31) ^ hash(self.time_stamp) + value = (value * 31) ^ hash(self.users) + value = (value * 31) ^ hash(self.groups) + return value + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + +class LSTopoHistoryList: + """ + Attributes: + - topo_history + """ + + thrift_spec = ( + None, # 0 + (1, TType.LIST, 'topo_history', (TType.STRUCT,(LSTopoHistory, LSTopoHistory.thrift_spec)), None, ), # 1 + ) + + def __init__(self, topo_history=None,): + self.topo_history = topo_history + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.LIST: + self.topo_history = [] + (_etype604, _size601) = iprot.readListBegin() + for _i605 in xrange(_size601): + _elem606 = LSTopoHistory() + _elem606.read(iprot) + self.topo_history.append(_elem606) + iprot.readListEnd() + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('LSTopoHistoryList') + if self.topo_history is not None: + oprot.writeFieldBegin('topo_history', TType.LIST, 1) + oprot.writeListBegin(TType.STRUCT, len(self.topo_history)) + for iter607 in self.topo_history: + iter607.write(oprot) + oprot.writeListEnd() + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + if self.topo_history is None: + raise TProtocol.TProtocolException(message='Required field topo_history is unset!') + return + + + def __hash__(self): + value = 17 + value = (value * 31) ^ hash(self.topo_history) + return value + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + class ProfileRequest: """ Attributes: @@ -8886,12 +9090,12 @@ class LogConfig: if fid == 2: if ftype == TType.MAP: self.named_logger_level = {} - (_ktype588, _vtype589, _size587 ) = iprot.readMapBegin() - for _i591 in xrange(_size587): - _key592 = iprot.readString().decode('utf-8') - _val593 = LogLevel() - _val593.read(iprot) - self.named_logger_level[_key592] = _val593 + (_ktype609, _vtype610, _size608 ) = iprot.readMapBegin() + for _i612 in xrange(_size608): + _key613 = iprot.readString().decode('utf-8') + _val614 = LogLevel() + _val614.read(iprot) + self.named_logger_level[_key613] = _val614 iprot.readMapEnd() else: iprot.skip(ftype) @@ -8908,9 +9112,9 @@ class LogConfig: if self.named_logger_level is not None: oprot.writeFieldBegin('named_logger_level', TType.MAP, 2) oprot.writeMapBegin(TType.STRING, TType.STRUCT, len(self.named_logger_level)) - for kiter594,viter595 in self.named_logger_level.items(): - oprot.writeString(kiter594.encode('utf-8')) - viter595.write(oprot) + for kiter615,viter616 in self.named_logger_level.items(): + oprot.writeString(kiter615.encode('utf-8')) + viter616.write(oprot) oprot.writeMapEnd() oprot.writeFieldEnd() oprot.writeFieldStop() @@ -8936,6 +9140,79 @@ class LogConfig: def __ne__(self, other): return not (self == other) +class TopologyHistoryInfo: + """ + Attributes: + - topo_ids + """ + + thrift_spec = ( + None, # 0 + (1, TType.LIST, 'topo_ids', (TType.STRING,None), None, ), # 1 + ) + + def __init__(self, topo_ids=None,): + self.topo_ids = topo_ids + + def read(self, iprot): + if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None: + fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec)) + return + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.LIST: + self.topo_ids = [] + (_etype620, _size617) = iprot.readListBegin() + for _i621 in xrange(_size617): + _elem622 = iprot.readString().decode('utf-8') + self.topo_ids.append(_elem622) + iprot.readListEnd() + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None: + oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('TopologyHistoryInfo') + if self.topo_ids is not None: + oprot.writeFieldBegin('topo_ids', TType.LIST, 1) + oprot.writeListBegin(TType.STRING, len(self.topo_ids)) + for iter623 in self.topo_ids: + oprot.writeString(iter623.encode('utf-8')) + oprot.writeListEnd() + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + + def __hash__(self): + value = 17 + value = (value * 31) ^ hash(self.topo_ids) + return value + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.iteritems()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + class DRPCRequest: """ Attributes:
http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/storm.thrift ---------------------------------------------------------------------- diff --git a/storm-core/src/storm.thrift b/storm-core/src/storm.thrift index 51e1236..5496ff2 100644 --- a/storm-core/src/storm.thrift +++ b/storm-core/src/storm.thrift @@ -461,6 +461,17 @@ struct LSWorkerHeartbeat { 4: required i32 port; } +struct LSTopoHistory { + 1: required string topology_id; + 2: required i64 time_stamp; + 3: required list<string> users; + 4: required list<string> groups; +} + +struct LSTopoHistoryList { + 1: required list<LSTopoHistory> topo_history; +} + enum NumErrorsChoice { ALL, NONE, @@ -518,6 +529,10 @@ struct LogConfig { 2: optional map<string, LogLevel> named_logger_level; } +struct TopologyHistoryInfo { + 1: list<string> topo_ids; +} + service Nimbus { void submitTopology(1: string name, 2: string uploadedJarLocation, 3: string jsonConf, 4: StormTopology topology) throws (1: AlreadyAliveException e, 2: InvalidTopologyException ite, 3: AuthorizationException aze); void submitTopologyWithOpts(1: string name, 2: string uploadedJarLocation, 3: string jsonConf, 4: StormTopology topology, 5: SubmitOptions options) throws (1: AlreadyAliveException e, 2: InvalidTopologyException ite, 3: AuthorizationException aze); @@ -573,6 +588,7 @@ service Nimbus { * Returns the user specified topology as submitted originally. Compare {@link #getTopology(String id)}. */ StormTopology getUserTopology(1: string id) throws (1: NotAliveException e, 2: AuthorizationException aze); + TopologyHistoryInfo getTopologyHistory(1: string user) throws (1: AuthorizationException aze); } struct DRPCRequest { http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/ui/public/deep_search_result.html ---------------------------------------------------------------------- diff --git a/storm-core/src/ui/public/deep_search_result.html b/storm-core/src/ui/public/deep_search_result.html new file mode 100644 index 0000000..30d54d1 --- /dev/null +++ b/storm-core/src/ui/public/deep_search_result.html @@ -0,0 +1,155 @@ +<html><head> + <!-- + 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. + --> +<meta charset="UTF-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>Storm UI</title> +<link href="/css/bootstrap-3.3.1.min.css" rel="stylesheet" type="text/css"> +<link href="/css/jquery.dataTables.1.10.4.min.css" rel="stylesheet" type="text/css"> +<link href="/css/dataTables.bootstrap.css" rel="stylesheet" type="text/css"> +<link href="/css/style.css" rel="stylesheet" type="text/css"> +<script src="/js/jquery-1.11.1.min.js" type="text/javascript"></script> +<script src="/js/jquery.dataTables.1.10.4.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/typeahead.jquery.min.js" type="text/javascript"></script> +<script src="/js/bootstrap-3.3.1.min.js" type="text/javascript"></script> +<script src="/js/jquery.blockUI.min.js" type="text/javascript"></script> +<script src="/js/url.min.js" type="text/javascript"></script> +<script src="/js/dataTables.bootstrap.min.js" type="text/javascript"></script> +<script src="/js/script.js" type="text/javascript"></script> +</head> +<body> +<div class="container-fluid"> + <div class="row"> + <div id="search-form"></div> + </div> + <div class="row"> + <div id="result"></div> + </div> +</div> +</body> +<script type="text/javascript"> + +function elem_id_for_host(host) { + return "search-results-"+host.replace(/\./g,"-"); +} + +$(document).ready(function() { + var id = $.url("?id"); + var search = $.url("?search"); + var count = $.url("?count") || 2; + var port = $.url("?port") || "*"; + var search_archived = $.url("?search-archived"); + + $.get("/templates/deep-search-result-page-template.html", function(template) { + var checked; + if (search_archived) { + checked = "checked"; + } + $.get("/api/v1/history/summary", function (response, status, jqXHR) { + var findIds = function findIds(query, cb) { + var found = []; + var re = new RegExp(query, 'i'); + for (var i in response["topo-history"]) { + var host = response["topo-history"][i].host; + if (re.test(host)) { + found.push({ value: host }); + } + } + cb(found); + }; + + $("#search-form").append(Mustache.render($(template).filter("#search-form-template").html(),{id: id, search: search, count: count, search_archived: checked, topologies: response["topo-history"]})); + $('#search-id').typeahead({ + hint: true, + highlight: true, + minLength: 1 + }, + { + name: 'ids', + displayKey: 'value', + source: findIds + }); + $('#search-form [data-toggle="tooltip"]').tooltip(); + }); + + function render_file(file, host, logviewerPort, count, template) { + file.host = host; + file.id = id; + file.count = count; + file.logviewerPort = logviewerPort; + file.search_archived = search_archived; + var searchTemplate = $(template).filter("#search-result-identified-template").html(); + var rendered = Mustache.render(searchTemplate, file); + var elemId = elem_id_for_host(host); + $("#"+elemId).remove(); + $("#search-result-table > tbody").append(rendered); + } + + + var result = $("#result"); + if(search) { + $.get("/api/v1/supervisor/summary", function(response, status, jqXHR) { + + for(var i in response.supervisors) { + response.supervisors[i].elemId = elem_id_for_host(response.supervisors[i].host); + } + + result.append(Mustache.render($(template).filter("#search-result-files-template").html(),response)); + + var logviewerPort = response.logviewerPort; + var distinct_hosts = {}; + for (var index in response.supervisors) { + distinct_hosts[response.supervisors[index].host] = true; + } + + + for (var host in distinct_hosts) { + var searchURL = "http://"+host+":"+logviewerPort+"/deepSearch/"+id+"?search-string="+search+"&num-matches="+count+"&port="+port; + if(search_archived) + searchURL += "&search-archived=" + search_archived; + + + $.ajax({dataType: "json", + url: searchURL, + xhrFields: { + withCredentials: true + }, + success: $.proxy(function(data,status,jqXHR) { + if(port == "*") { + for(var by_port in data) { + for(var i in data[by_port].matches) { + render_file(data[by_port].matches[i], this.host, logviewerPort, count, template); + } + } + } + else { + for(var i in data.matches) { + render_file(data.matches[i], this.host, logviewerPort, count, template); + } + } + }, {host: host, id: id}) + }); + } + }); + } + }); +}); + +</script> +</html> http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/ui/public/images/search.png ---------------------------------------------------------------------- diff --git a/storm-core/src/ui/public/images/search.png b/storm-core/src/ui/public/images/search.png new file mode 100644 index 0000000..fa3a689 Binary files /dev/null and b/storm-core/src/ui/public/images/search.png differ http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/ui/public/js/typeahead.jquery.min.js ---------------------------------------------------------------------- diff --git a/storm-core/src/ui/public/js/typeahead.jquery.min.js b/storm-core/src/ui/public/js/typeahead.jquery.min.js new file mode 100644 index 0000000..3ee29eb --- /dev/null +++ b/storm-core/src/ui/public/js/typeahead.jquery.min.js @@ -0,0 +1,7 @@ +/*! + * typeahead.js 0.10.5 + * https://github.com/twitter/typeahead.js + * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT + */ + +!function(a){var b=function(){"use strict";return{isMsie:function(){return/(msie|trident)/i.test(navigator.userAgent)?navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2]:!1},isBlankString:function(a){return!a||/^\s*$/.test(a)},escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(a){return"string"==typeof a},isNumber:function(a){return"number"==typeof a},isArray:a.isArray,isFunction:a.isFunction,isObject:a.isPlainObject,isUndefined:function(a){return"undefined"==typeof a},toStr:function(a){return b.isUndefined(a)||null===a?"":a+""},bind:a.proxy,each:function(b,c){function d(a,b){return c(b,a)}a.each(b,d)},map:a.map,filter:a.grep,every:function(b,c){var d=!0;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?void 0:!1}),!!d):d},some:function(b,c){var d=!1;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?!1:void 0}),!!d):d},mixin:a.extend,getUniqueId:function(){var a=0;return function(){return a++}}( ),templatify:function(b){function c(){return String(b)}return a.isFunction(b)?b:c},defer:function(a){setTimeout(a,0)},debounce:function(a,b,c){var d,e;return function(){var f,g,h=this,i=arguments;return f=function(){d=null,c||(e=a.apply(h,i))},g=c&&!d,clearTimeout(d),d=setTimeout(f,b),g&&(e=a.apply(h,i)),e}},throttle:function(a,b){var c,d,e,f,g,h;return g=0,h=function(){g=new Date,e=null,f=a.apply(c,d)},function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,0>=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},noop:function(){}}}(),c=function(){return{wrapper:'<span class="twitter-typeahead"></span>',dropdown:'<span class="tt-dropdown-menu"></span>',dataset:'<div class="tt-dataset-%CLASS%"></div>',suggestions:'<span class="tt-suggestions"></span>',suggestion:'<div class="tt-suggestion"></div>'}}(),d=function(){"use strict";var a={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxS hadow:"none",opacity:"1"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},dropdown:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},suggestions:{display:"block"},suggestion:{whiteSpace:"nowrap",cursor:"pointer"},suggestionChild:{whiteSpace:"normal"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:" 0"}};return b.isMsie()&&b.mixin(a.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),b.isMsie()&&b.isMsie()<=7&&b.mixin(a.input,{marginTop:"-1px"}),a}(),e=function(){"use strict";function c(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el)}var d="typeahead:";return b.mixin(c.prototype,{trigger:function(a){var b=[].slice.call(arguments,1);this.$el.trigger(d+a,b)}}),c}(),f=function(){"use strict";function a(a,b,c,d){var e;if(!c)return this;for(b=b.split(i),c=d?h(c,d):c,this._callbacks=this._callbacks ||{};e=b.shift();)this._callbacks[e]=this._callbacks[e]||{sync:[],async:[]},this._callbacks[e][a].push(c);return this}function b(b,c,d){return a.call(this,"async",b,c,d)}function c(b,c,d){return a.call(this,"sync",b,c,d)}function d(a){var b;if(!this._callbacks)return this;for(a=a.split(i);b=a.shift();)delete this._callbacks[b];return this}function e(a){var b,c,d,e,g;if(!this._callbacks)return this;for(a=a.split(i),d=[].slice.call(arguments,1);(b=a.shift())&&(c=this._callbacks[b]);)e=f(c.sync,this,[b].concat(d)),g=f(c.async,this,[b].concat(d)),e()&&j(g);return this}function f(a,b,c){function d(){for(var d,e=0,f=a.length;!d&&f>e;e+=1)d=a[e].apply(b,c)===!1;return!d}return d}function g(){var a;return a=window.setImmediate?function(a){setImmediate(function(){a()})}:function(a){setTimeout(function(){a()},0)}}function h(a,b){return a.bind?a.bind(b):function(){a.apply(b,[].slice.call(arguments,0))}}var i=/\s+/,j=g();return{onSync:c,onAsync:b,off:d,trigger:e}}(),g=function(a){"use strict";f unction c(a,c,d){for(var e,f=[],g=0,h=a.length;h>g;g++)f.push(b.escapeRegExChars(a[g]));return e=d?"\\b("+f.join("|")+")\\b":"("+f.join("|")+")",c?new RegExp(e):new RegExp(e,"i")}var d={node:null,pattern:null,tagName:"strong",className:null,wordsOnly:!1,caseSensitive:!1};return function(e){function f(b){var c,d,f;return(c=h.exec(b.data))&&(f=a.createElement(e.tagName),e.className&&(f.className=e.className),d=b.splitText(c.index),d.splitText(c[0].length),f.appendChild(d.cloneNode(!0)),b.parentNode.replaceChild(f,d)),!!c}function g(a,b){for(var c,d=3,e=0;e<a.childNodes.length;e++)c=a.childNodes[e],c.nodeType===d?e+=b(c)?1:0:g(c,b)}var h;e=b.mixin({},d,e),e.node&&e.pattern&&(e.pattern=b.isArray(e.pattern)?e.pattern:[e.pattern],h=c(e.pattern,e.caseSensitive,e.wordsOnly),g(e.node,f))}}(window.document),h=function(){"use strict";function c(c){var e,f,g,i,j=this;c=c||{},c.input||a.error("input is missing"),e=b.bind(this._onBlur,this),f=b.bind(this._onFocus,this),g=b.bind(this._onKeydown,th is),i=b.bind(this._onInput,this),this.$hint=a(c.hint),this.$input=a(c.input).on("blur.tt",e).on("focus.tt",f).on("keydown.tt",g),0===this.$hint.length&&(this.setHint=this.getHint=this.clearHint=this.clearHintIfInvalid=b.noop),b.isMsie()?this.$input.on("keydown.tt keypress.tt cut.tt paste.tt",function(a){h[a.which||a.keyCode]||b.defer(b.bind(j._onInput,j,a))}):this.$input.on("input.tt",i),this.query=this.$input.val(),this.$overflowHelper=d(this.$input)}function d(b){return a('<pre aria-hidden="true"></pre>').css({position:"absolute",visibility:"hidden",whiteSpace:"pre",fontFamily:b.css("font-family"),fontSize:b.css("font-size"),fontStyle:b.css("font-style"),fontVariant:b.css("font-variant"),fontWeight:b.css("font-weight"),wordSpacing:b.css("word-spacing"),letterSpacing:b.css("letter-spacing"),textIndent:b.css("text-indent"),textRendering:b.css("text-rendering"),textTransform:b.css("text-transform")}).insertAfter(b)}function e(a,b){return c.normalizeQuery(a)===c.normalizeQuery(b)}func tion g(a){return a.altKey||a.ctrlKey||a.metaKey||a.shiftKey}var h;return h={9:"tab",27:"esc",37:"left",39:"right",13:"enter",38:"up",40:"down"},c.normalizeQuery=function(a){return(a||"").replace(/^\s*/g,"").replace(/\s{2,}/g," ")},b.mixin(c.prototype,f,{_onBlur:function(){this.resetInputValue(),this.trigger("blurred")},_onFocus:function(){this.trigger("focused")},_onKeydown:function(a){var b=h[a.which||a.keyCode];this._managePreventDefault(b,a),b&&this._shouldTrigger(b,a)&&this.trigger(b+"Keyed",a)},_onInput:function(){this._checkInputValue()},_managePreventDefault:function(a,b){var c,d,e;switch(a){case"tab":d=this.getHint(),e=this.getInputValue(),c=d&&d!==e&&!g(b);break;case"up":case"down":c=!g(b);break;default:c=!1}c&&b.preventDefault()},_shouldTrigger:function(a,b){var c;switch(a){case"tab":c=!g(b);break;default:c=!0}return c},_checkInputValue:function(){var a,b,c;a=this.getInputValue(),b=e(a,this.query),c=b?this.query.length!==a.length:!1,this.query=a,b?c&&this.trigger("whitespa ceChanged",this.query):this.trigger("queryChanged",this.query)},focus:function(){this.$input.focus()},blur:function(){this.$input.blur()},getQuery:function(){return this.query},setQuery:function(a){this.query=a},getInputValue:function(){return this.$input.val()},setInputValue:function(a,b){this.$input.val(a),b?this.clearHint():this._checkInputValue()},resetInputValue:function(){this.setInputValue(this.query,!0)},getHint:function(){return this.$hint.val()},setHint:function(a){this.$hint.val(a)},clearHint:function(){this.setHint("")},clearHintIfInvalid:function(){var a,b,c,d;a=this.getInputValue(),b=this.getHint(),c=a!==b&&0===b.indexOf(a),d=""!==a&&c&&!this.hasOverflow(),!d&&this.clearHint()},getLanguageDirection:function(){return(this.$input.css("direction")||"ltr").toLowerCase()},hasOverflow:function(){var a=this.$input.width()-2;return this.$overflowHelper.text(this.getInputValue()),this.$overflowHelper.width()>=a},isCursorAtEnd:function(){var a,c,d;return a=this.$input.val().leng th,c=this.$input[0].selectionStart,b.isNumber(c)?c===a:document.selection?(d=document.selection.createRange(),d.moveStart("character",-a),a===d.text.length):!0},destroy:function(){this.$hint.off(".tt"),this.$input.off(".tt"),this.$hint=this.$input=this.$overflowHelper=null}}),c}(),i=function(){"use strict";function e(d){d=d||{},d.templates=d.templates||{},d.source||a.error("missing source"),d.name&&!j(d.name)&&a.error("invalid dataset name: "+d.name),this.query=null,this.highlight=!!d.highlight,this.name=d.name||b.getUniqueId(),this.source=d.source,this.displayFn=h(d.display||d.displayKey),this.templates=i(d.templates,this.displayFn),this.$el=a(c.dataset.replace("%CLASS%",this.name))}function h(a){function c(b){return b[a]}return a=a||"value",b.isFunction(a)?a:c}function i(a,c){function d(a){return"<p>"+c(a)+"</p>"}return{empty:a.empty&&b.templatify(a.empty),header:a.header&&b.templatify(a.header),footer:a.footer&&b.templatify(a.footer),suggestion:a.suggestion||d}}function j(a){retu rn/^[_a-zA-Z0-9-]+$/.test(a)}var k="ttDataset",l="ttValue",m="ttDatum";return e.extractDatasetName=function(b){return a(b).data(k)},e.extractValue=function(b){return a(b).data(l)},e.extractDatum=function(b){return a(b).data(m)},b.mixin(e.prototype,f,{_render:function(e,f){function h(){return p.templates.empty({query:e,isEmpty:!0})}function i(){function h(b){var e;return e=a(c.suggestion).append(p.templates.suggestion(b)).data(k,p.name).data(l,p.displayFn(b)).data(m,b),e.children().each(function(){a(this).css(d.suggestionChild)}),e}var i,j;return i=a(c.suggestions).css(d.suggestions),j=b.map(f,h),i.append.apply(i,j),p.highlight&&g({className:"tt-highlight",node:i[0],pattern:e}),i}function j(){return p.templates.header({query:e,isEmpty:!o})}function n(){return p.templates.footer({query:e,isEmpty:!o})}if(this.$el){var o,p=this;this.$el.empty(),o=f&&f.length,!o&&this.templates.empty?this.$el.html(h()).prepend(p.templates.header?j():null).append(p.templates.footer?n():null):o&&this.$el.h tml(i()).prepend(p.templates.header?j():null).append(p.templates.footer?n():null),this.trigger("rendered")}},getRoot:function(){return this.$el},update:function(a){function b(b){c.canceled||a!==c.query||c._render(a,b)}var c=this;this.query=a,this.canceled=!1,this.source(a,b)},cancel:function(){this.canceled=!0},clear:function(){this.cancel(),this.$el.empty(),this.trigger("rendered")},isEmpty:function(){return this.$el.is(":empty")},destroy:function(){this.$el=null}}),e}(),j=function(){"use strict";function c(c){var d,f,g,h=this;c=c||{},c.menu||a.error("menu is required"),this.isOpen=!1,this.isEmpty=!0,this.datasets=b.map(c.datasets,e),d=b.bind(this._onSuggestionClick,this),f=b.bind(this._onSuggestionMouseEnter,this),g=b.bind(this._onSuggestionMouseLeave,this),this.$menu=a(c.menu).on("click.tt",".tt-suggestion",d).on("mouseenter.tt",".tt-suggestion",f).on("mouseleave.tt",".tt-suggestion",g),b.each(this.datasets,function(a){h.$menu.append(a.getRoot()),a.onSync("rendered",h._onRendered ,h)})}function e(a){return new i(a)}return b.mixin(c.prototype,f,{_onSuggestionClick:function(b){this.trigger("suggestionClicked",a(b.currentTarget))},_onSuggestionMouseEnter:function(b){this._removeCursor(),this._setCursor(a(b.currentTarget),!0)},_onSuggestionMouseLeave:function(){this._removeCursor()},_onRendered:function(){function a(a){return a.isEmpty()}this.isEmpty=b.every(this.datasets,a),this.isEmpty?this._hide():this.isOpen&&this._show(),this.trigger("datasetRendered")},_hide:function(){this.$menu.hide()},_show:function(){this.$menu.css("display","block")},_getSuggestions:function(){return this.$menu.find(".tt-suggestion")},_getCursor:function(){return this.$menu.find(".tt-cursor").first()},_setCursor:function(a,b){a.first().addClass("tt-cursor"),!b&&this.trigger("cursorMoved")},_removeCursor:function(){this._getCursor().removeClass("tt-cursor")},_moveCursor:function(a){var b,c,d,e;if(this.isOpen){if(c=this._getCursor(),b=this._getSuggestions(),this._removeCursor(),d=b.inde x(c)+a,d=(d+1)%(b.length+1)-1,-1===d)return void this.trigger("cursorRemoved");-1>d&&(d=b.length-1),this._setCursor(e=b.eq(d)),this._ensureVisible(e)}},_ensureVisible:function(a){var b,c,d,e;b=a.position().top,c=b+a.outerHeight(!0),d=this.$menu.scrollTop(),e=this.$menu.height()+parseInt(this.$menu.css("paddingTop"),10)+parseInt(this.$menu.css("paddingBottom"),10),0>b?this.$menu.scrollTop(d+b):c>e&&this.$menu.scrollTop(d+(c-e))},close:function(){this.isOpen&&(this.isOpen=!1,this._removeCursor(),this._hide(),this.trigger("closed"))},open:function(){this.isOpen||(this.isOpen=!0,!this.isEmpty&&this._show(),this.trigger("opened"))},setLanguageDirection:function(a){this.$menu.css("ltr"===a?d.ltr:d.rtl)},moveCursorUp:function(){this._moveCursor(-1)},moveCursorDown:function(){this._moveCursor(1)},getDatumForSuggestion:function(a){var b=null;return a.length&&(b={raw:i.extractDatum(a),value:i.extractValue(a),datasetName:i.extractDatasetName(a)}),b},getDatumForCursor:function(){return this.get DatumForSuggestion(this._getCursor().first())},getDatumForTopSuggestion:function(){return this.getDatumForSuggestion(this._getSuggestions().first())},update:function(a){function c(b){b.update(a)}b.each(this.datasets,c)},empty:function(){function a(a){a.clear()}b.each(this.datasets,a),this.isEmpty=!0},isVisible:function(){return this.isOpen&&!this.isEmpty},destroy:function(){function a(a){a.destroy()}this.$menu.off(".tt"),this.$menu=null,b.each(this.datasets,a)}}),c}(),k=function(){"use strict";function f(c){var d,f,i;c=c||{},c.input||a.error("missing input"),this.isActivated=!1,this.autoselect=!!c.autoselect,this.minLength=b.isNumber(c.minLength)?c.minLength:1,this.$node=g(c.input,c.withHint),d=this.$node.find(".tt-dropdown-menu"),f=this.$node.find(".tt-input"),i=this.$node.find(".tt-hint"),f.on("blur.tt",function(a){var c,e,g;c=document.activeElement,e=d.is(c),g=d.has(c).length>0,b.isMsie()&&(e||g)&&(a.preventDefault(),a.stopImmediatePropagation(),b.defer(function(){f.focus()}))}), d.on("mousedown.tt",function(a){a.preventDefault()}),this.eventBus=c.eventBus||new e({el:f}),this.dropdown=new j({menu:d,datasets:c.datasets}).onSync("suggestionClicked",this._onSuggestionClicked,this).onSync("cursorMoved",this._onCursorMoved,this).onSync("cursorRemoved",this._onCursorRemoved,this).onSync("opened",this._onOpened,this).onSync("closed",this._onClosed,this).onAsync("datasetRendered",this._onDatasetRendered,this),this.input=new h({input:f,hint:i}).onSync("focused",this._onFocused,this).onSync("blurred",this._onBlurred,this).onSync("enterKeyed",this._onEnterKeyed,this).onSync("tabKeyed",this._onTabKeyed,this).onSync("escKeyed",this._onEscKeyed,this).onSync("upKeyed",this._onUpKeyed,this).onSync("downKeyed",this._onDownKeyed,this).onSync("leftKeyed",this._onLeftKeyed,this).onSync("rightKeyed",this._onRightKeyed,this).onSync("queryChanged",this._onQueryChanged,this).onSync("whitespaceChanged",this._onWhitespaceChanged,this),this._setLanguageDirection()}function g(b,e){var f,g,h,j;f=a(b),g=a(c.wrapper).css(d.wrapper),h=a(c.dropdown).css(d.dropdown),j=f.clone().css(d.hint).css(i(f)),j.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder required").prop("readonly",!0).attr({autocomplete:"off",spellcheck:"false",tabindex:-1}),f.data(l,{dir:f.attr("dir"),autocomplete:f.attr("autocomplete"),spellcheck:f.attr("spellcheck"),style:f.attr("style")}),f.addClass("tt-input").attr({autocomplete:"off",spellcheck:!1}).css(e?d.input:d.inputWithNoHint);try{!f.attr("dir")&&f.attr("dir","auto")}catch(k){}return f.wrap(g).parent().prepend(e?j:null).append(h)}function i(a){return{backgroundAttachment:a.css("background-attachment"),backgroundClip:a.css("background-clip"),backgroundColor:a.css("background-color"),backgroundImage:a.css("background-image"),backgroundOrigin:a.css("background-origin"),backgroundPosition:a.css("background-position"),backgroundRepeat:a.css("background-repeat"),backgroundSize:a.css("background-size")}}function k(a){var c=a.find (".tt-input");b.each(c.data(l),function(a,d){b.isUndefined(a)?c.removeAttr(d):c.attr(d,a)}),c.detach().removeData(l).removeClass("tt-input").insertAfter(a),a.remove()}var l="ttAttrs";return b.mixin(f.prototype,{_onSuggestionClicked:function(a,b){var c;(c=this.dropdown.getDatumForSuggestion(b))&&this._select(c)},_onCursorMoved:function(){var a=this.dropdown.getDatumForCursor();this.input.setInputValue(a.value,!0),this.eventBus.trigger("cursorchanged",a.raw,a.datasetName)},_onCursorRemoved:function(){this.input.resetInputValue(),this._updateHint()},_onDatasetRendered:function(){this._updateHint()},_onOpened:function(){this._updateHint(),this.eventBus.trigger("opened")},_onClosed:function(){this.input.clearHint(),this.eventBus.trigger("closed")},_onFocused:function(){this.isActivated=!0,this.dropdown.open()},_onBlurred:function(){this.isActivated=!1,this.dropdown.empty(),this.dropdown.close()},_onEnterKeyed:function(a,b){var c,d;c=this.dropdown.getDatumForCursor(),d=this.dropdown.getDa tumForTopSuggestion(),c?(this._select(c),b.preventDefault()):this.autoselect&&d&&(this._select(d),b.preventDefault())},_onTabKeyed:function(a,b){var c;(c=this.dropdown.getDatumForCursor())?(this._select(c),b.preventDefault()):this._autocomplete(!0)},_onEscKeyed:function(){this.dropdown.close(),this.input.resetInputValue()},_onUpKeyed:function(){var a=this.input.getQuery();this.dropdown.isEmpty&&a.length>=this.minLength?this.dropdown.update(a):this.dropdown.moveCursorUp(),this.dropdown.open()},_onDownKeyed:function(){var a=this.input.getQuery();this.dropdown.isEmpty&&a.length>=this.minLength?this.dropdown.update(a):this.dropdown.moveCursorDown(),this.dropdown.open()},_onLeftKeyed:function(){"rtl"===this.dir&&this._autocomplete()},_onRightKeyed:function(){"ltr"===this.dir&&this._autocomplete()},_onQueryChanged:function(a,b){this.input.clearHintIfInvalid(),b.length>=this.minLength?this.dropdown.update(b):this.dropdown.empty(),this.dropdown.open(),this._setLanguageDirection()},_onWhites paceChanged:function(){this._updateHint(),this.dropdown.open()},_setLanguageDirection:function(){var a;this.dir!==(a=this.input.getLanguageDirection())&&(this.dir=a,this.$node.css("direction",a),this.dropdown.setLanguageDirection(a))},_updateHint:function(){var a,c,d,e,f,g;a=this.dropdown.getDatumForTopSuggestion(),a&&this.dropdown.isVisible()&&!this.input.hasOverflow()?(c=this.input.getInputValue(),d=h.normalizeQuery(c),e=b.escapeRegExChars(d),f=new RegExp("^(?:"+e+")(.+$)","i"),g=f.exec(a.value),g?this.input.setHint(c+g[1]):this.input.clearHint()):this.input.clearHint()},_autocomplete:function(a){var b,c,d,e;b=this.input.getHint(),c=this.input.getQuery(),d=a||this.input.isCursorAtEnd(),b&&c!==b&&d&&(e=this.dropdown.getDatumForTopSuggestion(),e&&this.input.setInputValue(e.value),this.eventBus.trigger("autocompleted",e.raw,e.datasetName))},_select:function(a){this.input.setQuery(a.value),this.input.setInputValue(a.value,!0),this._setLanguageDirection(),this.eventBus.trigger("selecte d",a.raw,a.datasetName),this.dropdown.close(),b.defer(b.bind(this.dropdown.empty,this.dropdown))},open:function(){this.dropdown.open()},close:function(){this.dropdown.close()},setVal:function(a){a=b.toStr(a),this.isActivated?this.input.setInputValue(a):(this.input.setQuery(a),this.input.setInputValue(a,!0)),this._setLanguageDirection()},getVal:function(){return this.input.getQuery()},destroy:function(){this.input.destroy(),this.dropdown.destroy(),k(this.$node),this.$node=null}}),f}();!function(){"use strict";var c,d,f;c=a.fn.typeahead,d="ttTypeahead",f={initialize:function(c,f){function g(){var g,h,i=a(this);b.each(f,function(a){a.highlight=!!c.highlight}),h=new k({input:i,eventBus:g=new e({el:i}),withHint:b.isUndefined(c.hint)?!0:!!c.hint,minLength:c.minLength,autoselect:c.autoselect,datasets:f}),i.data(d,h)}return f=b.isArray(f)?f:[].slice.call(arguments,1),c=c||{},this.each(g)},open:function(){function b(){var b,c=a(this);(b=c.data(d))&&b.open()}return this.each(b)},close:functio n(){function b(){var b,c=a(this);(b=c.data(d))&&b.close()}return this.each(b)},val:function(b){function c(){var c,e=a(this);(c=e.data(d))&&c.setVal(b)}function e(a){var b,c;return(b=a.data(d))&&(c=b.getVal()),c}return arguments.length?this.each(c):e(this.first())},destroy:function(){function b(){var b,c=a(this);(b=c.data(d))&&(b.destroy(),c.removeData(d))}return this.each(b)}},a.fn.typeahead=function(b){var c;return f[b]&&"initialize"!==b?(c=this.filter(function(){return!!a(this).data(d)}),f[b].apply(c,[].slice.call(arguments,1))):f.initialize.apply(this,arguments)},a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this}}()}(window.jQuery); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/ui/public/logviewer_search.html ---------------------------------------------------------------------- diff --git a/storm-core/src/ui/public/logviewer_search.html b/storm-core/src/ui/public/logviewer_search.html new file mode 100644 index 0000000..670f3fb --- /dev/null +++ b/storm-core/src/ui/public/logviewer_search.html @@ -0,0 +1,65 @@ +<html><head> + <!-- + 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. + --> +<meta charset="UTF-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>Storm UI</title> +<link href="/css/bootstrap-3.3.1.min.css" rel="stylesheet" type="text/css"> +<link href="/css/jquery.dataTables.1.10.4.min.css" rel="stylesheet" type="text/css"> +<link href="/css/dataTables.bootstrap.css" rel="stylesheet" type="text/css"> +<link href="/css/style.css" rel="stylesheet" type="text/css"> +<script src="/js/jquery-1.11.1.min.js" type="text/javascript"></script> +<script src="/js/jquery.dataTables.1.10.4.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-3.3.1.min.js" type="text/javascript"></script> +<script src="/js/jquery.blockUI.min.js" type="text/javascript"></script> +<script src="/js/url.min.js" type="text/javascript"></script> +<script src="/js/dataTables.bootstrap.min.js" type="text/javascript"></script> +<script src="/js/script.js" type="text/javascript"></script> +</head> +<body> +<div class="container-fluid"> + <div class="row"> + <div id="search-form"></div> + </div> + <div class="row"> + <div id="result"></div> + </div> +</div> +</body> +<script> +$(document).ready(function() { + var file = $.url("?file"); + var search = $.url("?search"); + var offset = $.url("?offset") || 0; + file = decodeURIComponent(file); + search = decodeURIComponent(search); + + $.get("/templates/logviewer-search-page-template.html", function(template) { + $("#search-form").append(Mustache.render($(template).filter("#search-single-file").html(),{file: file, search: search})); + + var result = $("#result"); + var url = "/search/"+encodeURIComponent(file)+"?search-string="+search+"&start-byte-offset="+offset; + $.getJSON(url,function(response,status,jqXHR) { + response.file = file; + result.append(Mustache.render($(template).filter("#logviewer-search-result-template").html(),response)); + }); + }); + }); +</script> +</html> http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/ui/public/search_result.html ---------------------------------------------------------------------- diff --git a/storm-core/src/ui/public/search_result.html b/storm-core/src/ui/public/search_result.html new file mode 100644 index 0000000..ec44aa9 --- /dev/null +++ b/storm-core/src/ui/public/search_result.html @@ -0,0 +1,100 @@ +<html><head> + <!-- + 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. + --> +<meta charset="UTF-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>Storm UI</title> +<link href="/css/bootstrap-3.3.1.min.css" rel="stylesheet" type="text/css"> +<link href="/css/jquery.dataTables.1.10.4.min.css" rel="stylesheet" type="text/css"> +<link href="/css/dataTables.bootstrap.css" rel="stylesheet" type="text/css"> +<link href="/css/style.css" rel="stylesheet" type="text/css"> +<script src="/js/jquery-1.11.1.min.js" type="text/javascript"></script> +<script src="/js/jquery.dataTables.1.10.4.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-3.3.1.min.js" type="text/javascript"></script> +<script src="/js/jquery.blockUI.min.js" type="text/javascript"></script> +<script src="/js/url.min.js" type="text/javascript"></script> +<script src="/js/dataTables.bootstrap.min.js" type="text/javascript"></script> +<script src="/js/script.js" type="text/javascript"></script> +</head> +<body> +<div class="container-fluid"> + <div class="row"> + <div id="search-form"></div> + </div> + <div class="row"> + <div id="result"></div> + </div> +</div> +</body> +<script> +$(document).ready(function() { + var id = $.url("?id"); + var search = $.url("?search"); + var count = $.url("?count") || 2; + var searchArchived = $.url("?searchArchived") || ""; + + $.get("/templates/search-result-page-template.html", function(template) { + $("#search-form").append(Mustache.render($(template).filter("#search-form-template").html(),{id: id, search: search, count: count, searchArchived: searchArchived})); + + var result = $("#result"); + $.getJSON("/api/v1/topology-workers/"+id, function(response,status,jqXHR) { + for (var index in response.hostPortList) { + var host = response.hostPortList[index].host; + var port = response.hostPortList[index].port; + var elemId = "search-results-"+host.replace(/\./g,"-")+"-"+port; + response.hostPortList[index].elemId = elemId; + } + result.append(Mustache.render($(template).filter("#search-result-files-template").html(),response)); + + var logviewerPort = response.logviewerPort; + for (var index in response.hostPortList) { + var host = response.hostPortList[index].host; + var port = response.hostPortList[index].port; + var elemId = response.hostPortList[index].elemId; + var file = id+"/"+port+"/worker.log"; + var searchURL = "http://"+host+":"+logviewerPort+"/search/"+encodeURIComponent(file)+"?search-string="+search+"&num-matches="+count; + if (searchArchived != "") { + searchURL = "http://"+host+":"+logviewerPort+"/deepSearch/"+id+"?search-string="+search+"&num-matches="+count+"&search-archived=true&port="+port; + } + + $.ajax({dataType: "json", + url: searchURL, + xhrFields: { + withCredentials: true + }, + success: $.proxy(function(data,status,jqXHR) { + data.file = this.file; + data.host = this.host; + data.port = this.port; + data.id = id; + data.logviewerPort = logviewerPort; + var searchTemp = $(template).filter("#search-result-identified-template").html(); + if (searchArchived != "") { + searchTemp = $(template).filter("#deepsearch-result-identified-template").html(); + } + var rendered = Mustache.render(searchTemp, data); + $("#"+this.elemId).replaceWith(rendered); + }, {host: host, port: port, file: file, elemId: elemId}) + }); + } + }); + }); + }); +</script> +</html> http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/ui/public/templates/deep-search-result-page-template.html ---------------------------------------------------------------------- diff --git a/storm-core/src/ui/public/templates/deep-search-result-page-template.html b/storm-core/src/ui/public/templates/deep-search-result-page-template.html new file mode 100644 index 0000000..a658e5c --- /dev/null +++ b/storm-core/src/ui/public/templates/deep-search-result-page-template.html @@ -0,0 +1,66 @@ +<!-- + 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. +--> +<script id="search-result-files-template" type="text/html"> +<table id="search-result-table" class="table table-striped compact"> + <thead><tr><th>host:port</th><th>Match</th></tr></thead> + <tbody> + {{#supervisors}} + <tr id="{{elemId}}"> + <td>{{host}}</td> + <td>LOADING ...</td> + </tr> + {{/supervisors}} + </tbody> +</table> +</script> +<script id="search-result-identified-template" type="text/html"> + {{#matches}} + <tr> + <td><a href="http://{{host}}:{{logviewerPort}}/logviewer_search.html?file={{fileName}}&search={{searchString}}">{{host}}:{{port}}</a></td> + <td><pre>{{beforeString}}<b><a href="{{logviewerURL}}">{{matchString}}</a></b>{{afterString}}</pre></td> + </tr> + {{/matches}} +</script> +<script id="search-form-template" type="text/html"> + <div id="search-form-container" class="search-box"> + <form action="deep_search_result.html" id="search-box"> + <div class="row" data-toggle="tooltip" data-placement="bottom" title="The ID of the topology, can be a regex for search, i.e. '.' lists everything"> + <div class="col-md-2">Topology Id:</div> + <div class="col-md-10"> + <input class="expand-box" id="search-id" name="id" class="typeahead" type="text" placeholder="Topology-ID" value="{{id}}" number="50"> + </div> + </div> + <div class="row" data-toggle="tooltip" data-placement="bottom" title="Exact search string to look for (NOT A REGEX)"> + <div class="col-md-2">Search:</div> + <div class="col-md-10"> + <input class="expand-box" type="text" name="search" value="{{search}}" placeholder="Search" number="50"> + </div> + </div> + <div class="row" data-toggle="tooltip" data-placement="bottom" title="Search older logs that have rotated and may have been compressed. This could take much longer."> + <div class="col-md-2">Search archived logs:</div> + <div class="col-md-10"><input type="checkbox" name="search-archived" {{search_archived}}></div> + </div> + <div class="row"> + <div class="col-md-12"> + <input type="submit" value="Search"> + </td> + </div> + <input type="hidden" name="count" value="{{count}}"> + </form> + </div> +</script> + http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/ui/public/templates/logviewer-search-page-template.html ---------------------------------------------------------------------- diff --git a/storm-core/src/ui/public/templates/logviewer-search-page-template.html b/storm-core/src/ui/public/templates/logviewer-search-page-template.html new file mode 100644 index 0000000..9d208d3 --- /dev/null +++ b/storm-core/src/ui/public/templates/logviewer-search-page-template.html @@ -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. +--> +<script id="logviewer-search-result-template" type="text/html"> +{{#nextByteOffset}} +<a href="/logviewer_search.html?file={{file}}&search={{searchString}}&offset={{nextByteOffset}}" class="btn btn-default enabled">Next</a> +{{/nextByteOffset}} +<table id="search-result-table" class="table table-striped compact"> + <thead><tr><th>File offset</th><th>Match</th></tr></thead> + <tbody> + {{#matches}} + <tr> + <td>{{byteOffset}}</td> + <td><pre>{{beforeString}}<b><a href="{{logviewerURL}}">{{matchString}}</a></b>{{afterString}}</pre></td> + </tr> + {{/matches}} + </tbody> +</table> +{{#nextByteOffset}} +<a href="/logviewer_search.html?file={{file}}&search={{searchString}}&offset={{nextByteOffset}}" class="btn btn-default enabled">Next</a> +{{/nextByteOffset}} +</script> +<script id="search-single-file" type="text/html"> +<form action="logviewer_search.html" id="search-box"> + Search {{file}}: + <input type="text" name="search" value="{{search}}"> + <input type="hidden" name="file" value="{{file}}"> + <input type="submit" value="Search"> +</form> +</script> + http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/ui/public/templates/search-result-page-template.html ---------------------------------------------------------------------- diff --git a/storm-core/src/ui/public/templates/search-result-page-template.html b/storm-core/src/ui/public/templates/search-result-page-template.html new file mode 100644 index 0000000..742a643 --- /dev/null +++ b/storm-core/src/ui/public/templates/search-result-page-template.html @@ -0,0 +1,60 @@ +<!-- + 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. +--> +<script id="search-result-files-template" type="text/html"> +<table id="search-result-table" class="table table-striped compact"> + <thead><tr><th>host:port</th><th>Match</th></tr></thead> + <tbody> + {{#hostPortList}} + <tr id="{{elemId}}"> + <td>{{host}}:{{port}}</td> + <td>LOADING ...</td> + </tr> + {{/hostPortList}} + </tbody> +</table> +</script> +<script id="search-result-identified-template" type="text/html"> + {{#matches}} + <tr> + <td><a href="http://{{host}}:{{logviewerPort}}/logviewer_search.html?file={{file}}&search={{searchString}}">{{host}}:{{port}}</a></td> + <td><pre>{{beforeString}}<b><a href="{{logviewerURL}}">{{matchString}}</a></b>{{afterString}}</pre></td> + </tr> + {{/matches}} +</script> +<script id="deepsearch-result-identified-template" type="text/html"> + {{#matches}} + {{#matches}} + <tr> + <td><a href="http://{{host}}:{{logviewerPort}}/logviewer_search.html?file={{fileName}}&search={{searchString}}">{{host}}:{{port}}</a></td> + <td><pre>{{beforeString}}<b><a href="{{logviewerURL}}">{{matchString}}</a></b>{{afterString}}</pre></td> + </tr> + {{/matches}} + {{/matches}} +</script> +<script id="search-form-template" type="text/html"> + <div class="search-box"> + <form action="search_result.html" id="search-box"> + Search {{id}}: + <input type="text" name="search" value="{{search}}"> + <input type="hidden" name="id" value="{{id}}"> + <input type="hidden" name="count" value="{{count}}"> + <input type="submit" value="Search"> + Search Archived Logs: <input type="checkbox" name="searchArchived" value="checked" {{searchArchived}}> + </form> + </div> +</script> + http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/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 00e4fa2..0297839 100644 --- a/storm-core/src/ui/public/templates/topology-page-template.html +++ b/storm-core/src/ui/public/templates/topology-page-template.html @@ -435,6 +435,17 @@ <div id="change-log-level" style="display:none"></div> </script> +<script id="search-form-template" type="text/html"> + <form action="search_result.html" id="search-box"> + Search {{id}}: + <input type="text" name="search"> + <input type="hidden" name="id" value="{{id}}"> + <input type="hidden" name="count" value="1"> + <input type="submit" value="Search"> + Search Archived Logs: <input type="checkbox" name="searchArchived" value="checked"> + </form> +</script> + <script id="log-level-and-timeout" type="text/html" class="partials"> <tr id="logger-{{loggerId}}" class="{{cls}}"> {{#loggerName}} http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/storm-core/src/ui/public/templates/user-template.html ---------------------------------------------------------------------- diff --git a/storm-core/src/ui/public/templates/user-template.html b/storm-core/src/ui/public/templates/user-template.html index 4fa1338..e08896d 100644 --- a/storm-core/src/ui/public/templates/user-template.html +++ b/storm-core/src/ui/public/templates/user-template.html @@ -15,11 +15,14 @@ limitations under the License. --> <script id="user-template" type="text/html"> - {{#user}} - <div class="ui-user"><p> - <span data-toggle="tooltip" data-placement="below" data-original-title="This should be you."> - User: {{user}} - </span> - </p></div> - {{/user}} + <div class="ui-user"> + <span data-toggle="tooltip" data-placement="bottom" data-original-title="Search through all logs for any topology."> + <a href="/deep_search_result.html" target="_blank"><image src="/images/search.png" class="image_pre_format"/></a> + </span> + {{#user}} + <span data-toggle="tooltip" data-placement="bottom" data-original-title="This should be you."> + User: {{user}} + </span> + {{/user}} + </div> </script> http://git-wip-us.apache.org/repos/asf/storm/blob/22cf0acb/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 a0e359f..e2abab1 100644 --- a/storm-core/src/ui/public/topology.html +++ b/storm-core/src/ui/public/topology.html @@ -48,6 +48,10 @@ <div id="ui-user" class="col-md-1"></div> </div> <div class="row"> + <div class="col-md-12" id="search-form"> + </div> + </div> + <div class="row"> <div class="col-md-12"> <h2>Topology summary</h2> <div id="topology-summary"></div> @@ -278,13 +282,15 @@ $(document).ready(function() { var config = $("#topology-configuration"); var topologyActions = $("#topology-actions"); var topologyVisualization = $("#topology-visualization") + var searchForm = $("#search-form") var formattedConfig = formatConfigData(response["configuration"]); var buttonJsonData = topologyActionJson(response["id"],response["encodedId"],response["name"],response["status"] ,response["msgTimeout"],response["debug"],response["samplingPct"]); $.ajax ({url: "/templates/topology-page-template.html", success: function(template) { - toggleChangeLogLevel = function (data) { + toggleChangeLogLevel = function (data) { renderLogLevelForm (template, data); } + searchForm.append(Mustache.render($(template).filter("#search-form-template").html(),{id: topologyId})); topologySummary.append(Mustache.render($(template).filter("#topology-summary-template").html(),response)); topologyResources.append(Mustache.render($(template).filter("#topology-resources-template").html(),response)); topologyActions.append(Mustache.render($(template).filter("#topology-actions-template").html(),buttonJsonData));
