ahoy_matey 1.1.1 → 1.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile +1 -1
- data/README.md +43 -7
- data/Rakefile +1 -1
- data/ahoy_matey.gemspec +4 -4
- data/app/controllers/ahoy/base_controller.rb +0 -1
- data/app/controllers/ahoy/events_controller.rb +0 -2
- data/app/controllers/ahoy/visits_controller.rb +0 -2
- data/lib/ahoy.rb +9 -0
- data/lib/ahoy/controller.rb +0 -2
- data/lib/ahoy/deckhands/location_deckhand.rb +13 -3
- data/lib/ahoy/deckhands/request_deckhand.rb +0 -1
- data/lib/ahoy/deckhands/technology_deckhand.rb +0 -2
- data/lib/ahoy/deckhands/traffic_source_deckhand.rb +0 -2
- data/lib/ahoy/deckhands/utm_parameter_deckhand.rb +1 -3
- data/lib/ahoy/engine.rb +6 -11
- data/lib/ahoy/geocode_job.rb +0 -1
- data/lib/ahoy/logger_silencer.rb +73 -0
- data/lib/ahoy/model.rb +1 -4
- data/lib/ahoy/stores/active_record_store.rb +1 -3
- data/lib/ahoy/stores/active_record_token_store.rb +10 -14
- data/lib/ahoy/stores/base_store.rb +1 -3
- data/lib/ahoy/stores/fluentd_store.rb +17 -0
- data/lib/ahoy/stores/log_store.rb +11 -5
- data/lib/ahoy/stores/mongoid_store.rb +0 -2
- data/lib/ahoy/subscribers/active_record.rb +0 -2
- data/lib/ahoy/tracker.rb +14 -5
- data/lib/ahoy/version.rb +1 -1
- data/lib/ahoy/visit_properties.rb +2 -4
- data/lib/ahoy/warden.rb +1 -1
- data/lib/generators/ahoy/stores/active_record_events_generator.rb +1 -2
- data/lib/generators/ahoy/stores/active_record_generator.rb +0 -1
- data/lib/generators/ahoy/stores/active_record_visits_generator.rb +1 -2
- data/lib/generators/ahoy/stores/custom_generator.rb +0 -1
- data/lib/generators/ahoy/stores/fluentd_generator.rb +15 -0
- data/lib/generators/ahoy/stores/log_generator.rb +0 -1
- data/lib/generators/ahoy/stores/mongoid_events_generator.rb +0 -1
- data/lib/generators/ahoy/stores/mongoid_generator.rb +0 -2
- data/lib/generators/ahoy/stores/mongoid_visits_generator.rb +0 -1
- data/lib/generators/ahoy/stores/templates/active_record_event_model.rb +1 -1
- data/lib/generators/ahoy/stores/templates/active_record_events_migration.rb +3 -3
- data/lib/generators/ahoy/stores/templates/active_record_visits_migration.rb +5 -2
- data/lib/generators/ahoy/stores/templates/custom_initializer.rb +0 -2
- data/lib/generators/ahoy/stores/templates/fluentd_initializer.rb +3 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb1cce9c5947f97e0a19216e9427447c769c580d
|
4
|
+
data.tar.gz: 736da048bedafb0038ae932c1f76993941d6e95a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c05c1549e95925259447087b65a03351f29b82d99a47790e799f075bfceddafb49d5c20b5f4f20f0f5ac2469739749c56aec74dfa96b7a1f3a5d887a2091a79c
|
7
|
+
data.tar.gz: 62ee3cb9f38fdf312b7992bbb41df8ca5341f43743e308973ac71f57ad97a91d5c9225ee0364b165d6886da28613cce2125fc25a46014564e341ac5d41e3e70f
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# Ahoy
|
2
2
|
|
3
|
+
:fire: Never build an analytics platform from scratch again.
|
4
|
+
|
3
5
|
Ahoy provides a solid foundation to track visits and events in Ruby, JavaScript, and native apps.
|
4
6
|
|
5
|
-
|
7
|
+
Works with any data store so you can easily scale.
|
6
8
|
|
7
|
-
:
|
9
|
+
:tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
|
8
10
|
|
9
|
-
|
11
|
+
:postbox: To track emails, check out [Ahoy Email](https://github.com/ankane/ahoy_email).
|
10
12
|
|
11
13
|
See [upgrade instructions](#upgrading) on how to move to 1.0.
|
12
14
|
|
@@ -27,9 +29,26 @@ And add the javascript file in `app/assets/javascripts/application.js` after jQu
|
|
27
29
|
|
28
30
|
## Choose a Data Store
|
29
31
|
|
32
|
+
Ahoy supports a number of data stores out of the box. You can start with one of them and customize as needed, or create your own store from scratch.
|
33
|
+
|
34
|
+
- [PostgreSQL](#PostgreSQL)
|
35
|
+
- [MySQL](#MySQL-or-SQLite)
|
36
|
+
- [SQLite](#MySQL-or-SQLite)
|
37
|
+
- [MongoDB](#MongoDB)
|
38
|
+
- [Fluentd](#Fluentd)
|
39
|
+
- [Logs](#Logs)
|
40
|
+
- [Custom](#Custom)
|
41
|
+
|
30
42
|
### PostgreSQL
|
31
43
|
|
32
|
-
For Rails 4 and PostgreSQL 9.
|
44
|
+
For Rails 4 and PostgreSQL 9.4 or greater, use:
|
45
|
+
|
46
|
+
```sh
|
47
|
+
rails generate ahoy:stores:active_record -d postgresql-jsonb
|
48
|
+
rake db:migrate
|
49
|
+
```
|
50
|
+
|
51
|
+
For Rails 4 and PostgreSQL 9.2 and 9.3, use:
|
33
52
|
|
34
53
|
```sh
|
35
54
|
rails generate ahoy:stores:active_record -d postgresql
|
@@ -60,12 +79,28 @@ rails generate ahoy:stores:active_record_visits
|
|
60
79
|
rake db:migrate
|
61
80
|
```
|
62
81
|
|
63
|
-
###
|
82
|
+
### MongoDB
|
64
83
|
|
65
84
|
```sh
|
66
85
|
rails generate ahoy:stores:mongoid
|
67
86
|
```
|
68
87
|
|
88
|
+
### Fluentd
|
89
|
+
|
90
|
+
Add [fluent-logger](https://github.com/fluent/fluent-logger-ruby) to your Gemfile.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
gem 'fluent-logger'
|
94
|
+
```
|
95
|
+
|
96
|
+
And run:
|
97
|
+
|
98
|
+
```sh
|
99
|
+
rails generate ahoy:stores:fluentd
|
100
|
+
```
|
101
|
+
|
102
|
+
Use `ENV["FLUENTD_HOST"]` and `ENV["FLUENTD_PORT"]` to configure.
|
103
|
+
|
69
104
|
### Logs
|
70
105
|
|
71
106
|
```sh
|
@@ -297,7 +332,7 @@ Ahoy.visit_duration = 30.minutes
|
|
297
332
|
|
298
333
|
### ActiveRecord
|
299
334
|
|
300
|
-
Let’s associate orders with visits.
|
335
|
+
Let’s associate orders with visits. Add a `visit_id` column on orders and do:
|
301
336
|
|
302
337
|
```ruby
|
303
338
|
class Order < ActiveRecord::Base
|
@@ -584,7 +619,8 @@ end
|
|
584
619
|
|
585
620
|
## TODO
|
586
621
|
|
587
|
-
-
|
622
|
+
- real-time dashboard of visits and events
|
623
|
+
- more events for append only stores
|
588
624
|
- turn off modules
|
589
625
|
|
590
626
|
## No Ruby?
|
data/Rakefile
CHANGED
data/ahoy_matey.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "ahoy/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "ahoy_matey"
|
8
8
|
spec.version = Ahoy::VERSION
|
9
9
|
spec.authors = ["Andrew Kane"]
|
10
10
|
spec.email = ["andrew@chartkick.com"]
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
11
|
+
spec.summary = "Simple, powerful visit tracking for Rails"
|
12
|
+
spec.description = "Simple, powerful visit tracking for Rails"
|
13
13
|
spec.homepage = "https://github.com/ankane/ahoy"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
data/lib/ahoy.rb
CHANGED
@@ -22,7 +22,9 @@ require "ahoy/stores/base_store"
|
|
22
22
|
require "ahoy/stores/active_record_store"
|
23
23
|
require "ahoy/stores/active_record_token_store"
|
24
24
|
require "ahoy/stores/log_store"
|
25
|
+
require "ahoy/stores/fluentd_store"
|
25
26
|
require "ahoy/stores/mongoid_store"
|
27
|
+
require "ahoy/logger_silencer"
|
26
28
|
require "ahoy/engine"
|
27
29
|
require "ahoy/warden" if defined?(Warden)
|
28
30
|
|
@@ -82,3 +84,10 @@ end
|
|
82
84
|
|
83
85
|
ActionController::Base.send :include, Ahoy::Controller
|
84
86
|
ActiveRecord::Base.send(:extend, Ahoy::Model) if defined?(ActiveRecord)
|
87
|
+
|
88
|
+
Logger.send :include, Ahoy::LoggerSilencer
|
89
|
+
|
90
|
+
begin
|
91
|
+
require "syslog/logger"
|
92
|
+
Syslog::Logger.send :include, Ahoy::LoggerSilencer
|
93
|
+
rescue LoadError; end
|
data/lib/ahoy/controller.rb
CHANGED
@@ -2,7 +2,6 @@ require "request_store"
|
|
2
2
|
|
3
3
|
module Ahoy
|
4
4
|
module Controller
|
5
|
-
|
6
5
|
def self.included(base)
|
7
6
|
base.helper_method :current_visit
|
8
7
|
base.helper_method :ahoy
|
@@ -31,6 +30,5 @@ module Ahoy
|
|
31
30
|
ahoy.track_visit(defer: !Ahoy.track_visits_immediately)
|
32
31
|
end
|
33
32
|
end
|
34
|
-
|
35
33
|
end
|
36
34
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Ahoy
|
2
2
|
module Deckhands
|
3
3
|
class LocationDeckhand
|
4
|
-
|
5
4
|
def initialize(ip)
|
6
5
|
@ip = ip
|
7
6
|
end
|
@@ -14,14 +13,26 @@ module Ahoy
|
|
14
13
|
location.try(:state).presence
|
15
14
|
end
|
16
15
|
|
16
|
+
def postal_code
|
17
|
+
location.try(:postal_code).presence
|
18
|
+
end
|
19
|
+
|
17
20
|
def city
|
18
21
|
location.try(:city).presence
|
19
22
|
end
|
20
23
|
|
24
|
+
def latitude
|
25
|
+
location.try(:latitude).presence
|
26
|
+
end
|
27
|
+
|
28
|
+
def longitude
|
29
|
+
location.try(:longitude).presence
|
30
|
+
end
|
31
|
+
|
21
32
|
protected
|
22
33
|
|
23
34
|
def location
|
24
|
-
|
35
|
+
unless @checked
|
25
36
|
@location =
|
26
37
|
begin
|
27
38
|
Geocoder.search(@ip).first
|
@@ -33,7 +44,6 @@ module Ahoy
|
|
33
44
|
end
|
34
45
|
@location
|
35
46
|
end
|
36
|
-
|
37
47
|
end
|
38
48
|
end
|
39
49
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Ahoy
|
2
2
|
module Deckhands
|
3
3
|
class TechnologyDeckhand
|
4
|
-
|
5
4
|
def initialize(user_agent)
|
6
5
|
@user_agent = user_agent
|
7
6
|
end
|
@@ -43,7 +42,6 @@ module Ahoy
|
|
43
42
|
def self.user_agent_parser
|
44
43
|
@user_agent_parser ||= UserAgentParser::Parser.new
|
45
44
|
end
|
46
|
-
|
47
45
|
end
|
48
46
|
end
|
49
47
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Ahoy
|
2
2
|
module Deckhands
|
3
3
|
class TrafficSourceDeckhand
|
4
|
-
|
5
4
|
def initialize(referrer)
|
6
5
|
@referrer = referrer
|
7
6
|
end
|
@@ -18,7 +17,6 @@ module Ahoy
|
|
18
17
|
def self.referrer_parser
|
19
18
|
@referrer_parser ||= RefererParser::Parser.new
|
20
19
|
end
|
21
|
-
|
22
20
|
end
|
23
21
|
end
|
24
22
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Ahoy
|
2
2
|
module Deckhands
|
3
3
|
class UtmParameterDeckhand
|
4
|
-
|
5
4
|
def initialize(landing_page)
|
6
5
|
@landing_page = landing_page
|
7
6
|
end
|
@@ -13,12 +12,11 @@ module Ahoy
|
|
13
12
|
end
|
14
13
|
end
|
15
14
|
|
16
|
-
%w
|
15
|
+
%w(utm_source utm_medium utm_term utm_content utm_campaign).each do |name|
|
17
16
|
define_method name do
|
18
17
|
landing_params[name]
|
19
18
|
end
|
20
19
|
end
|
21
|
-
|
22
20
|
end
|
23
21
|
end
|
24
22
|
end
|
data/lib/ahoy/engine.rb
CHANGED
@@ -1,30 +1,25 @@
|
|
1
1
|
module Ahoy
|
2
2
|
class Engine < ::Rails::Engine
|
3
|
-
|
4
3
|
# from https://github.com/evrone/quiet_assets/blob/master/lib/quiet_assets.rb
|
5
|
-
initializer "ahoy.middleware", after: "sprockets.environment" do
|
4
|
+
initializer "ahoy.middleware", after: "sprockets.environment" do
|
6
5
|
next unless Ahoy.quiet
|
7
6
|
|
8
7
|
# Parse PATH_INFO by assets prefix
|
9
|
-
AHOY_PREFIX = "/ahoy/"
|
10
|
-
KEY = "ahoy.old_level"
|
8
|
+
AHOY_PREFIX = "/ahoy/".freeze
|
11
9
|
|
12
10
|
# Just create an alias for call in middleware
|
13
11
|
Rails::Rack::Logger.class_eval do
|
14
12
|
def call_with_quiet_ahoy(env)
|
15
|
-
|
16
|
-
|
17
|
-
env
|
18
|
-
Rails.logger.level = Logger::ERROR
|
13
|
+
if env["PATH_INFO"].start_with?(AHOY_PREFIX) && logger.respond_to?(:silence_logger)
|
14
|
+
logger.silence_logger do
|
15
|
+
call_without_quiet_ahoy(env)
|
19
16
|
end
|
17
|
+
else
|
20
18
|
call_without_quiet_ahoy(env)
|
21
|
-
ensure
|
22
|
-
Rails.logger.level = env[KEY] if env[KEY]
|
23
19
|
end
|
24
20
|
end
|
25
21
|
alias_method_chain :call, :quiet_ahoy
|
26
22
|
end
|
27
23
|
end
|
28
|
-
|
29
24
|
end
|
30
25
|
end
|
data/lib/ahoy/geocode_job.rb
CHANGED
@@ -0,0 +1,73 @@
|
|
1
|
+
# from https://github.com/rails/activerecord-session_store/blob/master/lib/active_record/session_store/extension/logger_silencer.rb
|
2
|
+
require "thread"
|
3
|
+
require "active_support/core_ext/class/attribute_accessors"
|
4
|
+
require "active_support/core_ext/module/aliasing"
|
5
|
+
require "active_support/core_ext/module/attribute_accessors"
|
6
|
+
require "active_support/concern"
|
7
|
+
|
8
|
+
module Ahoy
|
9
|
+
module LoggerSilencer
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
included do
|
13
|
+
cattr_accessor :silencer
|
14
|
+
self.silencer = true
|
15
|
+
alias_method_chain :level, :threadsafety
|
16
|
+
alias_method_chain :add, :threadsafety
|
17
|
+
end
|
18
|
+
|
19
|
+
def thread_level
|
20
|
+
Thread.current[thread_hash_level_key]
|
21
|
+
end
|
22
|
+
|
23
|
+
def thread_level=(level)
|
24
|
+
Thread.current[thread_hash_level_key] = level
|
25
|
+
end
|
26
|
+
|
27
|
+
def level_with_threadsafety
|
28
|
+
thread_level || level_without_threadsafety
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_with_threadsafety(severity, message = nil, progname = nil, &block)
|
32
|
+
if !defined?(@logdev) || @logdev.nil? || (severity || UNKNOWN) < level
|
33
|
+
true
|
34
|
+
else
|
35
|
+
add_without_threadsafety(severity, message, progname, &block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Silences the logger for the duration of the block.
|
40
|
+
def silence_logger(temporary_level = Logger::ERROR)
|
41
|
+
if silencer
|
42
|
+
begin
|
43
|
+
self.thread_level = temporary_level
|
44
|
+
yield self
|
45
|
+
ensure
|
46
|
+
self.thread_level = nil
|
47
|
+
end
|
48
|
+
else
|
49
|
+
yield self
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
for severity in Logger::Severity.constants
|
54
|
+
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
55
|
+
def #{severity.downcase}? # def debug?
|
56
|
+
Logger::#{severity} >= level # DEBUG >= level
|
57
|
+
end # end
|
58
|
+
EOT
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def thread_hash_level_key
|
64
|
+
@thread_hash_level_key ||= :"ThreadSafeLogger##{object_id}@level"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class NilLogger
|
70
|
+
def self.silence_logger
|
71
|
+
yield
|
72
|
+
end
|
73
|
+
end
|
data/lib/ahoy/model.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
module Ahoy
|
2
2
|
module Model
|
3
|
-
|
4
3
|
def visitable(name = nil, options = {})
|
5
4
|
if name.is_a?(Hash)
|
6
5
|
name = nil
|
@@ -11,7 +10,7 @@ module Ahoy
|
|
11
10
|
belongs_to name, options
|
12
11
|
before_create :set_visit
|
13
12
|
end
|
14
|
-
class_eval %
|
13
|
+
class_eval %{
|
15
14
|
def set_visit
|
16
15
|
self.#{name} ||= RequestStore.store[:ahoy].try(:visit)
|
17
16
|
end
|
@@ -32,9 +31,7 @@ module Ahoy
|
|
32
31
|
Deckhands::UtmParameterDeckhand.new(landing_page).landing_params
|
33
32
|
end
|
34
33
|
end
|
35
|
-
|
36
34
|
end
|
37
35
|
end
|
38
|
-
|
39
36
|
end
|
40
37
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Ahoy
|
2
2
|
module Stores
|
3
3
|
class ActiveRecordStore < BaseStore
|
4
|
-
|
5
4
|
def track_visit(options, &block)
|
6
5
|
visit =
|
7
6
|
visit_model.new do |v|
|
@@ -28,7 +27,7 @@ module Ahoy
|
|
28
27
|
event_model.new do |e|
|
29
28
|
e.id = options[:id]
|
30
29
|
e.visit_id = ahoy.visit_id
|
31
|
-
e.user = user
|
30
|
+
e.user = user if e.respond_to?(:user=)
|
32
31
|
e.name = name
|
33
32
|
e.properties = properties
|
34
33
|
e.time = options[:time]
|
@@ -56,7 +55,6 @@ module Ahoy
|
|
56
55
|
def event_model
|
57
56
|
::Ahoy::Event
|
58
57
|
end
|
59
|
-
|
60
58
|
end
|
61
59
|
end
|
62
60
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Ahoy
|
2
2
|
module Stores
|
3
3
|
class ActiveRecordTokenStore < BaseStore
|
4
|
-
|
5
4
|
def track_visit(options, &block)
|
6
5
|
visit =
|
7
6
|
visit_model.new do |v|
|
@@ -61,18 +60,18 @@ module Ahoy
|
|
61
60
|
|
62
61
|
def exclude?
|
63
62
|
(!Ahoy.track_bots && bot?) ||
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
63
|
+
(
|
64
|
+
if Ahoy.exclude_method
|
65
|
+
warn "[DEPRECATION] Ahoy.exclude_method is deprecated - use exclude? instead"
|
66
|
+
if Ahoy.exclude_method.arity == 1
|
67
|
+
Ahoy.exclude_method.call(controller)
|
68
|
+
else
|
69
|
+
Ahoy.exclude_method.call(controller, request)
|
70
|
+
end
|
69
71
|
else
|
70
|
-
|
72
|
+
false
|
71
73
|
end
|
72
|
-
|
73
|
-
false
|
74
|
-
end
|
75
|
-
)
|
74
|
+
)
|
76
75
|
end
|
77
76
|
|
78
77
|
def user
|
@@ -89,7 +88,6 @@ module Ahoy
|
|
89
88
|
end
|
90
89
|
|
91
90
|
class << self
|
92
|
-
|
93
91
|
def uses_deprecated_subscribers
|
94
92
|
warn "[DEPRECATION] Ahoy subscribers are deprecated"
|
95
93
|
@uses_deprecated_subscribers = true
|
@@ -98,7 +96,6 @@ module Ahoy
|
|
98
96
|
def uses_deprecated_subscribers?
|
99
97
|
@uses_deprecated_subscribers || false
|
100
98
|
end
|
101
|
-
|
102
99
|
end
|
103
100
|
|
104
101
|
protected
|
@@ -110,7 +107,6 @@ module Ahoy
|
|
110
107
|
def event_model
|
111
108
|
::Ahoy::Event
|
112
109
|
end
|
113
|
-
|
114
110
|
end
|
115
111
|
end
|
116
112
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Ahoy
|
2
2
|
module Stores
|
3
3
|
class BaseStore
|
4
|
-
|
5
4
|
def initialize(options)
|
6
5
|
@options = options
|
7
6
|
end
|
@@ -17,7 +16,7 @@ module Ahoy
|
|
17
16
|
|
18
17
|
def authenticate(user)
|
19
18
|
@user = user
|
20
|
-
if visit
|
19
|
+
if visit && visit.respond_to?(:user) && !visit.user
|
21
20
|
begin
|
22
21
|
visit.user = user
|
23
22
|
visit.save!
|
@@ -84,7 +83,6 @@ module Ahoy
|
|
84
83
|
classes << PG::UniqueViolation if defined?(PG::UniqueViolation)
|
85
84
|
classes
|
86
85
|
end
|
87
|
-
|
88
86
|
end
|
89
87
|
end
|
90
88
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Ahoy
|
2
|
+
module Stores
|
3
|
+
class FluentdStore < LogStore
|
4
|
+
def log_visit(data)
|
5
|
+
logger.post("visit", data)
|
6
|
+
end
|
7
|
+
|
8
|
+
def log_event(data)
|
9
|
+
logger.post("event", data)
|
10
|
+
end
|
11
|
+
|
12
|
+
def logger
|
13
|
+
@logger ||= Fluent::Logger::FluentLogger.new("ahoy", host: ENV["FLUENTD_HOST"] || "localhost", port: ENV["FLUENTD_PORT"] || 24224)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,18 +1,17 @@
|
|
1
1
|
module Ahoy
|
2
2
|
module Stores
|
3
3
|
class LogStore < BaseStore
|
4
|
-
|
5
4
|
def track_visit(options, &block)
|
6
5
|
data = {
|
7
6
|
id: ahoy.visit_id,
|
8
|
-
visitor_id: ahoy.visitor_id
|
7
|
+
visitor_id: ahoy.visitor_id
|
9
8
|
}.merge(visit_properties.to_hash)
|
10
9
|
data[:user_id] = user.id if user
|
11
10
|
data[:started_at] = options[:started_at]
|
12
11
|
|
13
12
|
yield(data) if block_given?
|
14
13
|
|
15
|
-
|
14
|
+
log_visit(data)
|
16
15
|
end
|
17
16
|
|
18
17
|
def track_event(name, properties, options, &block)
|
@@ -28,11 +27,19 @@ module Ahoy
|
|
28
27
|
|
29
28
|
yield(data) if block_given?
|
30
29
|
|
31
|
-
|
30
|
+
log_event(data)
|
32
31
|
end
|
33
32
|
|
34
33
|
protected
|
35
34
|
|
35
|
+
def log_visit(data)
|
36
|
+
visit_logger.info data.to_json
|
37
|
+
end
|
38
|
+
|
39
|
+
def log_event(data)
|
40
|
+
event_logger.info data.to_json
|
41
|
+
end
|
42
|
+
|
36
43
|
# TODO disable header
|
37
44
|
def visit_logger
|
38
45
|
@visit_logger ||= ActiveSupport::Logger.new(Rails.root.join("log/visits.log"))
|
@@ -41,7 +48,6 @@ module Ahoy
|
|
41
48
|
def event_logger
|
42
49
|
@event_logger ||= ActiveSupport::Logger.new(Rails.root.join("log/events.log"))
|
43
50
|
end
|
44
|
-
|
45
51
|
end
|
46
52
|
end
|
47
53
|
end
|
data/lib/ahoy/tracker.rb
CHANGED
@@ -10,7 +10,9 @@ module Ahoy
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def track(name, properties = {}, options = {})
|
13
|
-
|
13
|
+
if exclude?
|
14
|
+
debug "Event excluded"
|
15
|
+
else
|
14
16
|
options = options.dup
|
15
17
|
|
16
18
|
options[:time] = trusted_time(options[:time])
|
@@ -24,7 +26,9 @@ module Ahoy
|
|
24
26
|
end
|
25
27
|
|
26
28
|
def track_visit(options = {})
|
27
|
-
|
29
|
+
if exclude?
|
30
|
+
debug "Visit excluded"
|
31
|
+
else
|
28
32
|
if options[:defer]
|
29
33
|
set_cookie("ahoy_track", true)
|
30
34
|
else
|
@@ -41,7 +45,9 @@ module Ahoy
|
|
41
45
|
end
|
42
46
|
|
43
47
|
def authenticate(user)
|
44
|
-
|
48
|
+
if exclude?
|
49
|
+
debug "Authentication excluded"
|
50
|
+
else
|
45
51
|
@store.authenticate(user)
|
46
52
|
end
|
47
53
|
true
|
@@ -70,7 +76,7 @@ module Ahoy
|
|
70
76
|
end
|
71
77
|
|
72
78
|
def set_visitor_cookie
|
73
|
-
|
79
|
+
unless existing_visitor_id
|
74
80
|
set_cookie("ahoy_visitor", visitor_id, Ahoy.visitor_duration)
|
75
81
|
end
|
76
82
|
end
|
@@ -107,7 +113,7 @@ module Ahoy
|
|
107
113
|
end
|
108
114
|
|
109
115
|
def trusted_time(time)
|
110
|
-
if !time
|
116
|
+
if !time || (@options[:api] && !(1.minute.ago..Time.now).cover?(time))
|
111
117
|
Time.zone.now
|
112
118
|
else
|
113
119
|
time
|
@@ -146,5 +152,8 @@ module Ahoy
|
|
146
152
|
Ahoy.ensure_uuid(id)
|
147
153
|
end
|
148
154
|
|
155
|
+
def debug(message)
|
156
|
+
Rails.logger.debug { "[ahoy] #{message}" }
|
157
|
+
end
|
149
158
|
end
|
150
159
|
end
|
data/lib/ahoy/version.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
module Ahoy
|
2
2
|
class VisitProperties
|
3
|
-
|
4
3
|
REQUEST_KEYS = [:ip, :user_agent, :referrer, :landing_page, :platform, :app_version, :os_version, :screen_height, :screen_width]
|
5
4
|
TRAFFIC_SOURCE_KEYS = [:referring_domain, :search_keyword]
|
6
5
|
UTM_PARAMETER_KEYS = [:utm_source, :utm_medium, :utm_term, :utm_content, :utm_campaign]
|
7
6
|
TECHNOLOGY_KEYS = [:browser, :os, :device_type]
|
8
|
-
LOCATION_KEYS = [:country, :region, :city]
|
7
|
+
LOCATION_KEYS = [:country, :region, :city, :postal_code, :latitude, :longitude]
|
9
8
|
|
10
9
|
KEYS = REQUEST_KEYS + TRAFFIC_SOURCE_KEYS + UTM_PARAMETER_KEYS + TECHNOLOGY_KEYS + LOCATION_KEYS
|
11
10
|
|
@@ -33,7 +32,7 @@ module Ahoy
|
|
33
32
|
end
|
34
33
|
|
35
34
|
def to_hash
|
36
|
-
keys.inject({}){|memo, key| memo[key] = send(key); memo }
|
35
|
+
keys.inject({}) { |memo, key| memo[key] = send(key); memo }
|
37
36
|
end
|
38
37
|
|
39
38
|
protected
|
@@ -57,6 +56,5 @@ module Ahoy
|
|
57
56
|
def location_deckhand
|
58
57
|
@location_deckhand ||= Deckhands::LocationDeckhand.new(request_deckhand.ip)
|
59
58
|
end
|
60
|
-
|
61
59
|
end
|
62
60
|
end
|
data/lib/ahoy/warden.rb
CHANGED
@@ -24,7 +24,7 @@ module Ahoy
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def copy_migration
|
27
|
-
unless options["database"].in?([nil, "postgresql"])
|
27
|
+
unless options["database"].in?([nil, "postgresql", "postgresql-jsonb"])
|
28
28
|
raise Thor::Error, "Unknown database option"
|
29
29
|
end
|
30
30
|
migration_template "active_record_events_migration.rb", "db/migrate/create_ahoy_events.rb"
|
@@ -37,7 +37,6 @@ module Ahoy
|
|
37
37
|
def create_initializer
|
38
38
|
template "active_record_initializer.rb", "config/initializers/ahoy.rb"
|
39
39
|
end
|
40
|
-
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
@@ -24,7 +24,7 @@ module Ahoy
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def copy_migration
|
27
|
-
unless options["database"].in?([nil, "postgresql"])
|
27
|
+
unless options["database"].in?([nil, "postgresql", "postgresql-jsonb"])
|
28
28
|
raise Thor::Error, "Unknown database option"
|
29
29
|
end
|
30
30
|
migration_template "active_record_visits_migration.rb", "db/migrate/create_visits.rb"
|
@@ -37,7 +37,6 @@ module Ahoy
|
|
37
37
|
def create_initializer
|
38
38
|
template "active_record_initializer.rb", "config/initializers/ahoy.rb"
|
39
39
|
end
|
40
|
-
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
|
3
|
+
module Ahoy
|
4
|
+
module Stores
|
5
|
+
module Generators
|
6
|
+
class FluentdGenerator < Rails::Generators::Base
|
7
|
+
source_root File.expand_path("../templates", __FILE__)
|
8
|
+
|
9
|
+
def create_initializer
|
10
|
+
template "fluentd_initializer.rb", "config/initializers/ahoy.rb"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
class <%= migration_class_name %> < ActiveRecord::Migration
|
2
2
|
def change
|
3
3
|
create_table :ahoy_events, id: false do |t|
|
4
|
-
t.uuid :id, primary_key: true
|
5
|
-
t.uuid :visit_id
|
4
|
+
t.uuid :id, default: nil, primary_key: true
|
5
|
+
t.uuid :visit_id, default: nil
|
6
6
|
|
7
7
|
# user
|
8
8
|
t.integer :user_id
|
9
9
|
# add t.string :user_type if polymorphic
|
10
10
|
|
11
11
|
t.string :name
|
12
|
-
t.<%
|
12
|
+
t.<% case options["database"] when "postgresql" %>json<% when "postgresql-jsonb" %>jsonb<% else %>text<% end %> :properties
|
13
13
|
t.timestamp :time
|
14
14
|
end
|
15
15
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
class <%= migration_class_name %> < ActiveRecord::Migration
|
2
2
|
def change
|
3
3
|
create_table :visits, id: false do |t|
|
4
|
-
t.uuid :id, primary_key: true
|
5
|
-
t.uuid :visitor_id
|
4
|
+
t.uuid :id, default: nil, primary_key: true
|
5
|
+
t.uuid :visitor_id, default: nil
|
6
6
|
|
7
7
|
# the rest are recommended but optional
|
8
8
|
# simply remove the columns you don't want
|
@@ -32,6 +32,9 @@ class <%= migration_class_name %> < ActiveRecord::Migration
|
|
32
32
|
t.string :country
|
33
33
|
t.string :region
|
34
34
|
t.string :city
|
35
|
+
t.string :postal_code
|
36
|
+
t.decimal :latitude
|
37
|
+
t.decimal :longitude
|
35
38
|
|
36
39
|
# utm parameters
|
37
40
|
t.string :utm_source
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ahoy_matey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -205,10 +205,12 @@ files:
|
|
205
205
|
- lib/ahoy/deckhands/utm_parameter_deckhand.rb
|
206
206
|
- lib/ahoy/engine.rb
|
207
207
|
- lib/ahoy/geocode_job.rb
|
208
|
+
- lib/ahoy/logger_silencer.rb
|
208
209
|
- lib/ahoy/model.rb
|
209
210
|
- lib/ahoy/stores/active_record_store.rb
|
210
211
|
- lib/ahoy/stores/active_record_token_store.rb
|
211
212
|
- lib/ahoy/stores/base_store.rb
|
213
|
+
- lib/ahoy/stores/fluentd_store.rb
|
212
214
|
- lib/ahoy/stores/log_store.rb
|
213
215
|
- lib/ahoy/stores/mongoid_store.rb
|
214
216
|
- lib/ahoy/subscribers/active_record.rb
|
@@ -221,6 +223,7 @@ files:
|
|
221
223
|
- lib/generators/ahoy/stores/active_record_generator.rb
|
222
224
|
- lib/generators/ahoy/stores/active_record_visits_generator.rb
|
223
225
|
- lib/generators/ahoy/stores/custom_generator.rb
|
226
|
+
- lib/generators/ahoy/stores/fluentd_generator.rb
|
224
227
|
- lib/generators/ahoy/stores/log_generator.rb
|
225
228
|
- lib/generators/ahoy/stores/mongoid_events_generator.rb
|
226
229
|
- lib/generators/ahoy/stores/mongoid_generator.rb
|
@@ -231,6 +234,7 @@ files:
|
|
231
234
|
- lib/generators/ahoy/stores/templates/active_record_visit_model.rb
|
232
235
|
- lib/generators/ahoy/stores/templates/active_record_visits_migration.rb
|
233
236
|
- lib/generators/ahoy/stores/templates/custom_initializer.rb
|
237
|
+
- lib/generators/ahoy/stores/templates/fluentd_initializer.rb
|
234
238
|
- lib/generators/ahoy/stores/templates/log_initializer.rb
|
235
239
|
- lib/generators/ahoy/stores/templates/mongoid_event_model.rb
|
236
240
|
- lib/generators/ahoy/stores/templates/mongoid_initializer.rb
|
@@ -258,10 +262,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
258
262
|
version: '0'
|
259
263
|
requirements: []
|
260
264
|
rubyforge_project:
|
261
|
-
rubygems_version: 2.
|
265
|
+
rubygems_version: 2.4.5
|
262
266
|
signing_key:
|
263
267
|
specification_version: 4
|
264
268
|
summary: Simple, powerful visit tracking for Rails
|
265
269
|
test_files:
|
266
270
|
- test/test_helper.rb
|
267
271
|
- test/visit_properties_test.rb
|
272
|
+
has_rdoc:
|