mongoid_traffic 0.2.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,123 +1,68 @@
1
- require 'uri'
2
- require 'useragent'
3
-
4
- require_relative './log'
5
- require_relative './logger/bots'
6
- require_relative './logger/browser'
7
- require_relative './logger/geo_ip'
8
- require_relative './logger/referer'
9
-
10
1
  module MongoidTraffic
11
2
  class Logger
12
- TIME_SCOPE_OPTIONS = %i(year month week day).freeze
13
-
14
- # ---------------------------------------------------------------------
3
+ attr_accessor :log_cls
4
+ attr_accessor :selector
5
+ attr_accessor :time_scope
6
+ attr_accessor :additonal_counters
15
7
 
16
8
  def self.log(log_cls, *args)
17
9
  new(log_cls, *args).log
18
10
  end
19
11
 
20
- # ---------------------------------------------------------------------
21
-
22
- def initialize(log_cls, ip_address: nil, referer: nil, scope: nil, time_scope: %i(month day), unique_id: nil, user_agent: nil)
12
+ def initialize(log_cls, options = {})
23
13
  @log_cls = log_cls
24
- @ip_address = ip_address
25
- @referer_string = referer
26
- @scope = scope
27
- @time_scope = time_scope
28
- @unique_id = unique_id
29
- @user_agent_string = user_agent
14
+ @selector = log_cls.criteria.selector
15
+ @time_scope = options.fetch(:time_scope, TIME_SCOPE_OPTIONS.keys)
16
+ @additonal_counters = options.except(:time_scope, :scope)
17
+
18
+ raise "Invalid time scope definition: #{time_scope}" unless time_scope.all? { |ts| TIME_SCOPE_OPTIONS.key?(ts) }
30
19
  end
31
20
 
32
21
  def log
33
- return if Bots.is_a_bot?(@referer_string)
34
- raise "Invalid time scope definition: #{@time_scope}" unless @time_scope.all? { |ts| TIME_SCOPE_OPTIONS.include?(ts) }
35
-
36
- @time_scope.each do |ts|
37
- @log_cls.collection.find(find_query(ts)).update_many(upsert_query, upsert: true)
22
+ time_scope.each do |ts|
23
+ log_cls.collection
24
+ .find(find_query(ts))
25
+ .update_many(upsert_query(ts), upsert: true)
38
26
  end
39
27
  end
40
28
 
41
- # ---------------------------------------------------------------------
42
-
43
- def upsert_query
44
- {
45
- '$inc' => access_count_query
46
- .merge(browser_query)
47
- .merge(country_query)
48
- .merge(referer_query)
49
- .merge(unique_id_query),
50
- '$set' => { uat: Time.now }
51
- }
52
- end
53
-
54
- # ---------------------------------------------------------------------
55
-
56
- def access_count_query
57
- { ac: 1 }
58
- end
59
-
60
- def browser_query
61
- return {} unless browser.present?
62
- browser_path = [browser.platform, browser.name, browser.version].map { |s| escape_key(s) }.join('.')
63
- { "b.#{browser_path}" => 1 }
64
- end
29
+ private
65
30
 
66
- def country_query
67
- return {} unless @ip_address.present?
68
- return {} unless country_code2 = GeoIp.country_code2(@ip_address)
69
- country_code_key = escape_key(country_code2)
70
- { "c.#{country_code_key}" => 1 }
31
+ def find_query(ts)
32
+ time_query(ts).merge(selector)
71
33
  end
72
34
 
73
- def referer_query
74
- return {} unless referer.present?
75
- referer_key = escape_key(referer.to_s)
76
- { "r.#{referer_key}" => 1 }
77
- end
35
+ def upsert_query(time_scope)
36
+ ts = TIME_SCOPE_OPTIONS[time_scope]
78
37
 
79
- def unique_id_query
80
- return {} unless @unique_id.present?
81
- unique_id_key = escape_key(@unique_id.to_s)
82
- { "u.#{unique_id_key}" => 1 }
38
+ { '$inc' => access_count_query.merge(additonal_counters_query),
39
+ '$set' => { ts: ts, uat: Time.now } }
83
40
  end
84
41
 
85
- # ---------------------------------------------------------------------
86
-
87
- def escape_key(key)
88
- CGI.escape(key).gsub('.', '%2E')
42
+ def access_count_query
43
+ { ac: 1 }
89
44
  end
90
45
 
91
- # ---------------------------------------------------------------------
92
-
93
- def find_query(ts)
94
- res = time_query(ts)
95
- res = res.merge(scope_query) if @scope.present?
96
- res
46
+ def additonal_counters_query
47
+ Array(additonal_counters).each_with_object({}) do |(name, value), res|
48
+ next unless field = find_field(name)
49
+ res["#{field.name}.#{value}"] = 1
50
+ end
97
51
  end
98
52
 
99
- def scope_query
100
- { s: @scope }
53
+ def find_field(name)
54
+ log_cls.fields.detect do |field_name, field|
55
+ field_name == name.to_s || field.options[:as].to_s == name.to_s
56
+ end.try(:last)
101
57
  end
102
58
 
103
59
  def time_query(ts)
104
60
  date = Date.today
61
+
105
62
  case ts
106
63
  when :day then { df: date, dt: date }
107
64
  else { df: date.send("at_beginning_of_#{ts}"), dt: date.send("at_end_of_#{ts}") }
108
65
  end
109
66
  end
110
-
111
- private # =============================================================
112
-
113
- def browser
114
- return unless @user_agent_string.present?
115
- @browser ||= Browser.new(@user_agent_string)
116
- end
117
-
118
- def referer
119
- return unless @referer_string.present?
120
- @referer ||= Referer.new(@referer_string)
121
- end
122
67
  end
123
68
  end
@@ -1,3 +1,3 @@
1
1
  module MongoidTraffic
2
- VERSION = '0.2.5'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
@@ -6,29 +6,29 @@ require 'mongoid_traffic/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'mongoid_traffic'
8
8
  spec.version = MongoidTraffic::VERSION
9
- spec.authors = ["Tomáš Celizna"]
9
+ spec.authors = ['Tomáš Celizna']
10
10
  spec.email = ['tomas.celizna@gmail.com']
11
11
  spec.description = 'Aggregated traffic logs stored in MongoDB.'
12
12
  spec.summary = 'Aggregated traffic logs stored in MongoDB.'
13
13
  spec.homepage = 'https://github.com/tomasc/mongoid_traffic'
14
14
  spec.license = 'MIT'
15
15
 
16
- spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+
20
+ spec.bindir = 'exe'
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
22
  spec.require_paths = ['lib']
20
23
 
21
- spec.add_dependency 'geoip'
22
24
  spec.add_dependency 'mongoid', '>= 5', '< 8'
23
- spec.add_dependency 'nokogiri'
24
- spec.add_dependency 'useragent'
25
25
 
26
- spec.add_development_dependency 'bundler', '~> 1.3'
26
+ spec.add_development_dependency 'bundler', '~> 1.12'
27
27
  spec.add_development_dependency 'coveralls'
28
28
  spec.add_development_dependency 'database_cleaner', '~> 1.5.2'
29
29
  spec.add_development_dependency 'guard'
30
30
  spec.add_development_dependency 'guard-minitest'
31
- spec.add_development_dependency 'minitest'
31
+ spec.add_development_dependency 'minitest', '~> 5.0'
32
32
  spec.add_development_dependency 'minitest-around'
33
- spec.add_development_dependency 'rake'
33
+ spec.add_development_dependency 'rake', '~> 10.0'
34
34
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid_traffic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomáš Celizna
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-03 00:00:00.000000000 Z
11
+ date: 2018-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: geoip
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: mongoid
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -44,48 +30,20 @@ dependencies:
44
30
  - - "<"
45
31
  - !ruby/object:Gem::Version
46
32
  version: '8'
47
- - !ruby/object:Gem::Dependency
48
- name: nokogiri
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: '0'
61
- - !ruby/object:Gem::Dependency
62
- name: useragent
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- version: '0'
68
- type: :runtime
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- version: '0'
75
33
  - !ruby/object:Gem::Dependency
76
34
  name: bundler
77
35
  requirement: !ruby/object:Gem::Requirement
78
36
  requirements:
79
37
  - - "~>"
80
38
  - !ruby/object:Gem::Version
81
- version: '1.3'
39
+ version: '1.12'
82
40
  type: :development
83
41
  prerelease: false
84
42
  version_requirements: !ruby/object:Gem::Requirement
85
43
  requirements:
86
44
  - - "~>"
87
45
  - !ruby/object:Gem::Version
88
- version: '1.3'
46
+ version: '1.12'
89
47
  - !ruby/object:Gem::Dependency
90
48
  name: coveralls
91
49
  requirement: !ruby/object:Gem::Requirement
@@ -146,16 +104,16 @@ dependencies:
146
104
  name: minitest
147
105
  requirement: !ruby/object:Gem::Requirement
148
106
  requirements:
149
- - - ">="
107
+ - - "~>"
150
108
  - !ruby/object:Gem::Version
151
- version: '0'
109
+ version: '5.0'
152
110
  type: :development
153
111
  prerelease: false
154
112
  version_requirements: !ruby/object:Gem::Requirement
155
113
  requirements:
156
- - - ">="
114
+ - - "~>"
157
115
  - !ruby/object:Gem::Version
158
- version: '0'
116
+ version: '5.0'
159
117
  - !ruby/object:Gem::Dependency
160
118
  name: minitest-around
161
119
  requirement: !ruby/object:Gem::Requirement
@@ -174,16 +132,16 @@ dependencies:
174
132
  name: rake
175
133
  requirement: !ruby/object:Gem::Requirement
176
134
  requirements:
177
- - - ">="
135
+ - - "~>"
178
136
  - !ruby/object:Gem::Version
179
- version: '0'
137
+ version: '10.0'
180
138
  type: :development
181
139
  prerelease: false
182
140
  version_requirements: !ruby/object:Gem::Requirement
183
141
  requirements:
184
- - - ">="
142
+ - - "~>"
185
143
  - !ruby/object:Gem::Version
186
- version: '0'
144
+ version: '10.0'
187
145
  description: Aggregated traffic logs stored in MongoDB.
188
146
  email:
189
147
  - tomas.celizna@gmail.com
@@ -201,27 +159,10 @@ files:
201
159
  - README.md
202
160
  - Rakefile
203
161
  - lib/mongoid_traffic.rb
204
- - lib/mongoid_traffic/controller_additions.rb
205
162
  - lib/mongoid_traffic/log.rb
206
163
  - lib/mongoid_traffic/logger.rb
207
- - lib/mongoid_traffic/logger/bots.rb
208
- - lib/mongoid_traffic/logger/browser.rb
209
- - lib/mongoid_traffic/logger/geo_ip.rb
210
- - lib/mongoid_traffic/logger/referer.rb
211
164
  - lib/mongoid_traffic/version.rb
212
165
  - mongoid_traffic.gemspec
213
- - test/mongoid_traffic/controller_additions_test.rb
214
- - test/mongoid_traffic/log_test.rb
215
- - test/mongoid_traffic/logger/bots_test.rb
216
- - test/mongoid_traffic/logger/browser_test.rb
217
- - test/mongoid_traffic/logger/geoip_test.rb
218
- - test/mongoid_traffic/logger/referer_test.rb
219
- - test/mongoid_traffic/logger_test.rb
220
- - test/support/database_cleaner.rb
221
- - test/support/mongoid.rb
222
- - test/test_helper.rb
223
- - vendor/mongoid_traffic/GeoIP.dat
224
- - vendor/mongoid_traffic/allagents.xml
225
166
  homepage: https://github.com/tomasc/mongoid_traffic
226
167
  licenses:
227
168
  - MIT
@@ -242,18 +183,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
183
  version: '0'
243
184
  requirements: []
244
185
  rubyforge_project:
245
- rubygems_version: 2.7.3
186
+ rubygems_version: 2.7.6
246
187
  signing_key:
247
188
  specification_version: 4
248
189
  summary: Aggregated traffic logs stored in MongoDB.
249
- test_files:
250
- - test/mongoid_traffic/controller_additions_test.rb
251
- - test/mongoid_traffic/log_test.rb
252
- - test/mongoid_traffic/logger/bots_test.rb
253
- - test/mongoid_traffic/logger/browser_test.rb
254
- - test/mongoid_traffic/logger/geoip_test.rb
255
- - test/mongoid_traffic/logger/referer_test.rb
256
- - test/mongoid_traffic/logger_test.rb
257
- - test/support/database_cleaner.rb
258
- - test/support/mongoid.rb
259
- - test/test_helper.rb
190
+ test_files: []
@@ -1,31 +0,0 @@
1
- module MongoidTraffic
2
- module ControllerAdditions
3
- def log_traffic(log_cls, scope: nil)
4
- MongoidTraffic::Logger.log(
5
- log_cls,
6
- ip_address: request.remote_ip,
7
- referer: request.headers['Referer'],
8
- unique_id: request.session_options[:id], # FIXME: not sure about this
9
- user_agent: request.headers['User-Agent']
10
- )
11
- end
12
-
13
- def log_scoped_traffic(_log_cls, scope: nil)
14
- log_traffic(scope: (scope || request.fullpath.split('?').first))
15
- end
16
-
17
- # ---------------------------------------------------------------------
18
-
19
- def self.included(base)
20
- base.extend ClassMethods
21
- base.helper_method :log_traffic
22
- base.helper_method :log_scoped_traffic
23
- end
24
- end
25
- end
26
-
27
- if defined? ActionController::Base
28
- ActionController::Base.class_eval do
29
- include MongoidTraffic::ControllerAdditions
30
- end
31
- end
@@ -1,31 +0,0 @@
1
- require 'nokogiri'
2
-
3
- # sourced from https://github.com/charlotte-ruby/impressionist/blob/master/lib/impressionist/bots.rb
4
-
5
- module MongoidTraffic
6
- class Logger
7
- class Bots
8
- DATA_URL = 'http://www.user-agents.org/allagents.xml'.freeze
9
- FILE_PATH = File.join(File.dirname(__dir__), '..', '..', 'vendor', 'mongoid_traffic', 'allagents.xml')
10
-
11
- class << self
12
- def list
13
- @list ||= begin
14
- response = File.open(FILE_PATH).read
15
- doc = Nokogiri::XML(response)
16
- doc.xpath('//user-agent').inject([]) do |res, agent|
17
- type = agent.xpath('Type').text
18
- res << agent.xpath('String').text.gsub('&lt;', '<') if %w(R S).include?(type)
19
- res
20
- end
21
- end
22
- end
23
-
24
- def is_a_bot?(referer)
25
- return false unless referer.present?
26
- list.include?(referer)
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,29 +0,0 @@
1
- require 'user_agent'
2
-
3
- module MongoidTraffic
4
- class Logger
5
- class Browser
6
- def initialize(user_agent_string)
7
- @user_agent_string = user_agent_string
8
- end
9
-
10
- def platform
11
- user_agent.platform
12
- end
13
-
14
- def name
15
- user_agent.browser
16
- end
17
-
18
- def version
19
- user_agent.version.to_s.split('.')[0..1].join('.')
20
- end
21
-
22
- private # =============================================================
23
-
24
- def user_agent
25
- @user_agent ||= ::UserAgent.parse(@user_agent_string)
26
- end
27
- end
28
- end
29
- end