norikra 0.0.21-java → 0.0.22-java
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/norikra/engine.rb +1 -1
- data/lib/norikra/output_pool.rb +8 -0
- data/lib/norikra/query.rb +6 -3
- data/lib/norikra/version.rb +1 -1
- data/lib/norikra/webui/handler.rb +52 -1
- data/norikra.gemspec +4 -2
- data/public/js/norikra.webui.js +74 -0
- data/spec/query_spec.rb +17 -8
- data/views/base.erb +2 -7
- data/views/index.erb +19 -15
- metadata +40 -7
data/lib/norikra/engine.rb
CHANGED
data/lib/norikra/output_pool.rb
CHANGED
@@ -30,6 +30,14 @@ module Norikra
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
# returns [[time, event], ...], but not remove from pool
|
34
|
+
def fetch(query_name)
|
35
|
+
events = @mutex.synchronize do
|
36
|
+
@pool.fetch(query_name, [])
|
37
|
+
end
|
38
|
+
events.reduce(&:+) || []
|
39
|
+
end
|
40
|
+
|
33
41
|
# returns [[time(int from epoch), event], ...], event: hash
|
34
42
|
def pop(query_name)
|
35
43
|
events = @mutex.synchronize do
|
data/lib/norikra/query.rb
CHANGED
@@ -264,6 +264,7 @@ module Norikra
|
|
264
264
|
traverse_fields(rewriter, recaller, statement_model)
|
265
265
|
end
|
266
266
|
|
267
|
+
### Targets and fields re-writing supports (*) nodes
|
267
268
|
# model.methods.select{|m| m.to_s.start_with?('get')}
|
268
269
|
# :getContextName,
|
269
270
|
# :getCreateContext,
|
@@ -278,7 +279,7 @@ module Norikra
|
|
278
279
|
# :getForClause,
|
279
280
|
# (*) :getFromClause,
|
280
281
|
# (*) :getGroupByClause,
|
281
|
-
# :getHavingClause,
|
282
|
+
# (*) :getHavingClause,
|
282
283
|
# :getInsertInto,
|
283
284
|
# :getMatchRecognizeClause,
|
284
285
|
# :getOnExpr,
|
@@ -293,8 +294,6 @@ module Norikra
|
|
293
294
|
|
294
295
|
def self.traverse_fields(rewriter, recaller, statement_model)
|
295
296
|
#NOTICE: SQLStream is not supported yet.
|
296
|
-
#TODO: other clauses with fields, especially: Having, For
|
297
|
-
|
298
297
|
dig = lambda {|node|
|
299
298
|
rewriter.call(node)
|
300
299
|
|
@@ -368,6 +367,10 @@ module Norikra
|
|
368
367
|
end
|
369
368
|
end
|
370
369
|
|
370
|
+
if statement_model.getHavingClause
|
371
|
+
dig.call(statement_model.getHavingClause)
|
372
|
+
end
|
373
|
+
|
371
374
|
statement_model
|
372
375
|
end
|
373
376
|
end
|
data/lib/norikra/version.rb
CHANGED
@@ -5,11 +5,13 @@ require 'norikra/logger'
|
|
5
5
|
require 'norikra/webui'
|
6
6
|
|
7
7
|
require 'sinatra/base'
|
8
|
+
require 'sinatra/json'
|
9
|
+
require 'erubis'
|
8
10
|
|
9
11
|
class Norikra::WebUI::Handler < Sinatra::Base
|
10
12
|
set :public_folder, File.absolute_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'public'))
|
11
13
|
set :views, File.absolute_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'views'))
|
12
|
-
|
14
|
+
set :erb, :escape_html => true
|
13
15
|
|
14
16
|
enable :sessions
|
15
17
|
|
@@ -111,4 +113,53 @@ class Norikra::WebUI::Handler < Sinatra::Base
|
|
111
113
|
end
|
112
114
|
end
|
113
115
|
|
116
|
+
get '/json/query/:name' do
|
117
|
+
query_name = params[:name]
|
118
|
+
logging(:show, :json_query, [query_name]) do
|
119
|
+
query = engine.queries.select{|q| q.name == query_name}.first
|
120
|
+
if query
|
121
|
+
content = {
|
122
|
+
name: query.name,
|
123
|
+
group: query.group || "(default)",
|
124
|
+
targets: query.targets,
|
125
|
+
expression: query.expression,
|
126
|
+
events: engine.output_pool.fetch(query.name).size
|
127
|
+
}
|
128
|
+
json content
|
129
|
+
else
|
130
|
+
halt 404
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
get '/json/events_sample/:query_name' do
|
136
|
+
query_name = params[:query_name]
|
137
|
+
logging(:show, :json_query, [query_name]) do
|
138
|
+
query = engine.queries.select{|q| q.name == query_name}.first
|
139
|
+
if query
|
140
|
+
events = engine.output_pool.fetch(query.name).last(5)
|
141
|
+
json events
|
142
|
+
else
|
143
|
+
halt 404
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
get '/json/target/:name' do
|
149
|
+
target_name = params[:name]
|
150
|
+
logging(:show, :json_target, [target_name]) do
|
151
|
+
target = engine.targets.select{|t| t.name == target_name}.first
|
152
|
+
if target
|
153
|
+
content = {
|
154
|
+
name: target.name,
|
155
|
+
auto_field: target.auto_field,
|
156
|
+
fields: engine.typedef_manager.field_list(target.name)
|
157
|
+
}
|
158
|
+
json content
|
159
|
+
else
|
160
|
+
halt 404
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
114
165
|
end
|
data/norikra.gemspec
CHANGED
@@ -21,10 +21,12 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_runtime_dependency "mizuno", "~> 0.6"
|
23
23
|
spec.add_runtime_dependency "rack"
|
24
|
-
spec.add_runtime_dependency "sinatra"
|
25
|
-
spec.add_runtime_dependency "msgpack-rpc-over-http-jruby", ">= 0.0.5"
|
26
24
|
spec.add_runtime_dependency "thor"
|
25
|
+
spec.add_runtime_dependency "msgpack-rpc-over-http-jruby", ">= 0.0.5"
|
27
26
|
spec.add_runtime_dependency "norikra-client-jruby", ">= 0.0.7"
|
27
|
+
spec.add_runtime_dependency "sinatra"
|
28
|
+
spec.add_runtime_dependency "sinatra-contrib"
|
29
|
+
spec.add_runtime_dependency "erubis"
|
28
30
|
|
29
31
|
spec.add_development_dependency "bundler", "~> 1.3"
|
30
32
|
spec.add_development_dependency "rake"
|
@@ -0,0 +1,74 @@
|
|
1
|
+
$(function(){
|
2
|
+
|
3
|
+
$('.show-query-expression').each(function(i,e){
|
4
|
+
$(this).bind('click', function(e){
|
5
|
+
var button = $(this);
|
6
|
+
if (! button.data('loaded')) {
|
7
|
+
$.get(button.data('load'), function(data){
|
8
|
+
button.attr('data-loaded', 'true');
|
9
|
+
button.popover({
|
10
|
+
placement: 'left',
|
11
|
+
html: true,
|
12
|
+
title: 'name:' + data.name + ', group:' + data.group,
|
13
|
+
content: '<pre class="query-expression" style="border: none; width: 100%;">' + data.expression + '</pre>'
|
14
|
+
}).popover('toggle');
|
15
|
+
$('pre.query-expression').closest('div').css('padding', '0');
|
16
|
+
});
|
17
|
+
e.preventDefault();
|
18
|
+
}
|
19
|
+
});
|
20
|
+
});
|
21
|
+
|
22
|
+
$('.show-query-events-sample').each(function(i,e){
|
23
|
+
$(this).bind('click', function(e){
|
24
|
+
var button = $(this);
|
25
|
+
if (! button.data('loaded')) {
|
26
|
+
$.get(button.data('load'), function(data){
|
27
|
+
var events_texts = data.map(function(d){ return JSON.stringify(d); }).join("\n");
|
28
|
+
button.attr('data-loaded', 'true');
|
29
|
+
button.popover({
|
30
|
+
placement: 'left',
|
31
|
+
html: true,
|
32
|
+
title: 'Events sample',
|
33
|
+
content: '<pre class="query-events-sample" style="border: none; width: 100%;">' + events_texts + '</pre>'
|
34
|
+
}).popover('toggle');
|
35
|
+
$('pre.query-events-sample').closest('div').css('padding', '0');
|
36
|
+
});
|
37
|
+
e.preventDefault();
|
38
|
+
}
|
39
|
+
});
|
40
|
+
});
|
41
|
+
|
42
|
+
$('.show-target-fields').each(function(i,e){
|
43
|
+
$(this).bind('click', function(e){
|
44
|
+
var button = $(this);
|
45
|
+
if (! button.data('loaded')) {
|
46
|
+
$.get(button.data('load'), function(data){
|
47
|
+
var field_rows_html = data.fields.sort(function(a,b){
|
48
|
+
if (a.name > b.name) return 1;
|
49
|
+
if (a.name < b.name) return -1;
|
50
|
+
return 0;
|
51
|
+
}).map(function(t){
|
52
|
+
return '<tr style="border:none;"><td>' + t.name
|
53
|
+
+ '</td><td>' + t.type + '</td><td>' + (t.optional ? '(optional)' : '') + '</td></tr>';
|
54
|
+
}).join('');
|
55
|
+
var table_html = '<table class="target-fields" style="border: 0; width: 100%;">'
|
56
|
+
+ '<tr><th>field</th><th>type</th><th></th></tr>'
|
57
|
+
+ field_rows_html
|
58
|
+
+ '</table>';
|
59
|
+
button.attr('data-loaded', 'true');
|
60
|
+
button.popover({
|
61
|
+
placement: 'top',
|
62
|
+
html: true,
|
63
|
+
content: table_html
|
64
|
+
}).popover('toggle');
|
65
|
+
$('table.target-fields').closest('div').css('padding', '0');
|
66
|
+
});
|
67
|
+
e.preventDefault();
|
68
|
+
}
|
69
|
+
});
|
70
|
+
});
|
71
|
+
|
72
|
+
$('#query_add_editor_toggle').click(function(e){ $('#query_add_editor').toggle(); });
|
73
|
+
});
|
74
|
+
|
data/spec/query_spec.rb
CHANGED
@@ -358,17 +358,26 @@ describe Norikra::Query do
|
|
358
358
|
mapping = {'StreamA' => 'S1', 'StreamB' => 'S2'}
|
359
359
|
expect(Norikra::Query.rewrite_query(model, mapping).toEPL).to eql(x10)
|
360
360
|
|
361
|
-
|
362
|
-
|
361
|
+
# GROUP BY clause
|
362
|
+
e11 = 'select applog.campaign.id as campaign_id, member.region as region, member.lang as lang, count(*) as click, count(distinct member.id) as uu from applog.win:time_batch(1 minutes) where type = "click" group by applog.campaign.id, member.region, member.lang'
|
363
|
+
x11 = 'select A1.campaign$id as campaign_id, member$region as region, member$lang as lang, count(*) as click, count(distinct member$id) as uu from A1.win:time_batch(1 minutes) where type = "click" group by A1.campaign$id, member$region, member$lang'
|
363
364
|
model = administrator.compileEPL(e11)
|
364
|
-
mapping = {'
|
365
|
+
mapping = {'applog' => 'A1'}
|
365
366
|
expect(Norikra::Query.rewrite_query(model, mapping).toEPL).to eql(x11)
|
366
367
|
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
368
|
+
# ORDER BY clause
|
369
|
+
e12 = 'select campaign.id, member.region as region, member.lang as lang, count(*) as click, count(distinct member.id) as uu from applog.win:time_batch(1 minutes) where type = "click" group by campaign.id, member.region, member.lang order by campaign.id'
|
370
|
+
x12 = 'select campaign$id, member$region as region, member$lang as lang, count(*) as click, count(distinct member$id) as uu from A1.win:time_batch(1 minutes) where type = "click" group by campaign$id, member$region, member$lang order by campaign$id'
|
371
|
+
model = administrator.compileEPL(e12)
|
372
|
+
mapping = {'applog' => 'A1'}
|
373
|
+
expect(Norikra::Query.rewrite_query(model, mapping).toEPL).to eql(x12)
|
374
|
+
|
375
|
+
# HAVING clause
|
376
|
+
e13 = 'select path, max(response.duration) from logs.win:time_batch(10 seconds) where path.startsWith("/api/") group by path having max(response.duration) >= 100'
|
377
|
+
x13 = 'select path, max(response$duration) from L111.win:time_batch(10 seconds) where path.startsWith("/api/") group by path having max(response$duration) >= 100'
|
378
|
+
model = administrator.compileEPL(e13)
|
379
|
+
mapping = {'logs' => 'L111'}
|
380
|
+
expect(Norikra::Query.rewrite_query(model, mapping).toEPL).to eql(x13)
|
372
381
|
end
|
373
382
|
end
|
374
383
|
end
|
data/views/base.erb
CHANGED
@@ -52,7 +52,7 @@
|
|
52
52
|
</div>
|
53
53
|
|
54
54
|
<div class="container theme-showcase">
|
55
|
-
|
55
|
+
<%== yield %>
|
56
56
|
</div> <!-- /container -->
|
57
57
|
|
58
58
|
<!-- Bootstrap core JavaScript
|
@@ -61,12 +61,7 @@
|
|
61
61
|
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
62
62
|
<script src="//code.jquery.com/jquery.js"></script>
|
63
63
|
<script src="/js/bootstrap.min.js"></script>
|
64
|
-
<script>
|
65
|
-
$(function(){
|
66
|
-
$('.show-query-expression').each(function(i){ console.log(this); $(this).popover() });
|
67
|
-
$('.show-target-fields').each(function(i){ console.log(this); $(this).popover() });
|
68
|
-
})
|
69
|
-
</script>
|
64
|
+
<script src="/js/norikra.webui.js"></script>
|
70
65
|
</body>
|
71
66
|
</html>
|
72
67
|
|
data/views/index.erb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
<div class="page-header">
|
2
2
|
<h1 id="summary">Runtime Summary</h1>
|
3
|
+
at: <%= Time.now.rfc2822 %>
|
3
4
|
</div>
|
4
5
|
|
5
6
|
<% [["HEAP", :heap],["NON-HEAP", :nonheap]].each do |name,sym| %>
|
@@ -64,20 +65,27 @@
|
|
64
65
|
|
65
66
|
<% if queries.size > 0 %>
|
66
67
|
<table class="table">
|
67
|
-
<tr><th>Group</th><th>Query name</th><th>Targets</th><th>Query</th><th>Events</th><th></th></tr>
|
68
|
+
<tr><th>Group</th><th>Query name</th><th>Targets</th><th>Query</th><th style="text-align:right;">Events</th><th></th><th></th></tr>
|
68
69
|
<% queries.each do |query| %>
|
69
70
|
<tr>
|
70
71
|
<td><%= query.group || "(default)" %></td>
|
71
72
|
<td><%= query.name %></td>
|
72
73
|
<td><%= query.targets.join(", ") %></td>
|
73
74
|
<td>
|
74
|
-
<button class="btn btn-default btn-xs show-query-expression"
|
75
|
-
data-toggle="popover" data-placement="left" data-html="true"
|
76
|
-
data-content="query:<pre><%= escape_html query.expression %></pre>">show query</button>
|
75
|
+
<button class="btn btn-default btn-xs show-query-expression" data-load="/json/query/<%= query.name %>">show query</button>
|
77
76
|
</td>
|
78
|
-
<td><%= pool[query.name] %></td>
|
77
|
+
<td style="text-align: right;"><%= pool[query.name] %></td>
|
79
78
|
<td>
|
80
|
-
|
79
|
+
<% if pool[query.name].to_i > 0 %>
|
80
|
+
<button class="btn btn-info btn-xs show-query-events-sample" data-load="/json/events_sample/<%= query.name %>">
|
81
|
+
<span class="glyphicon glyphicon-search"></span>
|
82
|
+
</button>
|
83
|
+
<% end %>
|
84
|
+
</td>
|
85
|
+
<td>
|
86
|
+
<a class="btn btn-danger btn-xs" data-toggle="modal" href="#removeQuery<%= query.name %>">
|
87
|
+
<span class="glyphicon glyphicon-trash"></span>
|
88
|
+
</a>
|
81
89
|
<div class="modal fade"
|
82
90
|
id="removeQuery<%= query.name %>"
|
83
91
|
tabindex="-1" role="dialog" aria-labelledby="removeQueryLabel<%= query.name %>" aria-hidden="true">
|
@@ -109,10 +117,9 @@
|
|
109
117
|
<p>No queries found.</p>
|
110
118
|
<% end %>
|
111
119
|
|
112
|
-
<h3 id="query_add">Add Query</h3>
|
113
|
-
|
114
|
-
<div class="well">
|
115
|
-
<% input_data ||= {}; input_data[:query_add] ||= {} %>
|
120
|
+
<h3 id="query_add">Add Query <button class="btn btn-warning btn-xs" id="query_add_editor_toggle">editor</button></h3>
|
121
|
+
<% input_data ||= {}; input_data[:query_add] ||= {} %>
|
122
|
+
<div id="query_add_editor" class="well" style="display: <%= input_data[:query_add].empty? ? "none" : "block" %>;">
|
116
123
|
<% if input_data[:query_add][:error] %>
|
117
124
|
<div class="alert alert-danger"><%= input_data[:query_add][:error] %></div>
|
118
125
|
<% end %>
|
@@ -151,15 +158,12 @@
|
|
151
158
|
<td><%= target[:auto_field] %></td>
|
152
159
|
<td>
|
153
160
|
<% if target[:fields].size > 0 %>
|
154
|
-
|
155
|
-
<button class="btn btn-default btn-xs show-target-fields"
|
156
|
-
data-toggle="popover" data-placement="top" data-html="true"
|
157
|
-
data-content="<table><tr><th>name</th><th>type</th><th></th></tr><%= field_html %></table>">show fields</button>
|
161
|
+
<button class="btn btn-default btn-xs show-target-fields" data-load="/json/target/<%= target[:name] %>">show fields</button>
|
158
162
|
<% else %>
|
159
163
|
(lazy target)
|
160
164
|
<% end %>
|
161
165
|
</td>
|
162
|
-
<td>TODO: reserve fields, remove targets</td>
|
166
|
+
<td style="font-size: small; color: #c0c0c0;">TODO: change auto_fields, reserve fields, remove targets</td>
|
163
167
|
</tr>
|
164
168
|
<% end %>
|
165
169
|
</table>
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: norikra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.22
|
6
6
|
platform: java
|
7
7
|
authors:
|
8
8
|
- TAGOMORI Satoshi
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-10-
|
12
|
+
date: 2013-10-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mizuno
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
prerelease: false
|
45
45
|
type: :runtime
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: thor
|
48
48
|
version_requirements: !ruby/object:Gem::Requirement
|
49
49
|
requirements:
|
50
50
|
- - '>='
|
@@ -76,7 +76,23 @@ dependencies:
|
|
76
76
|
prerelease: false
|
77
77
|
type: :runtime
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
79
|
+
name: norikra-client-jruby
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 0.0.7
|
85
|
+
none: false
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 0.0.7
|
91
|
+
none: false
|
92
|
+
prerelease: false
|
93
|
+
type: :runtime
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: sinatra
|
80
96
|
version_requirements: !ruby/object:Gem::Requirement
|
81
97
|
requirements:
|
82
98
|
- - '>='
|
@@ -92,18 +108,34 @@ dependencies:
|
|
92
108
|
prerelease: false
|
93
109
|
type: :runtime
|
94
110
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
111
|
+
name: sinatra-contrib
|
96
112
|
version_requirements: !ruby/object:Gem::Requirement
|
97
113
|
requirements:
|
98
114
|
- - '>='
|
99
115
|
- !ruby/object:Gem::Version
|
100
|
-
version: 0
|
116
|
+
version: '0'
|
101
117
|
none: false
|
102
118
|
requirement: !ruby/object:Gem::Requirement
|
103
119
|
requirements:
|
104
120
|
- - '>='
|
105
121
|
- !ruby/object:Gem::Version
|
106
|
-
version: 0
|
122
|
+
version: '0'
|
123
|
+
none: false
|
124
|
+
prerelease: false
|
125
|
+
type: :runtime
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: erubis
|
128
|
+
version_requirements: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
none: false
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
107
139
|
none: false
|
108
140
|
prerelease: false
|
109
141
|
type: :runtime
|
@@ -313,6 +345,7 @@ files:
|
|
313
345
|
- public/fonts/glyphicons-halflings-regular.woff
|
314
346
|
- public/js/bootstrap.js
|
315
347
|
- public/js/bootstrap.min.js
|
348
|
+
- public/js/norikra.webui.js
|
316
349
|
- script/spec_server_pry
|
317
350
|
- spec/field_spec.rb
|
318
351
|
- spec/fieldset_spec.rb
|