ahoy_matey 1.1.1 → 1.2.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 +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:
|