game_analytics 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +115 -12
- data/Rakefile +7 -0
- data/lib/game_analytics.rb +4 -2
- data/lib/game_analytics/client.rb +30 -30
- data/lib/game_analytics/common.rb +18 -18
- data/lib/game_analytics/metric.rb +55 -37
- data/lib/game_analytics/version.rb +1 -1
- data/lib/game_analytics/worker.rb +29 -29
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 301b00ccddb8190e6d5adb999ab9ee5d6039ffc1
|
4
|
+
data.tar.gz: b98f7e0d885ecd8bf0ab3c873d656a4dc5c56b75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f5c54607d02134e62fceabc85482ee8475dadaea0cded1423b17f057543a464fc39daeca4ccb898b001205a8d298a8727e713f9f464c8c40f495a8acc3a44cf
|
7
|
+
data.tar.gz: fb669ef41103d51409d9a2426bed545e7a446e1d2d4f5ce90bd04172f5b9ccd6ccbe162947e09b7b21637a29225ee0696b697e6b10345ee97e1a9427e1f4811a
|
data/README.md
CHANGED
@@ -15,7 +15,9 @@ available.
|
|
15
15
|
|
16
16
|
Add this line to your application's Gemfile:
|
17
17
|
|
18
|
-
|
18
|
+
```ruby
|
19
|
+
gem 'game_analytics'
|
20
|
+
```
|
19
21
|
|
20
22
|
And then execute:
|
21
23
|
|
@@ -30,29 +32,130 @@ Or install it yourself as:
|
|
30
32
|
Configure the gem with your GameAnalytics keys by placing code like the following in
|
31
33
|
your initializer:
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
```ruby
|
36
|
+
GameAnalytics.config(
|
37
|
+
:game_key => '123451234512345123451234512345',
|
38
|
+
:secret_key => '123451234512345123451234512345'
|
39
|
+
)
|
40
|
+
```
|
37
41
|
|
38
42
|
In your application, create Metric objects of the appropriate GameAnalytics types
|
39
43
|
(Design, Business, Quality, or User), and send them to the service:
|
40
44
|
|
41
|
-
|
42
|
-
|
43
|
-
|
45
|
+
```ruby
|
46
|
+
m = GameAnalytics::Metric::Business.new(:user_id => '-100', :session_id => '-100',
|
47
|
+
:build => 'development', :message => 'test')
|
48
|
+
GameAnalytics.client.enqueue m
|
49
|
+
```
|
44
50
|
|
45
51
|
GameAnalytics uses the submitting ip to determine the country the user resides in. If you are submitting events
|
46
52
|
in the name of the user (e.g. client) from another machine (e.g. server), you can pass the original ip using `new_with_ip`:
|
47
53
|
|
48
|
-
|
49
|
-
|
50
|
-
|
54
|
+
```ruby
|
55
|
+
m = GameAnalytics::Metric::Business.new_with_ip('123.123.123.123', :user_id => '-100', :session_id => '-100', :build => 'development', :message => 'test')
|
56
|
+
GameAnalytics.client.enqueue m
|
57
|
+
```
|
51
58
|
|
52
59
|
You can also send arrays of objects in a single service request:
|
53
60
|
|
54
|
-
|
61
|
+
```ruby
|
62
|
+
GameAnalytics.client.enqueue [m1, m2]
|
63
|
+
```
|
55
64
|
|
65
|
+
## Events
|
66
|
+
|
67
|
+
There are 4 types of events you can send to GameAnalytics. For a general description of events see [General event structure](http://support.gameanalytics.com/hc/en-us/articles/200841486-General-event-structure).
|
68
|
+
|
69
|
+
All events **require** the following fields:
|
70
|
+
|
71
|
+
| Field | Type | Required | Description |
|
72
|
+
|:-----------|:-------|:--------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
73
|
+
| user_id | string | **Yes** | A unique ID representing the user playing your game. This ID should remain the same across different play sessions. |
|
74
|
+
| session_id | string | **Yes** | A unique ID representing the current play session. A new unique ID should be generated at the start of each session, and used for all events throughout that session. |
|
75
|
+
| build | string | **Yes** | Describes the current version of the game being played. |
|
76
|
+
|
77
|
+
|
78
|
+
### Design Event
|
79
|
+
|
80
|
+
Documentation: [Design event structure](http://support.gameanalytics.com/hc/en-us/articles/200841506-Design-event-structure)
|
81
|
+
|
82
|
+
#### Additional fields
|
83
|
+
|
84
|
+
| Field | Type | Required | Description |
|
85
|
+
|:---------|:-------|:--------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
86
|
+
| event_id | string | **Yes** | Identifies the event. This field can be sub-categorized by using ":", eg. "PickedUpAmmo:Shotgun". |
|
87
|
+
| area | string | No | Indicates the area or game level where the event occurred. |
|
88
|
+
| value | float | No | Numeric value which may be used to enhance the event_id. For example, if the event_id is "PickedUpAmmo:Shotgun", the value could indicate the number of shotgun shells gained. |
|
89
|
+
| x | float | No | The x coordinate at which this event occurred. |
|
90
|
+
| y | float | No | The y coordinate at which this event occurred. |
|
91
|
+
| z | float | No | The z coordinate at which this event occurred. |
|
92
|
+
|
93
|
+
|
94
|
+
### User Event
|
95
|
+
|
96
|
+
Documentation: [User event structure](http://support.gameanalytics.com/hc/en-us/articles/200841526-User-event-structure)
|
97
|
+
|
98
|
+
#### Additional fields
|
99
|
+
|
100
|
+
| Field | Type | Required | Description |
|
101
|
+
|:------------------|:--------|:--------:|:--------------------------------------------------------------------------------------------------------|
|
102
|
+
| gender | char | No | The gender of the user (M/F). |
|
103
|
+
| birth_year | integer | No | The year the user was born. |
|
104
|
+
| friend_count | integer | No | The number of friends in the users network. |
|
105
|
+
| facebook_id | string | No | The Facebook ID of the user, in clear. |
|
106
|
+
| googleplus_id | string | No | The Google Plus ID of the user, in clear. |
|
107
|
+
| ios_id | string | No | The IDFA of the user, in clear. |
|
108
|
+
| android_id | string | No | The Android ID of the user, in clear. |
|
109
|
+
| adtruth_id | string | No | The AdTruth ID of the user, in clear. |
|
110
|
+
| platform | string | No | The platform that this user plays the game on. |
|
111
|
+
| device | string | No | The device that this user plays the game on. |
|
112
|
+
| os_major | string | No | The major version of the OS that this user plays on. |
|
113
|
+
| os_minor | string | No | The minor version of the OS that this user plays on. |
|
114
|
+
| install_publisher | string | No | The name of the ad publisher. |
|
115
|
+
| install_site | string | No | The website or app where the ad for your game was shown. |
|
116
|
+
| install_campaign | string | No | The name of your ad campaign this user comes from. |
|
117
|
+
| install_adgroup | string | No | The name of the ad group this user comes from. |
|
118
|
+
| install_ad | string | No | The name of the ad this user comes from. |
|
119
|
+
| install_keyword | string | No | A keyword to associate with this user and the campaign ad. |
|
120
|
+
| sdk_version | string | No | Used by the GA team to provide support on specific versions of the different GA SDKs. DO NOT implement. |
|
121
|
+
|
122
|
+
|
123
|
+
### Business Event
|
124
|
+
|
125
|
+
Documentation: [Business event structure](http://support.gameanalytics.com/hc/en-us/articles/200841516-Business-event-structure)
|
126
|
+
|
127
|
+
#### Additional fields
|
128
|
+
|
129
|
+
| Field | Type | Required | Description |
|
130
|
+
|:---------|:--------|:--------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
131
|
+
| event_id | string | **Yes** | Identifies the event. This field can be sub-categorized by using ":", eg. "Purchase:RocketLauncher:Ammo". |
|
132
|
+
| area | string | No | Indicates the area or game level where the event occurred. |
|
133
|
+
| value | float | no | Numeric value which may be used to enhance the event_id. For example, if the event_id is "Purchase:RocketLauncher:Ammo", the value could indicate the number of rocket launcher ammo bought. |
|
134
|
+
| currency | string | **Yes** | A custom string for identifying the currency. The monetization dashboard will only be populated if you use one of the supported currencies, for example "USD", "RON" or "DKK". For all other virtual currency strings, you will need to create your custom dashboards and widgets. |
|
135
|
+
| amount | integer | **Yes** | Numeric value which corresponds to the cost of the purchase in the monetary unit multiplied by 100. For example, if the currency is "USD", the amount should be specified in cents. Exception: Google Play IAB uses a comma separator for representing EUR currency. Before you multiply by 100 we recommend you replace the comma with a point separator. (Example: 12,68€ -> 12.68€) |
|
136
|
+
| x | float | No | The x coordinate at which this event occurred. |
|
137
|
+
| y | float | No | The y coordinate at which this event occurred. |
|
138
|
+
| z | float | No | The z coordinate at which this event occurred. |
|
139
|
+
|
140
|
+
|
141
|
+
### Error Event
|
142
|
+
|
143
|
+
Documentation: [Error and Quality event structure](http://support.gameanalytics.com/hc/en-us/articles/200841476-Error-and-Quality-event-structure)
|
144
|
+
|
145
|
+
#### Additional fields
|
146
|
+
|
147
|
+
| Field | Type | Required | Description |
|
148
|
+
|:---------|:-------|:--------:|:-------------------------------------------------------------------------------------------------------------------------------------|
|
149
|
+
| message | string | **Yes** | Used to describe the event in further detail. For example, in the case of an exception the event could contain the stack trace. |
|
150
|
+
| severity | string | **Yes** | Used to describe the severity of the event. Must be one of the following values: `["critical", "error", "warning", "info", "debug"]` |
|
151
|
+
| area | string | No | Indicates the area or game level where the event occurred. |
|
152
|
+
| x | float | No | The x coordinate at which this event occurred. |
|
153
|
+
| y | float | No | The y coordinate at which this event occurred. |
|
154
|
+
| z | float | No | The z coordinate at which this event occurred. |
|
155
|
+
|
156
|
+
|
157
|
+
### Quality Event (Deprecated)
|
158
|
+
Documentation: [Error and Quality event structure](http://support.gameanalytics.com/hc/en-us/articles/200841476-Error-and-Quality-event-structure)
|
56
159
|
|
57
160
|
## Contributing
|
58
161
|
|
data/Rakefile
CHANGED
data/lib/game_analytics.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'logger'
|
1
2
|
require 'game_analytics/common'
|
2
3
|
require 'game_analytics/client'
|
3
4
|
require 'game_analytics/metric'
|
@@ -11,13 +12,14 @@ module GameAnalytics
|
|
11
12
|
attr_accessor :options, :logger, :disabled
|
12
13
|
end
|
13
14
|
|
15
|
+
self.logger = const_defined?('Rails') ? Rails.logger : Logger.new(STDOUT)
|
14
16
|
|
15
17
|
def self.config(opts)
|
16
18
|
@options = opts
|
17
|
-
@logger = opts[:logger]
|
19
|
+
@logger = opts[:logger] if opts[:logger]
|
18
20
|
@disabled = opts[:disabled]
|
19
21
|
end
|
20
|
-
|
22
|
+
|
21
23
|
def self.client
|
22
24
|
@client ||= Client.new
|
23
25
|
end
|
@@ -1,45 +1,45 @@
|
|
1
1
|
module GameAnalytics
|
2
|
-
class Client
|
3
|
-
|
4
|
-
include Common
|
2
|
+
class Client
|
5
3
|
|
4
|
+
include Common
|
6
5
|
|
7
|
-
def initialize
|
8
|
-
@queue = Queue.new
|
9
|
-
@worker_mutex = Mutex.new
|
10
|
-
end
|
11
6
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
7
|
+
def initialize
|
8
|
+
@queue = Queue.new
|
9
|
+
@worker_mutex = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def enqueue(metric)
|
13
|
+
return if disabled
|
14
|
+
ensure_worker_running
|
15
|
+
@queue << metric
|
16
|
+
nil
|
17
|
+
end
|
18
18
|
|
19
19
|
|
20
|
-
private
|
20
|
+
private
|
21
21
|
|
22
|
-
|
23
|
-
return if worker_running?
|
24
|
-
@worker_mutex.synchronize do
|
22
|
+
def ensure_worker_running
|
25
23
|
return if worker_running?
|
26
|
-
|
24
|
+
@worker_mutex.synchronize do
|
25
|
+
return if worker_running?
|
26
|
+
start_worker
|
27
|
+
end
|
27
28
|
end
|
28
|
-
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
def worker_running?
|
31
|
+
@worker_thread && @worker_thread.alive?
|
32
|
+
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
def start_worker
|
35
|
+
@worker_thread = Thread.new do
|
36
|
+
begin
|
37
|
+
Worker.new(@queue).run
|
38
|
+
rescue => ex
|
39
|
+
logger.info "GameAnalytics worker thread exception: #{ex}"
|
40
|
+
end
|
40
41
|
end
|
41
42
|
end
|
42
|
-
end
|
43
43
|
|
44
|
-
end
|
44
|
+
end
|
45
45
|
end
|
@@ -1,21 +1,21 @@
|
|
1
1
|
module GameAnalytics
|
2
|
-
module Common
|
3
|
-
|
4
|
-
def logger
|
5
|
-
GameAnalytics.logger
|
6
|
-
end
|
7
|
-
|
8
|
-
def options
|
9
|
-
GameAnalytics.options
|
10
|
-
end
|
11
|
-
|
12
|
-
def client
|
13
|
-
GameAnalytics.client
|
14
|
-
end
|
15
|
-
|
16
|
-
def disabled
|
17
|
-
GameAnalytics.disabled
|
18
|
-
end
|
2
|
+
module Common
|
19
3
|
|
20
|
-
|
4
|
+
def logger
|
5
|
+
GameAnalytics.logger
|
6
|
+
end
|
7
|
+
|
8
|
+
def options
|
9
|
+
GameAnalytics.options
|
10
|
+
end
|
11
|
+
|
12
|
+
def client
|
13
|
+
GameAnalytics.client
|
14
|
+
end
|
15
|
+
|
16
|
+
def disabled
|
17
|
+
GameAnalytics.disabled
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
21
|
end
|
@@ -1,47 +1,65 @@
|
|
1
1
|
module GameAnalytics
|
2
|
-
class Metric
|
3
|
-
|
4
|
-
include Common
|
2
|
+
class Metric
|
5
3
|
|
6
|
-
|
4
|
+
include Common
|
7
5
|
|
8
|
-
|
9
|
-
metric = self.new(data)
|
10
|
-
metric.origin_ip = ip
|
11
|
-
metric
|
12
|
-
end
|
6
|
+
attr_accessor :origin_ip
|
13
7
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
def as_json(options={})
|
21
|
-
@data
|
22
|
-
end
|
23
|
-
|
24
|
-
def required_keys
|
25
|
-
[:user_id, :session_id, :build, :event_id]
|
26
|
-
end
|
8
|
+
def self.new_with_ip(ip, data={})
|
9
|
+
metric = self.new(data)
|
10
|
+
metric.origin_ip = ip
|
11
|
+
metric
|
12
|
+
end
|
27
13
|
|
14
|
+
def initialize(data={})
|
15
|
+
@data = data
|
16
|
+
needs = required_keys - data.keys
|
17
|
+
raise "missing required fields #{needs}" unless needs.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
def as_json(options={})
|
21
|
+
@data
|
22
|
+
end
|
28
23
|
|
29
|
-
class Design < Metric
|
30
|
-
end
|
31
|
-
|
32
|
-
class User < Metric
|
33
|
-
end
|
34
|
-
|
35
|
-
class Business < Metric
|
36
|
-
|
37
24
|
def required_keys
|
38
|
-
|
25
|
+
self.class.const_get("REQUIRED_KEYS")
|
39
26
|
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
class Quality < Metric
|
44
|
-
end
|
45
27
|
|
46
|
-
|
28
|
+
|
29
|
+
class Design < Metric
|
30
|
+
|
31
|
+
REQUIRED_KEYS = [:user_id, :session_id, :build, :event_id]
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
class User < Metric
|
36
|
+
|
37
|
+
REQUIRED_KEYS = [:user_id, :session_id, :build, :event_id]
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class Business < Metric
|
42
|
+
|
43
|
+
REQUIRED_KEYS = [:user_id, :session_id, :build, :event_id, :currency, :amount]
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
class Quality < Metric
|
48
|
+
|
49
|
+
REQUIRED_KEYS = [:user_id, :session_id, :build, :event_id]
|
50
|
+
|
51
|
+
def initialize(data={})
|
52
|
+
super
|
53
|
+
logger.warn('Deprecation Warning: the Quality metric is deprecated, please use the Error metric instead')
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
class Error < Metric
|
59
|
+
|
60
|
+
REQUIRED_KEYS = [:user_id, :session_id, :build]
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
47
65
|
end
|
@@ -2,37 +2,37 @@ require 'digest/md5'
|
|
2
2
|
require 'httpclient'
|
3
3
|
|
4
4
|
module GameAnalytics
|
5
|
-
class Worker
|
6
|
-
|
7
|
-
include Common
|
5
|
+
class Worker
|
8
6
|
|
7
|
+
include Common
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def process(unit)
|
17
|
-
metric = unit.is_a?(Array) ? unit.first : unit
|
18
|
-
klass = metric.class
|
19
|
-
|
20
|
-
json_data = unit.to_json
|
21
|
-
header = {'Authorization' => Digest::MD5.hexdigest(json_data + options[:secret_key])}
|
22
|
-
header['X-Forwarded-For'] = metric.origin_ip if metric.origin_ip
|
23
|
-
category = klass.name.demodulize.downcase
|
24
|
-
url = "#{@url_base}/#{category}"
|
25
|
-
logger.info "GameAnalytics <: #{url} #{json_data} #{header.inspect}"
|
26
|
-
resp = @http.post(url, :body => json_data, :header => header)
|
27
|
-
logger.info "GameAnalytics >: #{resp.content} (#{resp.status})"
|
28
|
-
end
|
29
|
-
|
30
|
-
def run
|
31
|
-
logger.info "GameAnalytics worker running"
|
32
|
-
loop do
|
33
|
-
process @queue.pop
|
9
|
+
|
10
|
+
def initialize(q)
|
11
|
+
@queue = q
|
12
|
+
@http = HTTPClient.new
|
13
|
+
@url_base = "http://api.gameanalytics.com/1/#{options[:game_key]}"
|
34
14
|
end
|
35
|
-
end
|
36
15
|
|
37
|
-
|
16
|
+
def process(unit)
|
17
|
+
metric = unit.is_a?(Array) ? unit.first : unit
|
18
|
+
klass = metric.class
|
19
|
+
|
20
|
+
json_data = unit.to_json
|
21
|
+
header = {'Authorization' => Digest::MD5.hexdigest(json_data + options[:secret_key])}
|
22
|
+
header['X-Forwarded-For'] = metric.origin_ip if metric.origin_ip
|
23
|
+
category = klass.name.demodulize.downcase
|
24
|
+
url = "#{@url_base}/#{category}"
|
25
|
+
logger.info "GameAnalytics <: #{url} #{json_data} #{header.inspect}"
|
26
|
+
resp = @http.post(url, :body => json_data, :header => header)
|
27
|
+
logger.info "GameAnalytics >: #{resp.content} (#{resp.status})"
|
28
|
+
end
|
29
|
+
|
30
|
+
def run
|
31
|
+
logger.info "GameAnalytics worker running"
|
32
|
+
loop do
|
33
|
+
process @queue.pop
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
38
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: game_analytics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- wlipa
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-11-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: httpclient
|
@@ -107,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
107
|
version: '0'
|
108
108
|
requirements: []
|
109
109
|
rubyforge_project:
|
110
|
-
rubygems_version: 2.4.
|
110
|
+
rubygems_version: 2.4.8
|
111
111
|
signing_key:
|
112
112
|
specification_version: 4
|
113
113
|
summary: Interface to the REST API of the metrics collection service gameanalytics.com
|