mongoid_traffic 0.2.5 → 1.0.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.
@@ -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