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.
@@ -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