trueandco_analytics 0.3.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +152 -0
- data/Rakefile +36 -0
- data/app/assets/javascripts/trueandco_analytics.js +170 -0
- data/app/commands/trueandco_analytics/arr_jsons_to_arr_hash.rb +20 -0
- data/app/commands/trueandco_analytics/metric_c/add_list.rb +65 -0
- data/app/commands/trueandco_analytics/report_c/generate.rb +31 -0
- data/app/commands/trueandco_analytics/session_c/create.rb +65 -0
- data/app/commands/trueandco_analytics/session_c/put_data.rb +46 -0
- data/app/commands/trueandco_analytics/user_c/create_or_update_user_if_exist.rb +41 -0
- data/app/controllers/trueandco_analytics/application_controller.rb +5 -0
- data/app/controllers/trueandco_analytics/reciver_controller.rb +19 -0
- data/app/models/trueandco_analytics/application_record.rb +5 -0
- data/app/models/trueandco_analytics/metric_user.rb +8 -0
- data/app/models/trueandco_analytics/metric_user_session.rb +8 -0
- data/app/models/trueandco_analytics/metric_user_visit.rb +8 -0
- data/app/views/trueandco_analytics/receiver/pull_user_statistic.erb +0 -0
- data/app/workers/trueandco_analytics/user_session_metric_worker.rb +21 -0
- data/config/routes.rb +3 -0
- data/config/secrets.yml +2 -0
- data/db/migrate/20170802133950_create_metric_users.rb +19 -0
- data/db/migrate/20170802134044_create_metric_user_visits.rb +20 -0
- data/db/migrate/20170802134059_create_metric_user_sessions.rb +27 -0
- data/exe/trueandco_analytics +28 -0
- data/lib/extension_string.rb +20 -0
- data/lib/generators/trueandco_analytics/install_generator.rb +14 -0
- data/lib/generators/trueandco_analytics/templates/trueandco_analytics.rb +37 -0
- data/lib/trueandco_analytics/cli/common.rb +49 -0
- data/lib/trueandco_analytics/cli/report.rb +51 -0
- data/lib/trueandco_analytics/config/params.rb +81 -0
- data/lib/trueandco_analytics/engine.rb +31 -0
- data/lib/trueandco_analytics/helpers/trueandco_analytics_helper.rb +35 -0
- data/lib/trueandco_analytics/locales/en.yml +16 -0
- data/lib/trueandco_analytics/modules/info.rb +21 -0
- data/lib/trueandco_analytics/reports/application_report.rb +61 -0
- data/lib/trueandco_analytics/reports/details_report.rb +24 -0
- data/lib/trueandco_analytics/reports/page_buy_in_date_range_report.rb +29 -0
- data/lib/trueandco_analytics/services/logger.rb +24 -0
- data/lib/trueandco_analytics/services/redis_connect.rb +12 -0
- data/lib/trueandco_analytics/services/reports.rb +30 -0
- data/lib/trueandco_analytics/services/workers.rb +14 -0
- data/lib/trueandco_analytics/version.rb +3 -0
- data/lib/trueandco_analytics.rb +37 -0
- metadata +242 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
module TrueandcoAnalytics
|
2
|
+
module ReportC
|
3
|
+
class Generate
|
4
|
+
include TrueandcoAnalytics::Modules::Info
|
5
|
+
|
6
|
+
def initialize(name: nil, format: nil, datetime_start: nil, datetime_end: nil, path: nil)
|
7
|
+
@name = name
|
8
|
+
@format = format
|
9
|
+
@datetime_start = datetime_start
|
10
|
+
@datetime_end = datetime_end
|
11
|
+
@path = path || CURRENT_PATH
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute
|
15
|
+
report = ::TrueandcoAnalytics::Reports.get_report_obj(name, format, datetime_start, datetime_end)
|
16
|
+
return if report.nil? || report.data.empty?
|
17
|
+
@path += report.report_name if File.directory?(path)
|
18
|
+
dirname = File.dirname(path)
|
19
|
+
unless File.directory?(dirname)
|
20
|
+
FileUtils.mkdir_p(dirname)
|
21
|
+
end
|
22
|
+
File.open(path, 'w+') { |f| f.write(report.data) }
|
23
|
+
result(I18n.t('trueandco_analytics.result.done', path: path))
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :name, :format, :datetime_start, :datetime_end, :path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module TrueandcoAnalytics
|
2
|
+
module SessionC
|
3
|
+
class Create
|
4
|
+
|
5
|
+
def initialize(metric_user, first_point, timestamp_end, request_info)
|
6
|
+
|
7
|
+
if metric_user.nil? || first_point.nil? || timestamp_end.nil? ||request_info.nil?
|
8
|
+
raise ArgumentError.new("#{self.to_s} metric_user=#{metric_user}
|
9
|
+
first_point=#{first_point} timestamp_end=#{timestamp_end} request_info=#{request_info}")
|
10
|
+
end
|
11
|
+
|
12
|
+
@metric_user = metric_user
|
13
|
+
@ip = request_info['remote_ip']
|
14
|
+
@user_agent = request_info['user_agent']
|
15
|
+
@session_start = first_point['time']['timestamp']
|
16
|
+
@referer = first_point['userReferrer']
|
17
|
+
@live_time_s = timestamp_end - @session_start
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute
|
21
|
+
Browser::Base.include(Browser::Aliases)
|
22
|
+
browser = Browser.new(user_agent, accept_language: "en-us")
|
23
|
+
data = {
|
24
|
+
metric_user: metric_user,
|
25
|
+
user_agent: user_agent,
|
26
|
+
referer: referer,
|
27
|
+
session_start: datetime_session_start,
|
28
|
+
live_time_s: 60,
|
29
|
+
ip_4: ip_v4(ip),
|
30
|
+
ip_6: ip_v6(ip),
|
31
|
+
browser: browser.name,
|
32
|
+
is_mobile: browser.mobile? || false
|
33
|
+
}
|
34
|
+
MetricUserSession.create(data)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :metric_user, :ip, :user_agent, :session_start, :live_time_s, :referer
|
40
|
+
|
41
|
+
def datetime_session_start
|
42
|
+
DateTime.strptime(session_start.to_s,'%s')
|
43
|
+
end
|
44
|
+
|
45
|
+
def ip_v4(ip)
|
46
|
+
ip_o = get_ip_object(ip)
|
47
|
+
result = 0
|
48
|
+
result = ip_o.to_i if ip_o.ipv4?
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def ip_v6(ip)
|
54
|
+
ip_o = get_ip_object(ip)
|
55
|
+
result = 0
|
56
|
+
result = ip_o.data if ip_o.ipv6?
|
57
|
+
result
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_ip_object(ip)
|
61
|
+
@ip_o ||= IPAddress.parse ip
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module TrueandcoAnalytics
|
2
|
+
module SessionC
|
3
|
+
class PutData
|
4
|
+
|
5
|
+
def initialize(json_data, request_info, userInfo)
|
6
|
+
@json_data = json_data
|
7
|
+
@userInfo = userInfo
|
8
|
+
@request_info = request_info
|
9
|
+
@redis = RedisConnect.get
|
10
|
+
@time_survey = Config::Params.time_survey
|
11
|
+
@time_dead_session = Config::Params.time_dead_session
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute
|
15
|
+
1.times do
|
16
|
+
break if userInfo.nil? || userInfo.empty?
|
17
|
+
user_key = ::FNV.new.fnv1_32 userInfo.to_s
|
18
|
+
mange_job(user_key)
|
19
|
+
redis.rpush(user_key, json_data)
|
20
|
+
redis.expire(user_key, time_dead_session + 3)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :json_data, :userInfo, :request_info, :redis, :time_dead_session, :time_survey
|
27
|
+
|
28
|
+
def mange_job(user_key)
|
29
|
+
user_job_key = "#{user_key}:job_key"
|
30
|
+
unless redis.exists user_job_key
|
31
|
+
create_job(user_key, user_job_key)
|
32
|
+
end
|
33
|
+
if redis.ttl(user_job_key) < time_survey * 3
|
34
|
+
job_id = redis.get(user_job_key)
|
35
|
+
Sidekiq::ScheduledSet.new.find_job(job_id)&.delete
|
36
|
+
create_job(user_key, user_job_key)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_job(user_key, user_job_key)
|
41
|
+
job_id = UserSessionMetricWorker.perform_at(time_dead_session.seconds.from_now, user_key, request_info)
|
42
|
+
redis.setex(user_job_key, time_dead_session, job_id)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module TrueandcoAnalytics
|
2
|
+
module UserC
|
3
|
+
class CreateOrUpdateUserIfExist
|
4
|
+
|
5
|
+
def initialize(user_agent, timestamp_end)
|
6
|
+
if user_agent.nil? || timestamp_end.nil?
|
7
|
+
raise ArgumentError.new("#{self.to_s} user_agent=#{user_agent} timestamp_end=#{timestamp_end}")
|
8
|
+
end
|
9
|
+
@user_agent = user_agent
|
10
|
+
@timestamp_end = timestamp_end
|
11
|
+
@user_id = Config::Params.user_method&.id
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute
|
15
|
+
user = nil
|
16
|
+
user = TrueandcoAnalytics::MetricUser.find_by(user_id: user_id) if user_id
|
17
|
+
user = TrueandcoAnalytics::MetricUser.find_by(hash_id: hash_id) if user.nil?
|
18
|
+
user = if user.nil?
|
19
|
+
TrueandcoAnalytics::MetricUser.create(user_id: user_id || 0, datetime_create: datetime_end,
|
20
|
+
last_active_datetime: datetime_end, hash_id: hash_id)
|
21
|
+
else
|
22
|
+
user.update_attribute(:last_active_datetime, datetime_end)
|
23
|
+
user
|
24
|
+
end
|
25
|
+
user
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :user_agent, :timestamp_end, :user_id
|
31
|
+
|
32
|
+
def datetime_end
|
33
|
+
DateTime.strptime(timestamp_end.to_s,'%s')
|
34
|
+
end
|
35
|
+
|
36
|
+
def hash_id
|
37
|
+
@hash_id ||= FNV.new.fnv1_32(user_agent)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_dependency "trueandco_analytics/application_controller"
|
2
|
+
|
3
|
+
module TrueandcoAnalytics
|
4
|
+
class ReceiverController < ApplicationController
|
5
|
+
|
6
|
+
def pull_user_statistic
|
7
|
+
data = JSON.parse(params[:user_metric])
|
8
|
+
userInfo = request.user_agent
|
9
|
+
page_path = request.url.match(/(?:\/\/.+?\/)(.+?)(?=\?|$)/)[1]
|
10
|
+
data = data.merge({ page_path: page_path }).to_json
|
11
|
+
request_info = {
|
12
|
+
'remote_ip' => request.remote_ip,
|
13
|
+
'user_agent' => request.user_agent
|
14
|
+
}
|
15
|
+
SessionC::PutData.new(data, request_info, userInfo).execute
|
16
|
+
render nothing: true, status: 201, content_type: 'text/plain'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module TrueandcoAnalytics
|
2
|
+
|
3
|
+
class UserSessionMetricWorker
|
4
|
+
include Sidekiq::Worker
|
5
|
+
sidekiq_options queue: :user_metric
|
6
|
+
|
7
|
+
def perform(*args)
|
8
|
+
info_pages,info_request = args[0],args[1]
|
9
|
+
@redis = RedisConnect.get
|
10
|
+
user_session_data_json = @redis.lrange(info_pages, 0, -1)
|
11
|
+
return if user_session_data_json.nil?
|
12
|
+
user_session_data = ArrJsonsToArrHash.new(user_session_data_json).execute
|
13
|
+
return unless user_session_data.any?
|
14
|
+
first_point = user_session_data[0]
|
15
|
+
last_point = user_session_data[-1]
|
16
|
+
metric_user = UserC::CreateOrUpdateUserIfExist.new(info_request['user_agent'], last_point['time']['timestamp']).execute
|
17
|
+
session = SessionC::Create.new(metric_user, first_point, last_point['time']['timestamp'], info_request).execute
|
18
|
+
MetricC::AddList.new(metric_user, session, user_session_data).execute
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/config/routes.rb
ADDED
data/config/secrets.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateMetricUsers < ActiveRecord::Migration.try(:send, '[]', '5.1')
|
2
|
+
def up
|
3
|
+
drop_table :metric_users if (table_exists? :metric_users)
|
4
|
+
create_table :metric_users do |t|
|
5
|
+
t.integer :user_id, null: false, default: 0
|
6
|
+
t.timestamp :datetime_create, null: false
|
7
|
+
t.timestamp :last_active_datetime, null: false
|
8
|
+
end
|
9
|
+
|
10
|
+
add_column :metric_users, :hash_id, 'integer unsigned', null: false
|
11
|
+
|
12
|
+
add_index(:metric_users, :user_id)
|
13
|
+
add_index(:metric_users, :hash_id)
|
14
|
+
end
|
15
|
+
|
16
|
+
def down
|
17
|
+
drop_table :metric_users
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreateMetricUserVisits < ActiveRecord::Migration.try(:send, '[]', '5.1')
|
2
|
+
def up
|
3
|
+
drop_table :metric_user_visits if (table_exists? :metric_user_visits)
|
4
|
+
create_table :metric_user_visits do |t|
|
5
|
+
t.integer :metric_user_id, null: false, default: 0
|
6
|
+
t.integer :metric_user_session_id, null: false, default: 0
|
7
|
+
t.string :page_path, null: false
|
8
|
+
t.boolean :is_buy, null: false, default: false
|
9
|
+
t.text :user_action, null: false
|
10
|
+
end
|
11
|
+
add_column :metric_user_visits, :time_s, 'mediumint unsigned', null: false, default: 0
|
12
|
+
|
13
|
+
add_index(:metric_user_visits, :metric_user_id)
|
14
|
+
add_index(:metric_user_visits, :metric_user_session_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def down
|
18
|
+
drop_table :metric_user_visits
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class CreateMetricUserSessions < ActiveRecord::Migration.try(:send, '[]', '5.1')
|
2
|
+
def up
|
3
|
+
drop_table :metric_user_sessions if (table_exists? :metric_user_sessions)
|
4
|
+
create_table :metric_user_sessions do |t|
|
5
|
+
t.integer :metric_user_id, null: false, default: 0
|
6
|
+
t.binary :ip_6, limit: 16, null: false, default: 0
|
7
|
+
t.string :user_agent, null: false
|
8
|
+
t.string :referer, null: false
|
9
|
+
t.boolean :is_mobile, null: false, default: false
|
10
|
+
t.string :browser, null: false, default: ''
|
11
|
+
t.timestamp :session_start, null: false
|
12
|
+
end
|
13
|
+
|
14
|
+
add_column :metric_user_sessions, :ip_4, 'integer unsigned', null: false, default: 0
|
15
|
+
add_column :metric_user_sessions, :live_time_s, 'integer unsigned', null: false
|
16
|
+
|
17
|
+
add_index(:metric_user_sessions, :metric_user_id)
|
18
|
+
add_index(:metric_user_sessions, :ip_4)
|
19
|
+
add_index(:metric_user_sessions, :session_start)
|
20
|
+
end
|
21
|
+
|
22
|
+
def down
|
23
|
+
drop_table :metric_user_sessions
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
3
|
+
CURRENT_PATH = Dir.pwd + '/'
|
4
|
+
|
5
|
+
require 'bundler/setup'
|
6
|
+
require 'i18n'
|
7
|
+
require 'optparse'
|
8
|
+
require 'fileutils'
|
9
|
+
require 'trueandco_analytics'
|
10
|
+
require 'trueandco_analytics/cli/common'
|
11
|
+
require 'trueandco_analytics/cli/report'
|
12
|
+
require "#{ENGINE_ROOT}/app/commands/trueandco_analytics/report_c/generate"
|
13
|
+
require 'active_record'
|
14
|
+
require 'mysql2'
|
15
|
+
require "#{CURRENT_PATH}config/initializers/trueandco_analytics"
|
16
|
+
|
17
|
+
models_dir = "#{ENGINE_ROOT}/app/models/trueandco_analytics/"
|
18
|
+
require "#{models_dir}application_record.rb"
|
19
|
+
Dir["#{models_dir}/*.rb"].each do |f|
|
20
|
+
require f
|
21
|
+
end
|
22
|
+
|
23
|
+
connect_db = TrueandcoAnalytics::Config::Params.connect_db
|
24
|
+
1.times do
|
25
|
+
break if connect_db.nil?
|
26
|
+
ActiveRecord::Base.establish_connection(connect_db)
|
27
|
+
TrueandcoAnalytics::Cli::Common.new(ARGV).execute
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class String
|
2
|
+
def underscore!
|
3
|
+
gsub!(/(.)([A-Z])/,'\1_\2')
|
4
|
+
downcase!
|
5
|
+
end
|
6
|
+
|
7
|
+
def underscore
|
8
|
+
dup.tap { |s| s.underscore! }
|
9
|
+
end
|
10
|
+
|
11
|
+
def camelize(uppercase_first_letter = true)
|
12
|
+
string = self
|
13
|
+
if uppercase_first_letter
|
14
|
+
string = string.sub(/^[a-z\d]*/) { $&.capitalize }
|
15
|
+
else
|
16
|
+
string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { $&.downcase }
|
17
|
+
end
|
18
|
+
string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
module TrueandcoAnalytics
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
desc "Configuration UserMetrix gem"
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
8
|
+
end
|
9
|
+
|
10
|
+
def copy_initializer
|
11
|
+
template 'trueandco_analytics.rb', 'config/initializers/trueandco_analytics.rb'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
TrueandcoAnalytics.setup do |config|
|
2
|
+
# Time survey Analytics seconds
|
3
|
+
config.time_survey = 15
|
4
|
+
|
5
|
+
# Specify the method available in the ApplicationController to the receiving user object. Containing id, email.
|
6
|
+
#config.user_method = 'current_user'
|
7
|
+
|
8
|
+
# Specify css the selector class for the button purchase
|
9
|
+
config.buy_selector_class = 'buy'
|
10
|
+
|
11
|
+
# Specify the database where redis will store the statistics for the session user
|
12
|
+
config.connect_redis = {
|
13
|
+
#url: "redis://your_host:6379",
|
14
|
+
#redis_password: '',
|
15
|
+
redis_db: 1
|
16
|
+
}
|
17
|
+
|
18
|
+
# Specify Sidekiq config
|
19
|
+
config.sidekiq_configure_client_url = 'redis://localhost:6379/1'
|
20
|
+
config.sidekiq_configure_server_url = 'redis://localhost:6379/1'
|
21
|
+
config.sidekiq_configure_namespace = 'metric'
|
22
|
+
|
23
|
+
#Log name in rails app
|
24
|
+
config.log = nil
|
25
|
+
|
26
|
+
#Specify the database to use in console mode
|
27
|
+
=begin
|
28
|
+
config.connect_db = {
|
29
|
+
adapter: :mysql2,
|
30
|
+
database: 'development_db_name',
|
31
|
+
username: 'ivan',
|
32
|
+
password: '3443555',
|
33
|
+
host: '127.0.0.1',
|
34
|
+
port: 3306
|
35
|
+
}
|
36
|
+
=end
|
37
|
+
end
|