snowplow-tracker 0.2.0 → 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 +8 -8
- data/lib/snowplow-tracker.rb +3 -0
- data/lib/snowplow-tracker/contracts.rb +30 -0
- data/lib/snowplow-tracker/emitters.rb +218 -0
- data/lib/snowplow-tracker/subject.rb +97 -0
- data/lib/snowplow-tracker/tracker.rb +74 -101
- data/lib/snowplow-tracker/version.rb +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZjRhYzM4NmY5ZjI3ZWNkZDY0MGJkNDRhMWRiZGU0N2I0YjhkMDU3Yg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MTVkNjQxNDU2OWRhZWU2MDc5YjRkMmNhNTg5NmVlNjU4YTE1MzY2OA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YzM1MTc1Y2E0ZGQ1ZjY3NzljZDcwNDdjYWUzYjM4Y2MzMTQ1MTE4ODUwYjk0
|
10
|
+
NzIxZGQ1NjY1MDAzY2IzZTljN2M4ZWM0NmEwMTZmNzllZWY0NzYzOGMyNDMz
|
11
|
+
ODZlNjY4NDYyZDlhY2ZmNGMyZDQ1M2YwMDYwOGIxYTEwMDU2NTI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MDMxMzZjYTQxNWU3NDhhYzUwZjJhNjkwNGI4MTk2ZTI1YzBmMjE1MDEzNWZj
|
14
|
+
MTY5OGU5ZWE1MTExYmQ0YWRhMmFiNjA5MzgxNDhlNDg4NzEyYWNlMTQ1ZTU4
|
15
|
+
NWE5MTkxNjg1NDUxZTU0ZjgyZGE1NjFmNWU1ODExNDZkZGY5ZDA=
|
data/lib/snowplow-tracker.rb
CHANGED
@@ -13,6 +13,9 @@
|
|
13
13
|
# Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
|
14
14
|
# License:: Apache License Version 2.0
|
15
15
|
|
16
|
+
require 'snowplow-tracker/contracts.rb'
|
16
17
|
require 'snowplow-tracker/version.rb'
|
17
18
|
require 'snowplow-tracker/payload.rb'
|
19
|
+
require 'snowplow-tracker/subject.rb'
|
20
|
+
require 'snowplow-tracker/emitters.rb'
|
18
21
|
require 'snowplow-tracker/tracker.rb'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright (c) 2013-2014 Snowplow Analytics Ltd. All rights reserved.
|
2
|
+
#
|
3
|
+
# This program is licensed to you under the Apache License Version 2.0,
|
4
|
+
# and you may not use this file except in compliance with the Apache License Version 2.0.
|
5
|
+
# You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
|
6
|
+
#
|
7
|
+
# Unless required by applicable law or agreed to in writing,
|
8
|
+
# software distributed under the Apache License Version 2.0 is distributed on an
|
9
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
# See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
|
11
|
+
|
12
|
+
# Author:: Alex Dean, Fred Blundun (mailto:support@snowplowanalytics.com)
|
13
|
+
# Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
|
14
|
+
# License:: Apache License Version 2.0
|
15
|
+
|
16
|
+
require 'contracts'
|
17
|
+
include Contracts
|
18
|
+
|
19
|
+
module SnowplowTracker
|
20
|
+
|
21
|
+
ORIGINAL_FAILURE_CALLBACK = Contract.method(:failure_callback)
|
22
|
+
|
23
|
+
def self.disable_contracts
|
24
|
+
Contract.define_singleton_method(:failure_callback) {|data| true}
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.enable_contracts
|
28
|
+
Contract.define_singleton_method(:failure_callback, ORIGINAL_FAILURE_CALLBACK)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
# Copyright (c) 2013-2014 Snowplow Analytics Ltd. All rights reserved.
|
2
|
+
#
|
3
|
+
# This program is licensed to you under the Apache License Version 2.0,
|
4
|
+
# and you may not use this file except in compliance with the Apache License Version 2.0.
|
5
|
+
# You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
|
6
|
+
#
|
7
|
+
# Unless required by applicable law or agreed to in writing,
|
8
|
+
# software distributed under the Apache License Version 2.0 is distributed on an
|
9
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
# See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
|
11
|
+
|
12
|
+
# Author:: Alex Dean, Fred Blundun (mailto:support@snowplowanalytics.com)
|
13
|
+
# Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
|
14
|
+
# License:: Apache License Version 2.0
|
15
|
+
|
16
|
+
require 'net/http'
|
17
|
+
require 'set'
|
18
|
+
require 'logger'
|
19
|
+
require 'contracts'
|
20
|
+
include Contracts
|
21
|
+
|
22
|
+
module SnowplowTracker
|
23
|
+
|
24
|
+
LOGGER = Logger.new(STDERR)
|
25
|
+
LOGGER.level = Logger::INFO
|
26
|
+
|
27
|
+
class Emitter
|
28
|
+
|
29
|
+
@@ConfigHash = ({
|
30
|
+
:protocol => Maybe[Or['http', 'https']],
|
31
|
+
:port => Maybe[Num],
|
32
|
+
:method => Maybe[Or['get', 'post']],
|
33
|
+
:buffer_size => Maybe[Num],
|
34
|
+
:on_success => Maybe[Func[Num => Any]],
|
35
|
+
:on_failure => Maybe[Func[Num, Hash => Any]]
|
36
|
+
})
|
37
|
+
|
38
|
+
@@StrictConfigHash = And[@@ConfigHash, lambda { |x|
|
39
|
+
x.class == Hash and Set.new(x.keys).subset? Set.new(@@ConfigHash.keys)
|
40
|
+
}]
|
41
|
+
|
42
|
+
@@DefaultConfig = {
|
43
|
+
:protocol => 'http',
|
44
|
+
:method => 'get'
|
45
|
+
}
|
46
|
+
|
47
|
+
Contract String, @@StrictConfigHash => lambda { |x| x.is_a? Emitter }
|
48
|
+
def initialize(endpoint, config={})
|
49
|
+
config = @@DefaultConfig.merge(config)
|
50
|
+
@collector_uri = as_collector_uri(endpoint, config[:protocol], config[:port], config[:method])
|
51
|
+
@buffer = []
|
52
|
+
if not config[:buffer_size].nil?
|
53
|
+
@buffer_size = config[:buffer_size]
|
54
|
+
elsif config[:method] == 'get'
|
55
|
+
@buffer_size = 0
|
56
|
+
else
|
57
|
+
@buffer_size = 10
|
58
|
+
end
|
59
|
+
@method = config[:method]
|
60
|
+
@on_success = config[:on_success]
|
61
|
+
@on_failure = config[:on_failure]
|
62
|
+
@threads = []
|
63
|
+
LOGGER.info("#{self.class} initialized with endpoint #{@collector_uri}")
|
64
|
+
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
# Build the collector URI from the configuration hash
|
69
|
+
#
|
70
|
+
Contract String, String, Maybe[Num], String => String
|
71
|
+
def as_collector_uri(endpoint, protocol, port, method)
|
72
|
+
port_string = port == nil ? '' : ":#{port.to_s}"
|
73
|
+
path = method == 'get' ? '/i' : '/com.snowplowanalytics.snowplow/tp2'
|
74
|
+
|
75
|
+
"#{protocol}://#{endpoint}#{port_string}#{path}"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add an event to the buffer and flush it if maximum size has been reached
|
79
|
+
#
|
80
|
+
Contract Hash => nil
|
81
|
+
def input(payload)
|
82
|
+
payload.each { |k,v| payload[k] = v.to_s}
|
83
|
+
@buffer.push(payload)
|
84
|
+
if @buffer.size > @buffer_size
|
85
|
+
flush
|
86
|
+
end
|
87
|
+
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# Flush the buffer
|
92
|
+
#
|
93
|
+
Contract Bool => nil
|
94
|
+
def flush(sync=false)
|
95
|
+
send_requests
|
96
|
+
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
|
100
|
+
# Send all events in the buffer to the collector
|
101
|
+
#
|
102
|
+
Contract None => nil
|
103
|
+
def send_requests
|
104
|
+
LOGGER.info("Attempting to send #{@buffer.size} request#{@buffer.size == 1 ? '' : 's'}")
|
105
|
+
temp_buffer = @buffer
|
106
|
+
@buffer = []
|
107
|
+
|
108
|
+
if @method == 'get'
|
109
|
+
success_count = 0
|
110
|
+
unsent_requests = []
|
111
|
+
temp_buffer.each do |payload|
|
112
|
+
request = http_get(payload)
|
113
|
+
if request.code.to_i == 200
|
114
|
+
success_count += 1
|
115
|
+
else
|
116
|
+
unsent_requests.push(payload)
|
117
|
+
end
|
118
|
+
if unsent_requests.size == 0
|
119
|
+
unless @on_success.nil?
|
120
|
+
@on_success.call(success_count)
|
121
|
+
end
|
122
|
+
else
|
123
|
+
unless @on_failure.nil?
|
124
|
+
@on_failure.call(success_count, unsent_requests)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
elsif @method == 'post'
|
130
|
+
if temp_buffer.size > 0
|
131
|
+
request = http_post({
|
132
|
+
'schema' => 'iglu:com.snowplowanalytics.snowplow/payload_data/1-0-0',
|
133
|
+
'data' => temp_buffer
|
134
|
+
})
|
135
|
+
|
136
|
+
if request.code.to_i == 200
|
137
|
+
unless @on_success.nil?
|
138
|
+
@on_success.call(temp_buffer.size)
|
139
|
+
end
|
140
|
+
else
|
141
|
+
unless @on_failure.nil?
|
142
|
+
@on_failure.call(0, temp_buffer)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
nil
|
150
|
+
end
|
151
|
+
|
152
|
+
# Send a GET request
|
153
|
+
#
|
154
|
+
Contract Hash => lambda { |x| x.is_a? Net::HTTPResponse }
|
155
|
+
def http_get(payload)
|
156
|
+
destination = URI(@collector_uri + '?' + URI.encode_www_form(payload))
|
157
|
+
LOGGER.info("Sending GET request to #{@collector_uri}...")
|
158
|
+
LOGGER.debug("Payload: #{payload}")
|
159
|
+
response = Net::HTTP.get_response(destination)
|
160
|
+
LOGGER.add(response.code == '200' ? Logger::INFO : Logger::WARN) {
|
161
|
+
"GET request to #{@collector_uri} finished with status code #{response.code}"
|
162
|
+
}
|
163
|
+
|
164
|
+
response
|
165
|
+
end
|
166
|
+
|
167
|
+
# Send a POST request
|
168
|
+
#
|
169
|
+
Contract Hash => lambda { |x| x.is_a? Net::HTTPResponse }
|
170
|
+
def http_post(payload)
|
171
|
+
LOGGER.info("Sending POST request to #{@collector_uri}...")
|
172
|
+
LOGGER.debug("Payload: #{payload}")
|
173
|
+
destination = URI(@collector_uri)
|
174
|
+
http = Net::HTTP.new(destination.host, destination.port)
|
175
|
+
request = Net::HTTP::Post.new(destination)
|
176
|
+
request.form_data = payload
|
177
|
+
request.set_content_type('application/json; charset=utf-8')
|
178
|
+
response = http.request(request)
|
179
|
+
LOGGER.add(response.code == '200' ? Logger::INFO : Logger::WARN) {
|
180
|
+
"POST request to #{@collector_uri} finished with status code #{response.code}"
|
181
|
+
}
|
182
|
+
|
183
|
+
response
|
184
|
+
end
|
185
|
+
|
186
|
+
private :as_collector_uri,
|
187
|
+
:http_get,
|
188
|
+
:http_post
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
class AsyncEmitter < Emitter
|
194
|
+
|
195
|
+
# Flush the buffer in a new thread
|
196
|
+
# If sync is true, block until all flushing threads have exited
|
197
|
+
#
|
198
|
+
def flush(sync=false)
|
199
|
+
t = Thread.new do
|
200
|
+
send_requests
|
201
|
+
end
|
202
|
+
t.abort_on_exception = true
|
203
|
+
@threads.select!{ |thread| thread.alive?}
|
204
|
+
@threads.push(t)
|
205
|
+
|
206
|
+
if sync
|
207
|
+
LOGGER.info('Starting synchronous flush')
|
208
|
+
@threads.each do |thread|
|
209
|
+
thread.join(10)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
nil
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Copyright (c) 2013-2014 Snowplow Analytics Ltd. All rights reserved.
|
2
|
+
#
|
3
|
+
# This program is licensed to you under the Apache License Version 2.0,
|
4
|
+
# and you may not use this file except in compliance with the Apache License Version 2.0.
|
5
|
+
# You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
|
6
|
+
#
|
7
|
+
# Unless required by applicable law or agreed to in writing,
|
8
|
+
# software distributed under the Apache License Version 2.0 is distributed on an
|
9
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
# See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
|
11
|
+
|
12
|
+
# Author:: Alex Dean, Fred Blundun (mailto:support@snowplowanalytics.com)
|
13
|
+
# Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
|
14
|
+
# License:: Apache License Version 2.0
|
15
|
+
|
16
|
+
require 'contracts'
|
17
|
+
include Contracts
|
18
|
+
|
19
|
+
module SnowplowTracker
|
20
|
+
|
21
|
+
class Subject
|
22
|
+
|
23
|
+
@@default_platform = 'srv'
|
24
|
+
@@supported_platforms = ['pc', 'tv', 'mob', 'cnsl', 'iot']
|
25
|
+
|
26
|
+
attr_reader :standard_nv_pairs
|
27
|
+
|
28
|
+
Contract None => Subject
|
29
|
+
def initialize
|
30
|
+
@standard_nv_pairs = {"p" => @@default_platform}
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# Specify the platform
|
35
|
+
#
|
36
|
+
Contract String => Subject
|
37
|
+
def set_platform(value)
|
38
|
+
if @@supported_platforms.include?(value)
|
39
|
+
@standard_nv_pairs['p'] = value
|
40
|
+
else
|
41
|
+
raise "#{value} is not a supported platform"
|
42
|
+
end
|
43
|
+
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
# Set the business-defined user ID for a user
|
48
|
+
#
|
49
|
+
Contract String => Subject
|
50
|
+
def set_user_id(user_id)
|
51
|
+
@standard_nv_pairs['uid'] = user_id
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
# Set the screen resolution for a device
|
56
|
+
#
|
57
|
+
Contract Num, Num => Subject
|
58
|
+
def set_screen_resolution(width, height)
|
59
|
+
@standard_nv_pairs['res'] = "#{width}x#{height}"
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
# Set the dimensions of the current viewport
|
64
|
+
#
|
65
|
+
Contract Num, Num => Subject
|
66
|
+
def set_viewport(width, height)
|
67
|
+
@standard_nv_pairs['vp'] = "#{width}x#{height}"
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
# Set the color depth of the device in bits per pixel
|
72
|
+
#
|
73
|
+
Contract Num => Subject
|
74
|
+
def set_color_depth(depth)
|
75
|
+
@standard_nv_pairs['cd'] = depth
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# Set the timezone field
|
80
|
+
#
|
81
|
+
Contract String => Subject
|
82
|
+
def set_timezone(timezone)
|
83
|
+
@standard_nv_pairs['tz'] = timezone
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
# Set the language field
|
88
|
+
#
|
89
|
+
Contract String => Subject
|
90
|
+
def set_lang(lang)
|
91
|
+
@standard_nv_pairs['lang'] = lang
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -13,7 +13,6 @@
|
|
13
13
|
# Copyright:: Copyright (c) 2013-2014 Snowplow Analytics Ltd
|
14
14
|
# License:: Apache License Version 2.0
|
15
15
|
|
16
|
-
require 'net/http'
|
17
16
|
require 'contracts'
|
18
17
|
require 'set'
|
19
18
|
include Contracts
|
@@ -24,6 +23,8 @@ module SnowplowTracker
|
|
24
23
|
|
25
24
|
class Tracker
|
26
25
|
|
26
|
+
@@EmitterInput = Or[lambda {|x| x.is_a? Emitter}, ArrayOf[lambda {|x| x.is_a? Emitter}]]
|
27
|
+
|
27
28
|
@@required_transaction_keys = Set.new(%w(order_id total_value))
|
28
29
|
@@recognised_transaction_keys = Set.new(%w(order_id total_value affiliation tax_value shipping city state country currency))
|
29
30
|
|
@@ -66,38 +67,41 @@ module SnowplowTracker
|
|
66
67
|
|
67
68
|
@@version = TRACKER_VERSION
|
68
69
|
@@default_encode_base64 = true
|
69
|
-
@@default_platform = 'pc'
|
70
|
-
@@supported_platforms = ['pc', 'tv', 'mob', 'cnsl', 'iot']
|
71
|
-
@@http_errors = ['host not found',
|
72
|
-
'No address associated with name',
|
73
|
-
'No address associated with hostname']
|
74
70
|
|
75
71
|
@@base_schema_path = "iglu:com.snowplowanalytics.snowplow"
|
76
72
|
@@schema_tag = "jsonschema"
|
77
73
|
@@context_schema = "#{@@base_schema_path}/contexts/#{@@schema_tag}/1-0-0"
|
78
74
|
@@unstruct_event_schema = "#{@@base_schema_path}/unstruct_event/#{@@schema_tag}/1-0-0"
|
79
75
|
|
80
|
-
Contract
|
81
|
-
def initialize(
|
82
|
-
@
|
76
|
+
Contract @@EmitterInput, Maybe[Subject], Maybe[String], Maybe[String], Bool => Tracker
|
77
|
+
def initialize(emitters, subject=nil, namespace=nil, app_id=nil, encode_base64=@@default_encode_base64)
|
78
|
+
@emitters = Array(emitters)
|
79
|
+
if subject.nil?
|
80
|
+
@subject = Subject.new
|
81
|
+
else
|
82
|
+
@subject = subject
|
83
|
+
end
|
83
84
|
@standard_nv_pairs = {
|
84
85
|
'tna' => namespace,
|
85
86
|
'tv' => @@version,
|
86
|
-
'p' => @@default_platform,
|
87
87
|
'aid' => app_id
|
88
88
|
}
|
89
89
|
@config = {
|
90
90
|
'encode_base64' => encode_base64
|
91
91
|
}
|
92
92
|
@uuid = UUID.new
|
93
|
+
|
93
94
|
self
|
94
95
|
end
|
95
96
|
|
96
|
-
#
|
97
|
+
# Call subject methods from tracker instance
|
97
98
|
#
|
98
|
-
|
99
|
-
|
100
|
-
|
99
|
+
Subject.instance_methods(false).each do |name|
|
100
|
+
define_method name, ->(*splat) do
|
101
|
+
@subject.method(name.to_sym).call(*splat)
|
102
|
+
|
103
|
+
self
|
104
|
+
end
|
101
105
|
end
|
102
106
|
|
103
107
|
# Generates a type-4 UUID to identify this event
|
@@ -123,92 +127,24 @@ module SnowplowTracker
|
|
123
127
|
}
|
124
128
|
end
|
125
129
|
|
126
|
-
# Send request
|
127
|
-
#
|
128
|
-
Contract Payload => [Bool, Num]
|
129
|
-
def http_get(payload)
|
130
|
-
destination = URI(@collector_uri + '?' + URI.encode_www_form(payload.context))
|
131
|
-
r = Net::HTTP.get_response(destination)
|
132
|
-
if @@http_errors.include? r.code
|
133
|
-
return false, "Host [#{r.host}] not found (possible connectivity error)"
|
134
|
-
elsif r.code.to_i < 0 or 400 <= r.code.to_i
|
135
|
-
return false, r.code.to_i
|
136
|
-
else
|
137
|
-
return true, r.code.to_i
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
# Setter methods
|
142
|
-
|
143
|
-
# Specify the platform
|
144
|
-
#
|
145
|
-
Contract String => String
|
146
|
-
def set_platform(value)
|
147
|
-
if @@supported_platforms.include?(value)
|
148
|
-
@standard_nv_pairs['p'] = value
|
149
|
-
else
|
150
|
-
raise "#{value} is not a supported platform"
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
# Set the business-defined user ID for a user
|
155
|
-
#
|
156
|
-
Contract String => String
|
157
|
-
def set_user_id(user_id)
|
158
|
-
@standard_nv_pairs['uid'] = user_id
|
159
|
-
end
|
160
|
-
|
161
|
-
# Set the screen resolution for a device
|
162
|
-
#
|
163
|
-
Contract Num, Num => String
|
164
|
-
def set_screen_resolution(width, height)
|
165
|
-
@standard_nv_pairs['res'] = "#{width}x#{height}"
|
166
|
-
end
|
167
|
-
|
168
|
-
# Set the dimensions of the current viewport
|
169
|
-
#
|
170
|
-
Contract Num, Num => String
|
171
|
-
def set_viewport(width, height)
|
172
|
-
@standard_nv_pairs['vp'] = "#{width}x#{height}"
|
173
|
-
end
|
174
|
-
|
175
|
-
# Set the color depth of the device in bits per pixel
|
176
|
-
#
|
177
|
-
Contract Num => Num
|
178
|
-
def set_color_depth(depth)
|
179
|
-
@standard_nv_pairs['cd'] = depth
|
180
|
-
end
|
181
|
-
|
182
|
-
# Set the timezone field
|
183
|
-
#
|
184
|
-
Contract String => String
|
185
|
-
def set_timezone(timezone)
|
186
|
-
@standard_nv_pairs['tz'] = timezone
|
187
|
-
end
|
188
|
-
|
189
|
-
# Set the language field
|
190
|
-
#
|
191
|
-
Contract String => String
|
192
|
-
def set_lang(lang)
|
193
|
-
@standard_nv_pairs['lang'] = lang
|
194
|
-
end
|
195
|
-
|
196
130
|
# Tracking methods
|
197
131
|
|
198
132
|
# Attaches all the fields in @standard_nv_pairs to the request
|
199
133
|
# Only attaches the context vendor if the event has a custom context
|
200
134
|
#
|
201
|
-
Contract Payload =>
|
135
|
+
Contract Payload => nil
|
202
136
|
def track(pb)
|
137
|
+
pb.add_dict(@subject.standard_nv_pairs)
|
203
138
|
pb.add_dict(@standard_nv_pairs)
|
204
139
|
pb.add('eid', get_event_id())
|
140
|
+
@emitters.each{ |emitter| emitter.input(pb.context)}
|
205
141
|
|
206
|
-
|
142
|
+
nil
|
207
143
|
end
|
208
144
|
|
209
145
|
# Log a visit to this page
|
210
146
|
#
|
211
|
-
Contract String, Maybe[String], Maybe[String], Maybe[@@ContextsInput] =>
|
147
|
+
Contract String, Maybe[String], Maybe[String], Maybe[@@ContextsInput] => Tracker
|
212
148
|
def track_page_view(page_url, page_title=nil, referrer=nil, context=nil, tstamp=nil)
|
213
149
|
pb = Payload.new
|
214
150
|
pb.add('e', 'pv')
|
@@ -224,12 +160,14 @@ module SnowplowTracker
|
|
224
160
|
end
|
225
161
|
pb.add('dtm', tstamp)
|
226
162
|
track(pb)
|
163
|
+
|
164
|
+
self
|
227
165
|
end
|
228
166
|
|
229
167
|
# Track a single item within an ecommerce transaction
|
230
168
|
# Not part of the public API
|
231
169
|
#
|
232
|
-
Contract @@AugmentedItem =>
|
170
|
+
Contract @@AugmentedItem => self
|
233
171
|
def track_ecommerce_transaction_item(argmap)
|
234
172
|
pb = Payload.new
|
235
173
|
pb.add('e', 'ti')
|
@@ -245,11 +183,13 @@ module SnowplowTracker
|
|
245
183
|
end
|
246
184
|
pb.add('dtm', argmap['tstamp'])
|
247
185
|
track(pb)
|
186
|
+
|
187
|
+
self
|
248
188
|
end
|
249
189
|
|
250
190
|
# Track an ecommerce transaction and all the items in it
|
251
191
|
#
|
252
|
-
Contract @@Transaction, ArrayOf[@@Item], Maybe[@@ContextsInput], Maybe[Num] =>
|
192
|
+
Contract @@Transaction, ArrayOf[@@Item], Maybe[@@ContextsInput], Maybe[Num] => Tracker
|
253
193
|
def track_ecommerce_transaction(transaction, items,
|
254
194
|
context=nil, tstamp=nil)
|
255
195
|
pb = Payload.new
|
@@ -272,22 +212,21 @@ module SnowplowTracker
|
|
272
212
|
end
|
273
213
|
pb.add('dtm', tstamp)
|
274
214
|
|
275
|
-
|
276
|
-
item_results = []
|
215
|
+
track(pb)
|
277
216
|
|
278
217
|
for item in items
|
279
218
|
item['tstamp'] = tstamp
|
280
219
|
item['order_id'] = transaction['order_id']
|
281
220
|
item['currency'] = transaction['currency']
|
282
|
-
|
221
|
+
track_ecommerce_transaction_item(item)
|
283
222
|
end
|
284
223
|
|
285
|
-
|
224
|
+
self
|
286
225
|
end
|
287
226
|
|
288
227
|
# Track a structured event
|
289
228
|
#
|
290
|
-
Contract String, String, Maybe[String], Maybe[String], Maybe[Num], Maybe[@@ContextsInput], Maybe[Num] =>
|
229
|
+
Contract String, String, Maybe[String], Maybe[String], Maybe[Num], Maybe[@@ContextsInput], Maybe[Num] => Tracker
|
291
230
|
def track_struct_event(category, action, label=nil, property=nil, value=nil, context=nil, tstamp=nil)
|
292
231
|
pb = Payload.new
|
293
232
|
pb.add('e', 'se')
|
@@ -304,13 +243,18 @@ module SnowplowTracker
|
|
304
243
|
end
|
305
244
|
pb.add('dtm', tstamp)
|
306
245
|
track(pb)
|
246
|
+
|
247
|
+
self
|
307
248
|
end
|
308
249
|
|
309
250
|
# Track a screen view event
|
310
251
|
#
|
311
|
-
Contract String, Maybe[String], Maybe[@@ContextsInput], Maybe[Num] =>
|
312
|
-
def track_screen_view(name, id=nil, context=nil, tstamp=nil)
|
313
|
-
screen_view_properties = {
|
252
|
+
Contract Maybe[String], Maybe[String], Maybe[@@ContextsInput], Maybe[Num] => Tracker
|
253
|
+
def track_screen_view(name=nil, id=nil, context=nil, tstamp=nil)
|
254
|
+
screen_view_properties = {}
|
255
|
+
unless name.nil?
|
256
|
+
screen_view_properties['name'] = name
|
257
|
+
end
|
314
258
|
unless id.nil?
|
315
259
|
screen_view_properties['id'] = id
|
316
260
|
end
|
@@ -318,11 +262,13 @@ module SnowplowTracker
|
|
318
262
|
event_json = {schema: screen_view_schema, data: screen_view_properties}
|
319
263
|
|
320
264
|
self.track_unstruct_event(event_json, context, tstamp)
|
265
|
+
|
266
|
+
self
|
321
267
|
end
|
322
268
|
|
323
269
|
# Track an unstructured event
|
324
270
|
#
|
325
|
-
Contract @@SelfDescribingJson, Maybe[@@ContextsInput], Maybe[Num] =>
|
271
|
+
Contract @@SelfDescribingJson, Maybe[@@ContextsInput], Maybe[Num] => Tracker
|
326
272
|
def track_unstruct_event(event_json, context=nil, tstamp=nil)
|
327
273
|
pb = Payload.new
|
328
274
|
pb.add('e', 'ue')
|
@@ -343,12 +289,39 @@ module SnowplowTracker
|
|
343
289
|
pb.add('dtm', tstamp)
|
344
290
|
|
345
291
|
track(pb)
|
292
|
+
|
293
|
+
self
|
294
|
+
end
|
295
|
+
|
296
|
+
# Flush all events stored in all emitters
|
297
|
+
#
|
298
|
+
Contract Bool => Tracker
|
299
|
+
def flush(sync=false)
|
300
|
+
@emitters.each do |emitter|
|
301
|
+
emitter.flush(sync)
|
302
|
+
end
|
303
|
+
|
304
|
+
self
|
305
|
+
end
|
306
|
+
|
307
|
+
# Set the subject of the events fired by the tracker
|
308
|
+
#
|
309
|
+
Contract Subject => Tracker
|
310
|
+
def set_subject(subject)
|
311
|
+
@subject = subject
|
312
|
+
self
|
313
|
+
end
|
314
|
+
|
315
|
+
# Add a new emitter
|
316
|
+
#
|
317
|
+
Contract Emitter => Tracker
|
318
|
+
def add_emitter(emitter)
|
319
|
+
@emitters.push(emitter)
|
320
|
+
self
|
346
321
|
end
|
347
322
|
|
348
|
-
private :
|
349
|
-
:get_timestamp,
|
323
|
+
private :get_timestamp,
|
350
324
|
:build_context,
|
351
|
-
:http_get,
|
352
325
|
:track,
|
353
326
|
:track_ecommerce_transaction_item
|
354
327
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snowplow-tracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Dean
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: contracts
|
@@ -76,10 +76,13 @@ extra_rdoc_files: []
|
|
76
76
|
files:
|
77
77
|
- LICENSE-2.0.txt
|
78
78
|
- README.md
|
79
|
-
- lib/snowplow-tracker.rb
|
79
|
+
- lib/snowplow-tracker/contracts.rb
|
80
|
+
- lib/snowplow-tracker/emitters.rb
|
80
81
|
- lib/snowplow-tracker/payload.rb
|
82
|
+
- lib/snowplow-tracker/subject.rb
|
81
83
|
- lib/snowplow-tracker/tracker.rb
|
82
84
|
- lib/snowplow-tracker/version.rb
|
85
|
+
- lib/snowplow-tracker.rb
|
83
86
|
homepage: http://github.com/snowplow/snowplow-ruby-tracker
|
84
87
|
licenses:
|
85
88
|
- Apache License 2.0
|
@@ -100,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
103
|
version: '0'
|
101
104
|
requirements: []
|
102
105
|
rubyforge_project:
|
103
|
-
rubygems_version: 2.
|
106
|
+
rubygems_version: 2.1.11
|
104
107
|
signing_key:
|
105
108
|
specification_version: 4
|
106
109
|
summary: Ruby Analytics for Snowplow
|