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.
@@ -44,7 +44,7 @@ module Norikra
44
44
  def statistics
45
45
  s = @statistics
46
46
  {
47
- started: s[:started].httpdate,
47
+ started: s[:started].rfc2822,
48
48
  uptime: self.uptime,
49
49
  memory: self.memory_statistics,
50
50
  input_events: s[:events][:input],
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Norikra
2
- VERSION = "0.0.21"
2
+ VERSION = "0.0.22"
3
3
  end
@@ -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
- # set :erb, :escape_html => true # hmmm, this doesn't works...
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
- e11 = 'select campaign.id as campaign_id, member.region as region, member.lang as lang, count(*) as click, count(distinct member.id) as uu from applog_linereward.win:time_batch(1 minutes) where type = "click" group by campaign.id, member.region, member.lang'
362
- x11 = 'select 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 campaign$id, member$region, member$lang'
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 = {'applog_linereward' => 'A1'}
365
+ mapping = {'applog' => 'A1'}
365
366
  expect(Norikra::Query.rewrite_query(model, mapping).toEPL).to eql(x11)
366
367
 
367
- e11 = 'select campaign.id, member.region as region, member.lang as lang, count(*) as click, count(distinct member.id) as uu from applog_linereward.win:time_batch(1 minutes) where type = "click" group by campaign.id, member.region, member.lang order by campaign.id'
368
- x11 = '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'
369
- model = administrator.compileEPL(e11)
370
- mapping = {'applog_linereward' => 'A1'}
371
- expect(Norikra::Query.rewrite_query(model, mapping).toEPL).to eql(x11)
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
- <%= yield %>
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
- <a class="btn btn-danger btn-xs" data-toggle="modal" href="#removeQuery<%= query.name %>"><span class="glyphicon glyphicon-trash"></span></a>
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
- <!-- TODO: toggle button this "Add Query", and opened with input_data[:query_add] -->
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
- <% field_html = target[:fields].map{|t| "<tr><td>#{t[:name]}</td><td>#{t[:type]}</td><td>#{t[:optional] ? '(optional)' : ''}</td></tr>"}.join %>
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.21
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-25 00:00:00.000000000 Z
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: sinatra
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: thor
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: norikra-client-jruby
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.0.7
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.0.7
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