ahoy_matey 1.6.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE.md +7 -0
- data/CHANGELOG.md +22 -0
- data/CONTRIBUTING.md +40 -0
- data/LICENSE.txt +1 -1
- data/README.md +210 -489
- data/Rakefile +1 -0
- data/ahoy_matey.gemspec +6 -8
- data/app/controllers/ahoy/base_controller.rb +2 -6
- data/app/controllers/ahoy/events_controller.rb +7 -1
- data/app/controllers/ahoy/visits_controller.rb +7 -1
- data/app/jobs/ahoy/geocode_job.rb +10 -0
- data/app/jobs/ahoy/geocode_v2_job.rb +29 -0
- data/config/routes.rb +1 -1
- data/docs/Ahoy-2-Upgrade.md +147 -0
- data/docs/Data-Store-Examples.md +240 -0
- data/lib/ahoy.rb +30 -88
- data/lib/ahoy/base_store.rb +72 -0
- data/lib/ahoy/controller.rb +4 -10
- data/lib/ahoy/database_store.rb +72 -0
- data/lib/ahoy/engine.rb +5 -7
- data/lib/ahoy/model.rb +4 -26
- data/lib/ahoy/{properties.rb → query_methods.rb} +18 -4
- data/lib/ahoy/tracker.rb +60 -38
- data/lib/ahoy/version.rb +1 -1
- data/lib/ahoy/visit_properties.rb +65 -39
- data/lib/generators/ahoy/activerecord_generator.rb +58 -0
- data/lib/generators/ahoy/base_generator.rb +13 -0
- data/lib/generators/ahoy/install_generator.rb +44 -0
- data/lib/generators/ahoy/mongoid_generator.rb +20 -0
- data/lib/generators/ahoy/templates/active_record_event_model.rb +10 -0
- data/lib/generators/ahoy/{stores/templates/active_record_visits_migration.rb → templates/active_record_migration.rb} +19 -21
- data/lib/generators/ahoy/templates/active_record_visit_model.rb +6 -0
- data/lib/generators/ahoy/templates/base_store_initializer.rb +17 -0
- data/lib/generators/ahoy/templates/database_store_initializer.rb +5 -0
- data/lib/generators/ahoy/{stores/templates → templates}/mongoid_event_model.rb +4 -2
- data/lib/generators/ahoy/{stores/templates → templates}/mongoid_visit_model.rb +7 -3
- data/test/query_methods/mongoid_test.rb +23 -0
- data/test/{properties → query_methods}/mysql_json_test.rb +1 -1
- data/test/{properties → query_methods}/mysql_text_test.rb +1 -1
- data/test/{properties → query_methods}/postgresql_hstore_test.rb +1 -1
- data/test/{properties → query_methods}/postgresql_json_test.rb +1 -1
- data/test/{properties → query_methods}/postgresql_jsonb_test.rb +1 -1
- data/test/{properties → query_methods}/postgresql_text_test.rb +1 -1
- data/test/test_helper.rb +4 -3
- data/vendor/assets/javascripts/ahoy.js +551 -325
- metadata +67 -112
- data/lib/ahoy/deckhands/location_deckhand.rb +0 -49
- data/lib/ahoy/deckhands/request_deckhand.rb +0 -52
- data/lib/ahoy/deckhands/technology_deckhand.rb +0 -47
- data/lib/ahoy/deckhands/traffic_source_deckhand.rb +0 -22
- data/lib/ahoy/deckhands/utm_parameter_deckhand.rb +0 -23
- data/lib/ahoy/geocode_job.rb +0 -13
- data/lib/ahoy/logger_silencer.rb +0 -75
- data/lib/ahoy/stores/active_record_store.rb +0 -61
- data/lib/ahoy/stores/active_record_token_store.rb +0 -114
- data/lib/ahoy/stores/base_store.rb +0 -88
- data/lib/ahoy/stores/bunny_store.rb +0 -33
- data/lib/ahoy/stores/fluentd_store.rb +0 -17
- data/lib/ahoy/stores/kafka_store.rb +0 -42
- data/lib/ahoy/stores/kinesis_firehose_store.rb +0 -42
- data/lib/ahoy/stores/log_store.rb +0 -53
- data/lib/ahoy/stores/mongoid_store.rb +0 -63
- data/lib/ahoy/stores/nats_store.rb +0 -34
- data/lib/ahoy/stores/nsq_store.rb +0 -36
- data/lib/ahoy/subscribers/active_record.rb +0 -19
- data/lib/ahoy/throttle.rb +0 -17
- data/lib/generators/ahoy/stores/active_record_events_generator.rb +0 -59
- data/lib/generators/ahoy/stores/active_record_generator.rb +0 -16
- data/lib/generators/ahoy/stores/active_record_visits_generator.rb +0 -49
- data/lib/generators/ahoy/stores/bunny_generator.rb +0 -15
- data/lib/generators/ahoy/stores/custom_generator.rb +0 -15
- data/lib/generators/ahoy/stores/fluentd_generator.rb +0 -15
- data/lib/generators/ahoy/stores/kafka_generator.rb +0 -15
- data/lib/generators/ahoy/stores/kinesis_firehose_generator.rb +0 -15
- data/lib/generators/ahoy/stores/log_generator.rb +0 -15
- data/lib/generators/ahoy/stores/mongoid_events_generator.rb +0 -19
- data/lib/generators/ahoy/stores/mongoid_generator.rb +0 -14
- data/lib/generators/ahoy/stores/mongoid_visits_generator.rb +0 -27
- data/lib/generators/ahoy/stores/nats_generator.rb +0 -15
- data/lib/generators/ahoy/stores/nsq_generator.rb +0 -15
- data/lib/generators/ahoy/stores/templates/active_record_event_model.rb +0 -12
- data/lib/generators/ahoy/stores/templates/active_record_events_migration.rb +0 -20
- data/lib/generators/ahoy/stores/templates/active_record_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/active_record_visit_model.rb +0 -4
- data/lib/generators/ahoy/stores/templates/bunny_initializer.rb +0 -9
- data/lib/generators/ahoy/stores/templates/custom_initializer.rb +0 -10
- data/lib/generators/ahoy/stores/templates/fluentd_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/kafka_initializer.rb +0 -9
- data/lib/generators/ahoy/stores/templates/kinesis_firehose_initializer.rb +0 -17
- data/lib/generators/ahoy/stores/templates/log_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/mongoid_initializer.rb +0 -3
- data/lib/generators/ahoy/stores/templates/nats_initializer.rb +0 -9
- data/lib/generators/ahoy/stores/templates/nsq_initializer.rb +0 -9
- data/test/visit_properties_test.rb +0 -44
@@ -1,42 +0,0 @@
|
|
1
|
-
module Ahoy
|
2
|
-
module Stores
|
3
|
-
class KafkaStore < LogStore
|
4
|
-
def log_visit(data)
|
5
|
-
post(visits_topic, data)
|
6
|
-
end
|
7
|
-
|
8
|
-
def log_event(data)
|
9
|
-
post(events_topic, data)
|
10
|
-
end
|
11
|
-
|
12
|
-
def client
|
13
|
-
@client ||= begin
|
14
|
-
Kafka.new(
|
15
|
-
seed_brokers: ENV["KAFKA_URL"] || "localhost:9092",
|
16
|
-
logger: Rails.logger
|
17
|
-
)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def producer
|
22
|
-
@producer ||= begin
|
23
|
-
producer = client.async_producer(delivery_interval: 3)
|
24
|
-
at_exit { producer.shutdown }
|
25
|
-
producer
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def post(topic, data)
|
30
|
-
producer.produce(data.to_json, topic: topic)
|
31
|
-
end
|
32
|
-
|
33
|
-
def visits_topic
|
34
|
-
"ahoy_visits"
|
35
|
-
end
|
36
|
-
|
37
|
-
def events_topic
|
38
|
-
"ahoy_events"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module Ahoy
|
2
|
-
module Stores
|
3
|
-
class KinesisFirehoseStore < LogStore
|
4
|
-
def log_visit(data)
|
5
|
-
post(visits_stream, data)
|
6
|
-
end
|
7
|
-
|
8
|
-
def log_event(data)
|
9
|
-
post(events_stream, data)
|
10
|
-
end
|
11
|
-
|
12
|
-
def client
|
13
|
-
@client ||= Aws::Firehose::Client.new(credentials)
|
14
|
-
end
|
15
|
-
|
16
|
-
def post(stream, data)
|
17
|
-
client.put_record(
|
18
|
-
delivery_stream_name: stream,
|
19
|
-
record: {
|
20
|
-
data: "#{data.to_json}\n"
|
21
|
-
}
|
22
|
-
)
|
23
|
-
end
|
24
|
-
|
25
|
-
def credentials
|
26
|
-
{
|
27
|
-
access_key_id: ENV["AWS_ACCESS_KEY_ID"],
|
28
|
-
secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
|
29
|
-
region: "us-east-1"
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
|
-
def visits_stream
|
34
|
-
"ahoy_visits"
|
35
|
-
end
|
36
|
-
|
37
|
-
def events_stream
|
38
|
-
"ahoy_events"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module Ahoy
|
2
|
-
module Stores
|
3
|
-
class LogStore < BaseStore
|
4
|
-
def track_visit(options, &block)
|
5
|
-
data = {
|
6
|
-
id: ahoy.visit_id,
|
7
|
-
visitor_id: ahoy.visitor_id
|
8
|
-
}.merge(visit_properties.to_hash)
|
9
|
-
data[:user_id] = user.id if user
|
10
|
-
data[:started_at] = options[:started_at]
|
11
|
-
|
12
|
-
yield(data) if block_given?
|
13
|
-
|
14
|
-
log_visit(data)
|
15
|
-
end
|
16
|
-
|
17
|
-
def track_event(name, properties, options, &block)
|
18
|
-
data = {
|
19
|
-
id: options[:id],
|
20
|
-
name: name,
|
21
|
-
properties: properties,
|
22
|
-
visit_id: ahoy.visit_id,
|
23
|
-
visitor_id: ahoy.visitor_id
|
24
|
-
}
|
25
|
-
data[:user_id] = user.id if user
|
26
|
-
data[:time] = options[:time]
|
27
|
-
|
28
|
-
yield(data) if block_given?
|
29
|
-
|
30
|
-
log_event(data)
|
31
|
-
end
|
32
|
-
|
33
|
-
protected
|
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
|
-
|
43
|
-
# TODO disable header
|
44
|
-
def visit_logger
|
45
|
-
@visit_logger ||= ActiveSupport::Logger.new(Rails.root.join("log/visits.log"))
|
46
|
-
end
|
47
|
-
|
48
|
-
def event_logger
|
49
|
-
@event_logger ||= ActiveSupport::Logger.new(Rails.root.join("log/events.log"))
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
module Ahoy
|
2
|
-
module Stores
|
3
|
-
class MongoidStore < BaseStore
|
4
|
-
def track_visit(options, &block)
|
5
|
-
@visit =
|
6
|
-
visit_model.new do |v|
|
7
|
-
v.id = binary(ahoy.visit_id)
|
8
|
-
v.visitor_id = binary(ahoy.visitor_id)
|
9
|
-
v.user = user if v.respond_to?(:user=) && user
|
10
|
-
v.started_at = options[:started_at]
|
11
|
-
end
|
12
|
-
|
13
|
-
set_visit_properties(visit)
|
14
|
-
|
15
|
-
yield(visit) if block_given?
|
16
|
-
|
17
|
-
visit.upsert
|
18
|
-
geocode(visit)
|
19
|
-
end
|
20
|
-
|
21
|
-
def track_event(name, properties, options, &block)
|
22
|
-
event =
|
23
|
-
event_model.new do |e|
|
24
|
-
e.id = binary(options[:id])
|
25
|
-
e.visit_id = binary(ahoy.visit_id)
|
26
|
-
e.user = user if e.respond_to?(:user)
|
27
|
-
e.name = name
|
28
|
-
e.properties = properties
|
29
|
-
e.time = options[:time]
|
30
|
-
end
|
31
|
-
|
32
|
-
yield(event) if block_given?
|
33
|
-
|
34
|
-
event.upsert
|
35
|
-
end
|
36
|
-
|
37
|
-
def visit
|
38
|
-
@visit ||= visit_model.where(_id: binary(ahoy.visit_id)).first if ahoy.visit_id
|
39
|
-
end
|
40
|
-
|
41
|
-
protected
|
42
|
-
|
43
|
-
def visit_model
|
44
|
-
::Visit
|
45
|
-
end
|
46
|
-
|
47
|
-
def event_model
|
48
|
-
::Ahoy::Event
|
49
|
-
end
|
50
|
-
|
51
|
-
def binary(token)
|
52
|
-
token = token.delete("-")
|
53
|
-
if defined?(::BSON)
|
54
|
-
::BSON::Binary.new(token, :uuid)
|
55
|
-
elsif defined?(::Moped::BSON)
|
56
|
-
::Moped::BSON::Binary.new(:uuid, token)
|
57
|
-
else
|
58
|
-
token
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Ahoy
|
2
|
-
module Stores
|
3
|
-
class NatsStore < LogStore
|
4
|
-
def log_visit(data)
|
5
|
-
publish(visits_subject, data)
|
6
|
-
end
|
7
|
-
|
8
|
-
def log_event(data)
|
9
|
-
publish(events_subject, data)
|
10
|
-
end
|
11
|
-
|
12
|
-
def publish(subject, data)
|
13
|
-
client.publish(subject, data.to_json)
|
14
|
-
end
|
15
|
-
|
16
|
-
def client
|
17
|
-
@client ||= begin
|
18
|
-
require "nats/io/client"
|
19
|
-
client = NATS::IO::Client.new
|
20
|
-
client.connect(servers: (ENV["NATS_URL"] || "nats://127.0.0.1:4222").split(","))
|
21
|
-
client
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def visits_subject
|
26
|
-
"ahoy_visits"
|
27
|
-
end
|
28
|
-
|
29
|
-
def events_subject
|
30
|
-
"ahoy_events"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module Ahoy
|
2
|
-
module Stores
|
3
|
-
class NsqStore < LogStore
|
4
|
-
def log_visit(data)
|
5
|
-
post(visits_topic, data)
|
6
|
-
end
|
7
|
-
|
8
|
-
def log_event(data)
|
9
|
-
post(events_topic, data)
|
10
|
-
end
|
11
|
-
|
12
|
-
def client
|
13
|
-
@client ||= begin
|
14
|
-
require "nsq"
|
15
|
-
client = Nsq::Producer.new(
|
16
|
-
nsqd: ENV["NSQ_URL"] || "127.0.0.1:4150"
|
17
|
-
)
|
18
|
-
at_exit { client.terminate }
|
19
|
-
client
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def post(topic, data)
|
24
|
-
client.write_to_topic(topic, data.to_json)
|
25
|
-
end
|
26
|
-
|
27
|
-
def visits_topic
|
28
|
-
"ahoy_visits"
|
29
|
-
end
|
30
|
-
|
31
|
-
def events_topic
|
32
|
-
"ahoy_events"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Ahoy
|
2
|
-
module Subscribers
|
3
|
-
class ActiveRecord
|
4
|
-
def initialize(options = {})
|
5
|
-
@model = options[:model] || Ahoy::Event
|
6
|
-
end
|
7
|
-
|
8
|
-
def track(name, properties, options = {})
|
9
|
-
@model.create! do |e|
|
10
|
-
e.visit = options[:visit]
|
11
|
-
e.user = options[:user]
|
12
|
-
e.name = name
|
13
|
-
e.properties = properties
|
14
|
-
e.time = options[:time]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/lib/ahoy/throttle.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require "rack/attack"
|
2
|
-
|
3
|
-
module Ahoy
|
4
|
-
class Throttle < Rack::Attack
|
5
|
-
throttle("ahoy/ip", limit: Ahoy.throttle_limit, period: Ahoy.throttle_period) do |req|
|
6
|
-
if req.path.start_with?("/ahoy/")
|
7
|
-
req.ip
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def_delegators self, :whitelisted?, :blacklisted?, :throttled?, :tracked?, :blocklisted?, :safelisted?
|
12
|
-
|
13
|
-
def self.throttled_response
|
14
|
-
Rack::Attack.throttled_response
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
# taken from https://github.com/collectiveidea/audited/blob/master/lib/generators/audited/install_generator.rb
|
2
|
-
require "rails/generators"
|
3
|
-
require "rails/generators/migration"
|
4
|
-
require "active_record"
|
5
|
-
require "rails/generators/active_record"
|
6
|
-
|
7
|
-
module Ahoy
|
8
|
-
module Stores
|
9
|
-
module Generators
|
10
|
-
class ActiveRecordEventsGenerator < Rails::Generators::Base
|
11
|
-
include Rails::Generators::Migration
|
12
|
-
source_root File.expand_path("../templates", __FILE__)
|
13
|
-
|
14
|
-
class_option :database, type: :string, aliases: "-d"
|
15
|
-
|
16
|
-
# Implement the required interface for Rails::Generators::Migration.
|
17
|
-
def self.next_migration_number(dirname) #:nodoc:
|
18
|
-
next_migration_number = current_migration_number(dirname) + 1
|
19
|
-
if ::ActiveRecord::Base.timestamped_migrations
|
20
|
-
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
|
21
|
-
else
|
22
|
-
"%.3d" % next_migration_number
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def copy_migration
|
27
|
-
@database = options["database"] || detect_database
|
28
|
-
unless @database.in?([nil, "postgresql", "postgresql-jsonb", "mysql", "sqlite"])
|
29
|
-
raise Thor::Error, "Unknown database option"
|
30
|
-
end
|
31
|
-
migration_template "active_record_events_migration.rb", "db/migrate/create_ahoy_events.rb", migration_version: migration_version
|
32
|
-
end
|
33
|
-
|
34
|
-
def generate_model
|
35
|
-
template "active_record_event_model.rb", "app/models/ahoy/event.rb"
|
36
|
-
end
|
37
|
-
|
38
|
-
def create_initializer
|
39
|
-
template "active_record_initializer.rb", "config/initializers/ahoy.rb"
|
40
|
-
end
|
41
|
-
|
42
|
-
def detect_database
|
43
|
-
postgresql_version = ActiveRecord::Base.connection.send(:postgresql_version) rescue 0
|
44
|
-
if postgresql_version >= 90400
|
45
|
-
"postgresql-jsonb"
|
46
|
-
elsif postgresql_version >= 90200
|
47
|
-
"postgresql"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def migration_version
|
52
|
-
if ActiveRecord::VERSION::MAJOR >= 5
|
53
|
-
"[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require "rails/generators"
|
2
|
-
|
3
|
-
module Ahoy
|
4
|
-
module Stores
|
5
|
-
module Generators
|
6
|
-
class ActiveRecordGenerator < Rails::Generators::Base
|
7
|
-
class_option :database, type: :string, aliases: "-d"
|
8
|
-
|
9
|
-
def boom
|
10
|
-
invoke "ahoy:stores:active_record_visits", nil, options
|
11
|
-
invoke "ahoy:stores:active_record_events", nil, options
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# taken from https://github.com/collectiveidea/audited/blob/master/lib/generators/audited/install_generator.rb
|
2
|
-
require "rails/generators"
|
3
|
-
require "rails/generators/migration"
|
4
|
-
require "active_record"
|
5
|
-
require "rails/generators/active_record"
|
6
|
-
|
7
|
-
module Ahoy
|
8
|
-
module Stores
|
9
|
-
module Generators
|
10
|
-
class ActiveRecordVisitsGenerator < Rails::Generators::Base
|
11
|
-
include Rails::Generators::Migration
|
12
|
-
source_root File.expand_path("../templates", __FILE__)
|
13
|
-
|
14
|
-
class_option :database, type: :string, aliases: "-d"
|
15
|
-
|
16
|
-
# Implement the required interface for Rails::Generators::Migration.
|
17
|
-
def self.next_migration_number(dirname) #:nodoc:
|
18
|
-
next_migration_number = current_migration_number(dirname) + 1
|
19
|
-
if ::ActiveRecord::Base.timestamped_migrations
|
20
|
-
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
|
21
|
-
else
|
22
|
-
"%.3d" % next_migration_number
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def copy_migration
|
27
|
-
unless options["database"].in?([nil, "postgresql", "postgresql-jsonb"])
|
28
|
-
raise Thor::Error, "Unknown database option"
|
29
|
-
end
|
30
|
-
migration_template "active_record_visits_migration.rb", "db/migrate/create_visits.rb", migration_version: migration_version
|
31
|
-
end
|
32
|
-
|
33
|
-
def generate_model
|
34
|
-
template "active_record_visit_model.rb", "app/models/visit.rb"
|
35
|
-
end
|
36
|
-
|
37
|
-
def create_initializer
|
38
|
-
template "active_record_initializer.rb", "config/initializers/ahoy.rb"
|
39
|
-
end
|
40
|
-
|
41
|
-
def migration_version
|
42
|
-
if ActiveRecord::VERSION::MAJOR >= 5
|
43
|
-
"[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|