appstats 0.13.4 → 0.14.0
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/Gemfile.lock +1 -1
- data/db/migrations/20110301170733_add_appstats_results_group_query_to_sql.rb +9 -0
- data/db/migrations/20110301170947_create_appstats_sub_results.rb +19 -0
- data/db/schema.rb +13 -1
- data/lib/appstats.rb +1 -0
- data/lib/appstats/query.rb +32 -2
- data/lib/appstats/result.rb +1 -0
- data/lib/appstats/sub_result.rb +26 -0
- data/lib/appstats/version.rb +1 -1
- data/spec/entry_spec.rb +8 -8
- data/spec/logger_spec.rb +22 -22
- data/spec/query_spec.rb +167 -78
- data/spec/result_spec.rb +24 -0
- data/spec/sub_result_spec.rb +85 -0
- metadata +10 -5
data/Gemfile.lock
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateAppstatsSubResults < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :appstats_sub_results do |t|
|
4
|
+
t.integer :appstats_result_id
|
5
|
+
t.string :context_filter
|
6
|
+
t.integer :count
|
7
|
+
t.float :ratio_of_total
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :appstats_sub_results, :context_filter
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.down
|
15
|
+
remove_index :appstats_sub_results, :context_filter
|
16
|
+
|
17
|
+
drop_table :appstats_sub_results
|
18
|
+
end
|
19
|
+
end
|
data/db/schema.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended to check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema.define(:version =>
|
13
|
+
ActiveRecord::Schema.define(:version => 20110301170947) do
|
14
14
|
|
15
15
|
create_table "appstats_actions", :force => true do |t|
|
16
16
|
t.string "name"
|
@@ -118,6 +118,7 @@ ActiveRecord::Schema.define(:version => 20110225192624) do
|
|
118
118
|
t.datetime "created_at"
|
119
119
|
t.datetime "updated_at"
|
120
120
|
t.text "contexts"
|
121
|
+
t.text "group_query_to_sql"
|
121
122
|
end
|
122
123
|
|
123
124
|
add_index "appstats_results", ["action"], :name => "index_appstats_results_on_action"
|
@@ -125,6 +126,17 @@ ActiveRecord::Schema.define(:version => 20110225192624) do
|
|
125
126
|
add_index "appstats_results", ["name"], :name => "index_appstats_results_on_name"
|
126
127
|
add_index "appstats_results", ["page"], :name => "index_appstats_results_on_page"
|
127
128
|
|
129
|
+
create_table "appstats_sub_results", :force => true do |t|
|
130
|
+
t.integer "appstats_result_id"
|
131
|
+
t.string "context_filter"
|
132
|
+
t.integer "count"
|
133
|
+
t.float "ratio_of_total"
|
134
|
+
t.datetime "created_at"
|
135
|
+
t.datetime "updated_at"
|
136
|
+
end
|
137
|
+
|
138
|
+
add_index "appstats_sub_results", ["context_filter"], :name => "index_appstats_sub_results_on_context_filter"
|
139
|
+
|
128
140
|
create_table "appstats_test_objects", :force => true do |t|
|
129
141
|
t.string "name"
|
130
142
|
t.datetime "created_at"
|
data/lib/appstats.rb
CHANGED
@@ -13,6 +13,7 @@ require "#{File.dirname(__FILE__)}/appstats/log_collector"
|
|
13
13
|
require "#{File.dirname(__FILE__)}/appstats/parser"
|
14
14
|
require "#{File.dirname(__FILE__)}/appstats/query"
|
15
15
|
require "#{File.dirname(__FILE__)}/appstats/result"
|
16
|
+
require "#{File.dirname(__FILE__)}/appstats/sub_result"
|
16
17
|
require "#{File.dirname(__FILE__)}/appstats/result_job"
|
17
18
|
require "#{File.dirname(__FILE__)}/appstats/host"
|
18
19
|
require "#{File.dirname(__FILE__)}/appstats/context_key"
|
data/lib/appstats/query.rb
CHANGED
@@ -2,12 +2,13 @@
|
|
2
2
|
module Appstats
|
3
3
|
class Query
|
4
4
|
|
5
|
-
@@parser_template = Appstats::Parser.new(:rules => ":operation :action :date on :host where :contexts")
|
5
|
+
@@parser_template = Appstats::Parser.new(:rules => ":operation :action :date on :host where :contexts group by :groups")
|
6
6
|
@@contexts_parser_template = Appstats::Parser.new(:rules => ":context", :repeating => true, :tokenize => "and or || && = <= >= <> != ( ) like")
|
7
|
+
@@groups_parser_template = Appstats::Parser.new(:rules => ":filter", :repeating => true, :tokenize => ",")
|
7
8
|
|
8
9
|
@@nill_query = "select 0 from appstats_entries LIMIT 1"
|
9
10
|
@@default = "1=1"
|
10
|
-
attr_accessor :name, :query, :action, :host, :date_range, :query_to_sql, :contexts
|
11
|
+
attr_accessor :name, :query, :action, :host, :date_range, :query_to_sql, :contexts, :groups, :group_query_to_sql
|
11
12
|
|
12
13
|
def initialize(data = {})
|
13
14
|
@name = data[:name]
|
@@ -24,6 +25,17 @@ module Appstats
|
|
24
25
|
result = Appstats::Result.new(:name => @name, :result_type => @result_type, :query => @query, :query_as_sql => @query_to_sql, :action => @action, :host => @host, :from_date => @date_range.from_date, :to_date => @date_range.to_date, :contexts => @contexts)
|
25
26
|
result.count = ActiveRecord::Base.connection.select_one(@query_to_sql)["count(*)"].to_i
|
26
27
|
result.save
|
28
|
+
|
29
|
+
unless @groups.empty?
|
30
|
+
all_sub_results = ActiveRecord::Base.connection.select_all(@group_query_to_sql)
|
31
|
+
all_sub_results.each do |data|
|
32
|
+
ratio_of_total = data["num"].to_f / result.count
|
33
|
+
sub_result = Appstats::SubResult.new(:context_filter => data["context_filter"], :count => data["num"], :ratio_of_total => ratio_of_total)
|
34
|
+
sub_result.result = result
|
35
|
+
sub_result.save
|
36
|
+
end
|
37
|
+
end
|
38
|
+
result.reload
|
27
39
|
result
|
28
40
|
end
|
29
41
|
|
@@ -101,6 +113,15 @@ module Appstats
|
|
101
113
|
action.nil? ? action_name : action.name
|
102
114
|
end
|
103
115
|
|
116
|
+
def parse_groups(raw_input)
|
117
|
+
group_parser = @@groups_parser_template.dup
|
118
|
+
return if (raw_input.blank? || !group_parser.parse(raw_input))
|
119
|
+
group_parser.raw_results.each do |entry|
|
120
|
+
next if entry.kind_of?(String)
|
121
|
+
@groups<< entry[:filter]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
104
125
|
def parse_query
|
105
126
|
reset_query
|
106
127
|
return nil_query if @query.nil?
|
@@ -114,6 +135,7 @@ module Appstats
|
|
114
135
|
@date_range = DateRange.parse(parser.results[:date])
|
115
136
|
@host = parser.results[:host]
|
116
137
|
@contexts = parser.results[:contexts]
|
138
|
+
parse_groups(parser.results[:groups])
|
117
139
|
|
118
140
|
if @operation == "#"
|
119
141
|
@query_to_sql = "select count(*) from appstats_entries"
|
@@ -123,6 +145,12 @@ module Appstats
|
|
123
145
|
@query_to_sql += " and #{Query.contexts_filter_to_sql(@contexts)}" unless @contexts.nil?
|
124
146
|
end
|
125
147
|
|
148
|
+
unless @groups.empty?
|
149
|
+
query_to_sql_with_id = @query_to_sql.sub("count(*)","id")
|
150
|
+
group_as_sql = @groups.collect { |g| "'#{Query.sqlclean(g)}'" }.join(',')
|
151
|
+
@group_query_to_sql = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in (#{group_as_sql}) and appstats_entry_id in ( #{query_to_sql_with_id} ) group by appstats_entry_id) results group by context_filter;"
|
152
|
+
end
|
153
|
+
|
126
154
|
@query_to_sql
|
127
155
|
end
|
128
156
|
|
@@ -138,6 +166,7 @@ module Appstats
|
|
138
166
|
def nil_query
|
139
167
|
@query_to_sql = @@nill_query
|
140
168
|
@query_to_sql
|
169
|
+
@group_query_to_sql = nil
|
141
170
|
end
|
142
171
|
|
143
172
|
def reset_query
|
@@ -145,6 +174,7 @@ module Appstats
|
|
145
174
|
@host = nil
|
146
175
|
nil_query
|
147
176
|
@date_range = DateRange.new
|
177
|
+
@groups = []
|
148
178
|
end
|
149
179
|
|
150
180
|
end
|
data/lib/appstats/result.rb
CHANGED
@@ -3,6 +3,7 @@ module Appstats
|
|
3
3
|
set_table_name "appstats_results"
|
4
4
|
|
5
5
|
attr_accessible :name, :result_type, :query, :query_as_sql, :count, :action, :host, :from_date, :to_date, :contexts
|
6
|
+
has_many :sub_results, :table_name => 'appstats_subresults', :foreign_key => 'appstats_result_id', :order => 'count DESC'
|
6
7
|
|
7
8
|
def date_to_s
|
8
9
|
return "" if from_date.nil? && to_date.nil?
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Appstats
|
2
|
+
class SubResult < ActiveRecord::Base
|
3
|
+
set_table_name "appstats_sub_results"
|
4
|
+
|
5
|
+
attr_accessible :context_filter, :count, :ratio_of_total
|
6
|
+
belongs_to :result, :foreign_key => "appstats_result_id"
|
7
|
+
|
8
|
+
def total_count
|
9
|
+
return 0 if result.nil?
|
10
|
+
result.count
|
11
|
+
end
|
12
|
+
|
13
|
+
def ==(o)
|
14
|
+
o.class == self.class && o.send(:state) == state
|
15
|
+
end
|
16
|
+
alias_method :eql?, :==
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def state
|
21
|
+
[context_filter, count, ratio_of_total]
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/appstats/version.rb
CHANGED
data/spec/entry_spec.rb
CHANGED
@@ -193,18 +193,18 @@ module Appstats
|
|
193
193
|
end
|
194
194
|
|
195
195
|
it "should understand an entry without contexts" do
|
196
|
-
entry = Entry.create_from_logger_string("0.
|
196
|
+
entry = Entry.create_from_logger_string("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
|
197
197
|
Entry.count.should == @before_count + 1
|
198
198
|
entry.action.should == "address_search"
|
199
|
-
entry.raw_entry.should == "0.
|
199
|
+
entry.raw_entry.should == "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
|
200
200
|
entry.occurred_at.should == Time.parse("2010-09-21 23:15:20")
|
201
201
|
end
|
202
202
|
|
203
203
|
it "should understand contexts" do
|
204
|
-
entry = Entry.create_from_logger_string("0.
|
204
|
+
entry = Entry.create_from_logger_string("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
|
205
205
|
Entry.count.should == @before_count + 1
|
206
206
|
entry.action.should == "address_filter"
|
207
|
-
entry.raw_entry.should == "0.
|
207
|
+
entry.raw_entry.should == "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
|
208
208
|
entry.occurred_at.should == Time.parse("2010-09-21 23:15:20")
|
209
209
|
entry.contexts.size.should == 2
|
210
210
|
entry.contexts[0].context_key = "app_name"
|
@@ -214,10 +214,10 @@ module Appstats
|
|
214
214
|
end
|
215
215
|
|
216
216
|
it "should handle 'action' as a context" do
|
217
|
-
entry = Entry.create_from_logger_string('0.
|
217
|
+
entry = Entry.create_from_logger_string('0.14.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb')
|
218
218
|
Entry.count.should == @before_count + 1
|
219
219
|
entry.action.should == "page-view"
|
220
|
-
entry.raw_entry.should == "0.
|
220
|
+
entry.raw_entry.should == "0.14.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb"
|
221
221
|
entry.occurred_at.should == Time.parse("2011-02-24 12:59:57")
|
222
222
|
entry.contexts.size.should == 2
|
223
223
|
entry.contexts[0].context_key = "action"
|
@@ -228,10 +228,10 @@ module Appstats
|
|
228
228
|
end
|
229
229
|
|
230
230
|
it "should handle multiple of the same 'context'" do
|
231
|
-
entry = Entry.create_from_logger_string('0.
|
231
|
+
entry = Entry.create_from_logger_string('0.14.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb')
|
232
232
|
Entry.count.should == @before_count + 1
|
233
233
|
entry.action.should == "page-view"
|
234
|
-
entry.raw_entry.should == "0.
|
234
|
+
entry.raw_entry.should == "0.14.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb"
|
235
235
|
entry.occurred_at.should == Time.parse("2011-02-24 12:59:57")
|
236
236
|
entry.contexts.size.should == 2
|
237
237
|
entry.contexts[0].context_key = "app_name"
|
data/spec/logger_spec.rb
CHANGED
@@ -115,12 +115,12 @@ module Appstats
|
|
115
115
|
|
116
116
|
it "should accept numbers" do
|
117
117
|
Appstats::Logger.entry(5, :blah => 6)
|
118
|
-
Appstats::Logger.raw_read.should == ["0.
|
118
|
+
Appstats::Logger.raw_read.should == ["0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=5 : blah=6"]
|
119
119
|
end
|
120
120
|
|
121
121
|
it "should accept arrays" do
|
122
122
|
Appstats::Logger.entry('search', :provider => [ 'one', 'two' ])
|
123
|
-
Appstats::Logger.raw_read.should == ["0.
|
123
|
+
Appstats::Logger.raw_read.should == ["0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=search : provider=one : provider=two"]
|
124
124
|
end
|
125
125
|
|
126
126
|
|
@@ -130,7 +130,7 @@ module Appstats
|
|
130
130
|
|
131
131
|
it "should look similar to regular entry" do
|
132
132
|
Appstats::Logger.exception_entry(RuntimeError.new("blah"),:on => "login")
|
133
|
-
Appstats::Logger.raw_read.should == ["0.
|
133
|
+
Appstats::Logger.raw_read.should == ["0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=appstats-exception : error=blah : on=login"]
|
134
134
|
end
|
135
135
|
|
136
136
|
end
|
@@ -147,47 +147,47 @@ module Appstats
|
|
147
147
|
|
148
148
|
it "should handle a statistics entry" do
|
149
149
|
expected = { :action => "address_search", :timestamp => "2010-09-21 23:15:20" }
|
150
|
-
actual = Appstats::Logger.entry_to_hash("0.
|
150
|
+
actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
|
151
151
|
actual.should == expected
|
152
152
|
end
|
153
153
|
|
154
154
|
it "should handle contexts" do
|
155
155
|
expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
|
156
|
-
actual = Appstats::Logger.entry_to_hash("0.
|
156
|
+
actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
|
157
157
|
actual.should == expected
|
158
158
|
end
|
159
159
|
|
160
160
|
it "should handle multiple actions" do
|
161
161
|
expected = { :action => ["address_filter", "blah"], :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
|
162
|
-
actual = Appstats::Logger.entry_to_hash("0.
|
162
|
+
actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : action=blah : app_name=Market : server=Live")
|
163
163
|
actual.should == expected
|
164
164
|
end
|
165
165
|
|
166
166
|
it "should handle multiple of same context" do
|
167
167
|
expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => ['Sin','Market'] }
|
168
|
-
actual = Appstats::Logger.entry_to_hash("0.
|
168
|
+
actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Sin : app_name=Market : server=Live")
|
169
169
|
actual.should == expected
|
170
170
|
end
|
171
171
|
|
172
172
|
it "should handle no actions" do
|
173
173
|
expected = { :action => "UNKNOWN_ACTION", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
|
174
|
-
actual = Appstats::Logger.entry_to_hash("0.
|
174
|
+
actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 app_name=Market : server=Live")
|
175
175
|
actual.should == expected
|
176
176
|
end
|
177
177
|
|
178
178
|
it "should handle actions with the delimiter (and change the delimiter)" do
|
179
179
|
expected = { :action => "address:=search-n", :timestamp => "2010-09-21 23:15:20" }
|
180
|
-
actual = Appstats::Logger.entry_to_hash("0.
|
180
|
+
actual = Appstats::Logger.entry_to_hash("0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n")
|
181
181
|
actual.should == expected
|
182
182
|
|
183
183
|
expected = { :action => "address::search==--n", :timestamp => "2010-09-21 23:15:20" }
|
184
|
-
actual = Appstats::Logger.entry_to_hash("0.
|
184
|
+
actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n")
|
185
185
|
actual.should == expected
|
186
186
|
end
|
187
187
|
|
188
188
|
it "should handle contexts with the delimiter (and change the delimiter)" do
|
189
189
|
expected = { :action => "address", :timestamp => "2010-09-21 23:15:20", :server => "market:eval=-n" }
|
190
|
-
actual = Appstats::Logger.entry_to_hash("0.
|
190
|
+
actual = Appstats::Logger.entry_to_hash("0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n")
|
191
191
|
actual.should == expected
|
192
192
|
end
|
193
193
|
|
@@ -196,66 +196,66 @@ module Appstats
|
|
196
196
|
describe "#entry_to_s" do
|
197
197
|
|
198
198
|
it "should handle a statistics entry" do
|
199
|
-
expected = "0.
|
199
|
+
expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
|
200
200
|
actual = Appstats::Logger.entry_to_s("address_search")
|
201
201
|
actual.should == expected
|
202
202
|
end
|
203
203
|
|
204
204
|
it "should handle numbers" do
|
205
|
-
expected = "0.
|
205
|
+
expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=1 : note=2.2"
|
206
206
|
actual = Appstats::Logger.entry_to_s(1,:note => 2.2)
|
207
207
|
actual.should == expected
|
208
208
|
end
|
209
209
|
|
210
210
|
it "should handle default contexts" do
|
211
211
|
Appstats::Logger.default_contexts[:app_name] = "market"
|
212
|
-
expected = "0.
|
212
|
+
expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : app_name=market"
|
213
213
|
actual = Appstats::Logger.entry_to_s("address_search")
|
214
214
|
actual.should == expected
|
215
215
|
end
|
216
216
|
|
217
217
|
it "should handle contexts (and sort them by symbol)" do
|
218
|
-
expected = "0.
|
218
|
+
expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
|
219
219
|
actual = Appstats::Logger.entry_to_s("address_filter", { :server => "Live", :app_name => 'Market' })
|
220
220
|
actual.should == expected
|
221
221
|
end
|
222
222
|
|
223
223
|
it "should handle actions with the delimiter (and change the delimiter)" do
|
224
|
-
expected = "0.
|
224
|
+
expected = "0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n"
|
225
225
|
actual = Appstats::Logger.entry_to_s("address:=search-n")
|
226
226
|
actual.should == expected
|
227
227
|
|
228
|
-
expected = "0.
|
228
|
+
expected = "0.14.0 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n"
|
229
229
|
actual = Appstats::Logger.entry_to_s("address::search==--n")
|
230
230
|
actual.should == expected
|
231
231
|
end
|
232
232
|
|
233
233
|
it "should handle contexts with the delimiter (and change the delimiter)" do
|
234
|
-
expected = "0.
|
234
|
+
expected = "0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n"
|
235
235
|
actual = Appstats::Logger.entry_to_s("address", :server => 'market:eval=-n')
|
236
236
|
actual.should == expected
|
237
237
|
end
|
238
238
|
|
239
239
|
it "should ignore spaces" do
|
240
|
-
expected = "0.
|
240
|
+
expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address search"
|
241
241
|
actual = Appstats::Logger.entry_to_s("address search")
|
242
242
|
actual.should == expected
|
243
243
|
end
|
244
244
|
|
245
245
|
it "should convert newlines in action" do
|
246
|
-
expected = "0.
|
246
|
+
expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_-nsearch"
|
247
247
|
actual = Appstats::Logger.entry_to_s("address_\nsearch")
|
248
248
|
actual.should == expected
|
249
249
|
end
|
250
250
|
|
251
251
|
it "should convert newlines in context" do
|
252
|
-
expected = "0.
|
252
|
+
expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : blah=some-nlong-nstatement"
|
253
253
|
actual = Appstats::Logger.entry_to_s("address_search",:blah => "some\nlong\nstatement")
|
254
254
|
actual.should == expected
|
255
255
|
end
|
256
256
|
|
257
257
|
it "should convert newlines based on the delimiter" do
|
258
|
-
expected = "0.
|
258
|
+
expected = "0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=--nsearch-n"
|
259
259
|
actual = Appstats::Logger.entry_to_s("address:=\nsearch-n")
|
260
260
|
actual.should == expected
|
261
261
|
end
|
data/spec/query_spec.rb
CHANGED
@@ -32,7 +32,8 @@ module Appstats
|
|
32
32
|
query.action.should == nil
|
33
33
|
query.host.should == nil
|
34
34
|
query.date_range.should == DateRange.new
|
35
|
-
|
35
|
+
query.groups.should == []
|
36
|
+
query.group_query_to_sql.should == nil
|
36
37
|
end
|
37
38
|
|
38
39
|
it "should set the action and host" do
|
@@ -40,6 +41,8 @@ module Appstats
|
|
40
41
|
query.action.should == "myblahs"
|
41
42
|
query.host.should == "xyz.localnet"
|
42
43
|
query.date_range.should == DateRange.parse("today")
|
44
|
+
query.groups.should == []
|
45
|
+
query.group_query_to_sql.should == nil
|
43
46
|
end
|
44
47
|
|
45
48
|
it "should understand the short hand 'on' instead of 'on server'" do
|
@@ -47,6 +50,8 @@ module Appstats
|
|
47
50
|
query.action.should == "myblahs"
|
48
51
|
query.host.should == "xyz.localnet"
|
49
52
|
query.date_range.should == DateRange.new
|
53
|
+
query.groups.should == []
|
54
|
+
query.group_query_to_sql.should == nil
|
50
55
|
end
|
51
56
|
|
52
57
|
it "should understand the old 'on server' instead of new 'on'" do
|
@@ -54,7 +59,24 @@ module Appstats
|
|
54
59
|
query.action.should == "myblahs"
|
55
60
|
query.host.should == "xyz.localnet"
|
56
61
|
query.date_range.should == DateRange.new
|
62
|
+
query.groups.should == []
|
63
|
+
query.group_query_to_sql.should == nil
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "group by" do
|
67
|
+
|
68
|
+
it "should handle single entry" do
|
69
|
+
query = Appstats::Query.new(:query => "# myblahs group by aa")
|
70
|
+
query.groups.should == ["aa"]
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should handle multi-entry" do
|
74
|
+
query = Appstats::Query.new(:query => "# myblahs group by aa,bbbb")
|
75
|
+
query.groups.should == ["aa","bbbb"]
|
76
|
+
end
|
77
|
+
|
57
78
|
end
|
79
|
+
|
58
80
|
|
59
81
|
end
|
60
82
|
|
@@ -64,102 +86,130 @@ module Appstats
|
|
64
86
|
Appstats::Entry.delete_all
|
65
87
|
end
|
66
88
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
89
|
+
describe "core search" do
|
90
|
+
it "should return 0 if no results" do
|
91
|
+
query = Appstats::Query.new(:query => "# blahs")
|
92
|
+
result = query.run
|
93
|
+
result.new_record?.should == false
|
94
|
+
result.should == Appstats::Result.new(:result_type => "on_demand", :query => "# blahs", :query_as_sql => query.query_to_sql, :count => 0, :action => "blahs")
|
95
|
+
end
|
73
96
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
it "should track contexts" do
|
82
|
-
query = Appstats::Query.new(:query => "# blahs where (a=b and c=4) or (aaa=5)")
|
83
|
-
result = query.run
|
84
|
-
result.new_record?.should == false
|
85
|
-
result.contexts.should == "(a=b and c=4) or (aaa=5)"
|
86
|
-
end
|
87
|
-
|
88
|
-
|
89
|
-
it "should track the count if available" do
|
90
|
-
Appstats::Entry.create(:action => "myblahs")
|
91
|
-
query = Appstats::Query.new(:query => "# myblahs")
|
92
|
-
query.run.count.should == 1
|
93
|
-
Appstats::Entry.create(:action => "myblahs")
|
94
|
-
query.run.count.should == 2
|
95
|
-
end
|
97
|
+
it "should set name and result_type if provided" do
|
98
|
+
query = Appstats::Query.new(:name => "x", :result_type => "some_reason", :query => "# blahs")
|
99
|
+
result = query.run
|
100
|
+
result.new_record?.should == false
|
101
|
+
result.should == Appstats::Result.new(:name => "x", :result_type => "some_reason", :query => "# blahs", :query_as_sql => query.query_to_sql, :count => 0, :action => "blahs")
|
102
|
+
end
|
96
103
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
104
|
+
it "should track contexts" do
|
105
|
+
query = Appstats::Query.new(:query => "# blahs where (a=b and c=4) or (aaa=5)")
|
106
|
+
result = query.run
|
107
|
+
result.new_record?.should == false
|
108
|
+
result.contexts.should == "(a=b and c=4) or (aaa=5)"
|
109
|
+
end
|
101
110
|
|
102
|
-
Appstats::Entry.create_from_logger("myblahs",:app_name => ["a","c"])
|
103
|
-
Appstats::Entry.create_from_logger("myblahs",:app_name => ["b","d"])
|
104
|
-
Appstats::Entry.create_from_logger("myblahs",:app_name => ["c","d"])
|
105
|
-
query = Appstats::Query.new(:query => "# myblahs where app_name='a' or app_name = 'b'")
|
106
|
-
query.run.count.should == 3
|
107
111
|
|
108
|
-
|
112
|
+
it "should track the count if available" do
|
113
|
+
Appstats::Entry.create(:action => "myblahs")
|
114
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
115
|
+
query.run.count.should == 1
|
116
|
+
Appstats::Entry.create(:action => "myblahs")
|
117
|
+
query.run.count.should == 2
|
118
|
+
end
|
109
119
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
query = Appstats::Query.new(:query => "# myblahs where one=11")
|
116
|
-
result = query.run
|
117
|
-
result.count.should == 1
|
118
|
-
|
119
|
-
query = Appstats::Query.new(:query => "# myblahs where one=anything")
|
120
|
-
query.run.count.should == 0
|
121
|
-
|
122
|
-
query = Appstats::Query.new(:query => "# myblahs where one=11 && two=22")
|
123
|
-
query.run.count.should == 0
|
124
|
-
|
125
|
-
query = Appstats::Query.new(:query => "# myblahs where one=11 || two=22")
|
126
|
-
query.run.count.should == 2
|
127
|
-
end
|
128
|
-
|
129
|
-
describe "fixed_points searches" do
|
120
|
+
it "should not double count an entry with multiple contexts" do
|
121
|
+
Appstats::Entry.create_from_logger("myblahs",:app_name => ["a","b"])
|
122
|
+
query = Appstats::Query.new(:query => "# myblahs where app_name='a' or app_name = 'b'")
|
123
|
+
query.run.count.should == 1
|
130
124
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
125
|
+
Appstats::Entry.create_from_logger("myblahs",:app_name => ["a","c"])
|
126
|
+
Appstats::Entry.create_from_logger("myblahs",:app_name => ["b","d"])
|
127
|
+
Appstats::Entry.create_from_logger("myblahs",:app_name => ["c","d"])
|
128
|
+
query = Appstats::Query.new(:query => "# myblahs where app_name='a' or app_name = 'b'")
|
129
|
+
query.run.count.should == 3
|
136
130
|
|
137
|
-
it "should handle quarter" do
|
138
|
-
query = Appstats::Query.new(:query => "# myblahs last quarter")
|
139
|
-
result = query.run
|
140
|
-
result.date_to_s.should == "2010-04-01 to 2010-06-30"
|
141
131
|
end
|
142
132
|
|
143
|
-
|
144
|
-
|
133
|
+
|
134
|
+
it "should perform the action search" do
|
135
|
+
Appstats::Entry.create_from_logger("myblahs", :one => "11", :two => "222")
|
136
|
+
Appstats::Entry.create_from_logger("myblahs", :one => "111", :two => "22")
|
137
|
+
|
138
|
+
query = Appstats::Query.new(:query => "# myblahs where one=11")
|
145
139
|
result = query.run
|
146
|
-
result.
|
140
|
+
result.count.should == 1
|
141
|
+
|
142
|
+
query = Appstats::Query.new(:query => "# myblahs where one=anything")
|
143
|
+
query.run.count.should == 0
|
144
|
+
|
145
|
+
query = Appstats::Query.new(:query => "# myblahs where one=11 && two=22")
|
146
|
+
query.run.count.should == 0
|
147
|
+
|
148
|
+
query = Appstats::Query.new(:query => "# myblahs where one=11 || two=22")
|
149
|
+
query.run.count.should == 2
|
147
150
|
end
|
148
151
|
|
149
|
-
|
150
|
-
|
152
|
+
describe "fixed_points searches" do
|
153
|
+
|
154
|
+
it "should handle year" do
|
155
|
+
query = Appstats::Query.new(:query => "# myblahs last year")
|
156
|
+
result = query.run
|
157
|
+
result.date_to_s.should == "2009-01-01 to 2009-12-31"
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should handle quarter" do
|
161
|
+
query = Appstats::Query.new(:query => "# myblahs last quarter")
|
162
|
+
result = query.run
|
163
|
+
result.date_to_s.should == "2010-04-01 to 2010-06-30"
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should handle month" do
|
167
|
+
query = Appstats::Query.new(:query => "# myblahs last month")
|
168
|
+
result = query.run
|
169
|
+
result.date_to_s.should == "2010-08-01 to 2010-08-31"
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should handle week" do
|
173
|
+
query = Appstats::Query.new(:query => "# myblahs last week")
|
174
|
+
result = query.run
|
175
|
+
result.date_to_s.should == "2010-09-13 to 2010-09-19"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should handle day" do
|
179
|
+
query = Appstats::Query.new(:query => "# myblahs last day")
|
180
|
+
result = query.run
|
181
|
+
result.date_to_s.should == "2010-09-20"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "group sub results" do
|
187
|
+
|
188
|
+
it "should not create sub results if no groups" do
|
189
|
+
query = Appstats::Query.new(:query => "# myblahs last day")
|
151
190
|
result = query.run
|
152
|
-
result.
|
191
|
+
result.sub_results.should == []
|
153
192
|
end
|
154
193
|
|
155
|
-
it "should
|
156
|
-
|
194
|
+
it "should track sub results as required" do
|
195
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :ignore => "1")
|
196
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :ignore => "1")
|
197
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :ignore => "2")
|
198
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "b", :ignore => "1")
|
199
|
+
|
200
|
+
query = Appstats::Query.new(:query => "# myblahs group by service_provider")
|
157
201
|
result = query.run
|
158
|
-
result.
|
202
|
+
result.count.should == 4
|
203
|
+
result.sub_results.size.should == 2
|
204
|
+
|
205
|
+
result.sub_results[0].should == SubResult.new(:context_filter => "a", :count => 3, :ratio_of_total => 0.75)
|
206
|
+
result.sub_results[1].should == SubResult.new(:context_filter => "b", :count => 1, :ratio_of_total => 0.25)
|
207
|
+
|
208
|
+
|
159
209
|
end
|
160
210
|
|
211
|
+
|
161
212
|
end
|
162
|
-
|
163
213
|
|
164
214
|
end
|
165
215
|
|
@@ -252,6 +302,45 @@ module Appstats
|
|
252
302
|
|
253
303
|
end
|
254
304
|
|
305
|
+
describe "#group_query_to_sql" do
|
306
|
+
|
307
|
+
before(:each) do
|
308
|
+
@template = "select id from appstats_entries where action = 'myblahs'"
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should support no filters" do
|
312
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
313
|
+
query.group_query_to_sql.should == nil
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should support 1 filter" do
|
317
|
+
query = Appstats::Query.new(:query => "# myblahs group by aa")
|
318
|
+
expected = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in ('aa') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_filter;"
|
319
|
+
query.group_query_to_sql.should == expected
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should support surrounding quotes" do
|
323
|
+
query = Appstats::Query.new(:query => "# myblahs group by 'aa'")
|
324
|
+
expected = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in ('aa') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_filter;"
|
325
|
+
query.group_query_to_sql.should == expected
|
326
|
+
end
|
327
|
+
|
328
|
+
it "should support inner quotes" do
|
329
|
+
query = Appstats::Query.new(:query => "# myblahs group by a's")
|
330
|
+
expected = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in ('a''s') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_filter;"
|
331
|
+
query.group_query_to_sql.should == expected
|
332
|
+
end
|
333
|
+
|
334
|
+
|
335
|
+
it "should support many filters" do
|
336
|
+
query = Appstats::Query.new(:query => "# myblahs group by aa, bbb")
|
337
|
+
expected = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in ('aa','bbb') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_filter;"
|
338
|
+
query.group_query_to_sql.should == expected
|
339
|
+
end
|
340
|
+
|
341
|
+
|
342
|
+
end
|
343
|
+
|
255
344
|
describe "#contexts_filter_to_sql" do
|
256
345
|
|
257
346
|
before(:each) do
|
data/spec/result_spec.rb
CHANGED
@@ -126,6 +126,30 @@ module Appstats
|
|
126
126
|
end
|
127
127
|
|
128
128
|
end
|
129
|
+
|
130
|
+
describe "#sub_results" do
|
131
|
+
|
132
|
+
it "should be empty be default" do
|
133
|
+
@result.sub_results.should == []
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should order by count" do
|
137
|
+
@result = Result.create
|
138
|
+
sub1 = SubResult.create(:count => 10)
|
139
|
+
sub2 = SubResult.create(:count => 20)
|
140
|
+
sub3 = SubResult.create(:count => 30)
|
141
|
+
|
142
|
+
@result.sub_results<< sub1
|
143
|
+
@result.sub_results<< sub3
|
144
|
+
@result.sub_results<< sub2
|
145
|
+
|
146
|
+
@result.save.should == true
|
147
|
+
@result.reload
|
148
|
+
|
149
|
+
@result.sub_results.should == [sub3,sub2,sub1]
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
129
153
|
|
130
154
|
end
|
131
155
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Appstats
|
4
|
+
describe SubResult do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@sub_result = Appstats::SubResult.new
|
8
|
+
Time.stub!(:now).and_return(Time.parse('2010-09-21 23:15:20'))
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#initialize" do
|
12
|
+
|
13
|
+
it "should set attributes to nil" do
|
14
|
+
@sub_result.context_filter.should == nil
|
15
|
+
@sub_result.count.should == nil
|
16
|
+
@sub_result.ratio_of_total.should == nil
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set on constructor" do
|
20
|
+
sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
|
21
|
+
sub_result.context_filter.should == 'a'
|
22
|
+
sub_result.count.should == 1
|
23
|
+
sub_result.ratio_of_total.should == 0.2
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#result" do
|
29
|
+
|
30
|
+
it "should be nil be default" do
|
31
|
+
@sub_result.result.should == nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should be settable" do
|
35
|
+
@result = Result.create
|
36
|
+
@sub_result.result = @result
|
37
|
+
@sub_result.save.should == true
|
38
|
+
|
39
|
+
@sub_result.reload
|
40
|
+
@result.reload
|
41
|
+
|
42
|
+
@sub_result.result.should == @result
|
43
|
+
@result.sub_results.should == [@sub_result]
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#==" do
|
49
|
+
|
50
|
+
it "should be equal on all attributes" do
|
51
|
+
sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
|
52
|
+
same_sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
|
53
|
+
(sub_result == same_sub_result).should == true
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should be not equal if diferent attributes" do
|
57
|
+
sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
|
58
|
+
|
59
|
+
[:context_filter,:count,:ratio_of_total].each do |attr|
|
60
|
+
different_sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
|
61
|
+
different_sub_result.context_filter = "XXX" if attr == :context_filter
|
62
|
+
different_sub_result.count = 11 if attr == :count
|
63
|
+
different_sub_result.ratio_of_total = 0.22 if attr == :ratio_of_total
|
64
|
+
|
65
|
+
different_sub_result.should_not == sub_result
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#total_count" do
|
72
|
+
|
73
|
+
it "should be zero if no result" do
|
74
|
+
@sub_result.total_count.should == 0
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should be based on result.count" do
|
78
|
+
@sub_result.result = Result.create(:count => 10)
|
79
|
+
@sub_result.total_count.should == 10
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appstats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 39
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 14
|
9
|
+
- 0
|
10
|
+
version: 0.14.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andrew Forward
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-03-01 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -159,6 +159,8 @@ files:
|
|
159
159
|
- db/migrations/20110222215437_create_appstats_jobs.rb
|
160
160
|
- db/migrations/20110223212232_add_appstats_entries_week_and_quarter.rb
|
161
161
|
- db/migrations/20110225192624_add_appstats_log_collector_local_filename.rb
|
162
|
+
- db/migrations/20110301170733_add_appstats_results_group_query_to_sql.rb
|
163
|
+
- db/migrations/20110301170947_create_appstats_sub_results.rb
|
162
164
|
- db/schema.rb
|
163
165
|
- lib/appstats.rb
|
164
166
|
- lib/appstats/action.rb
|
@@ -177,6 +179,7 @@ files:
|
|
177
179
|
- lib/appstats/query.rb
|
178
180
|
- lib/appstats/result.rb
|
179
181
|
- lib/appstats/result_job.rb
|
182
|
+
- lib/appstats/sub_result.rb
|
180
183
|
- lib/appstats/tasks.rb
|
181
184
|
- lib/appstats/test_object.rb
|
182
185
|
- lib/appstats/version.rb
|
@@ -217,6 +220,7 @@ files:
|
|
217
220
|
- spec/result_job_spec.rb
|
218
221
|
- spec/result_spec.rb
|
219
222
|
- spec/spec_helper.rb
|
223
|
+
- spec/sub_result_spec.rb
|
220
224
|
- spec/test_object_spec.rb
|
221
225
|
has_rdoc: true
|
222
226
|
homepage: http://github.com/aforward/appstats
|
@@ -270,4 +274,5 @@ test_files:
|
|
270
274
|
- spec/result_job_spec.rb
|
271
275
|
- spec/result_spec.rb
|
272
276
|
- spec/spec_helper.rb
|
277
|
+
- spec/sub_result_spec.rb
|
273
278
|
- spec/test_object_spec.rb
|