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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +88 -91
- data/Rakefile +2 -19
- data/lib/mongoid_traffic.rb +4 -1
- data/lib/mongoid_traffic/log.rb +29 -49
- data/lib/mongoid_traffic/logger.rb +33 -88
- data/lib/mongoid_traffic/version.rb +1 -1
- data/mongoid_traffic.gemspec +10 -10
- metadata +15 -84
- data/lib/mongoid_traffic/controller_additions.rb +0 -31
- data/lib/mongoid_traffic/logger/bots.rb +0 -31
- data/lib/mongoid_traffic/logger/browser.rb +0 -29
- data/lib/mongoid_traffic/logger/geo_ip.rb +0 -20
- data/lib/mongoid_traffic/logger/referer.rb +0 -25
- data/test/mongoid_traffic/controller_additions_test.rb +0 -25
- data/test/mongoid_traffic/log_test.rb +0 -143
- data/test/mongoid_traffic/logger/bots_test.rb +0 -21
- data/test/mongoid_traffic/logger/browser_test.rb +0 -24
- data/test/mongoid_traffic/logger/geoip_test.rb +0 -15
- data/test/mongoid_traffic/logger/referer_test.rb +0 -28
- data/test/mongoid_traffic/logger_test.rb +0 -62
- data/test/support/database_cleaner.rb +0 -10
- data/test/support/mongoid.rb +0 -8
- data/test/test_helper.rb +0 -22
- data/vendor/mongoid_traffic/GeoIP.dat +0 -0
- data/vendor/mongoid_traffic/allagents.xml +0 -22134
@@ -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
|
-
|
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
|
-
@
|
25
|
-
@
|
26
|
-
@
|
27
|
-
|
28
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
67
|
-
|
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
|
74
|
-
|
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
|
-
|
80
|
-
|
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
|
-
|
94
|
-
|
95
|
-
|
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
|
100
|
-
|
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
|
data/mongoid_traffic.gemspec
CHANGED
@@ -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 = [
|
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
|
17
|
-
|
18
|
-
|
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.
|
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.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomáš Celizna
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
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.
|
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.
|
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.
|
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('<', '<') 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
|