norikra 0.0.21-java → 0.0.22-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|