analytics-ruby 2.2.7 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/analytics +22 -7
- data/lib/segment/analytics.rb +3 -2
- data/lib/segment/analytics/client.rb +12 -0
- data/lib/segment/analytics/field_parser.rb +17 -9
- data/lib/segment/analytics/message_batch.rb +8 -1
- data/lib/segment/analytics/test_queue.rb +56 -0
- data/lib/segment/analytics/{request.rb → transport.rb} +11 -7
- data/lib/segment/analytics/utils.rb +2 -6
- data/lib/segment/analytics/version.rb +1 -1
- data/lib/segment/analytics/worker.rb +14 -4
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51f3f02afed05c9c8461b454e0a3067962a75b8efde0930db0098eebf4a62829
|
4
|
+
data.tar.gz: e7d486d6c6186535e9a005c4d950e6e29d2dd9937f9b6da625191d786f76846a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2ce09d450de65620eb99f9fae86aa5ce57709d53aa4a93c73c2d3db0b173afad532383a50fe4dcb953df72171b731a263ff7308aed79b646a25bc202c555e4d
|
7
|
+
data.tar.gz: b3625484ebca6117ae79fc42f03a595dff861b8c5ca02a6ef12ea9e933229c1479dad40b4db1d85e61ddf585c7c5a072d68e9cd21ced6b2482db338f45073707
|
data/bin/analytics
CHANGED
@@ -29,6 +29,7 @@ command :send do |c|
|
|
29
29
|
c.option '--userId=<userId>', String, 'the user id to send the event as'
|
30
30
|
c.option '--anonymousId=<anonymousId>', String, 'the anonymous user id to send the event as'
|
31
31
|
c.option '--context=<context>', 'additional context for the event (JSON-encoded)'
|
32
|
+
c.option '--integrations=<integrations>', 'additional integrations for the event (JSON-encoded)'
|
32
33
|
|
33
34
|
c.option '--event=<event>', String, 'the event name to send with the event'
|
34
35
|
c.option '--properties=<properties>', 'the event properties to send (JSON-encoded)'
|
@@ -38,6 +39,7 @@ command :send do |c|
|
|
38
39
|
c.option '--traits=<traits>', 'the identify/group traits to send (JSON-encoded)'
|
39
40
|
|
40
41
|
c.option '--groupId=<groupId>', String, 'the group id'
|
42
|
+
c.option '--previousId=<previousId>', String, 'the previous id'
|
41
43
|
|
42
44
|
c.action do |args, options|
|
43
45
|
Analytics = Segment::Analytics.new({
|
@@ -52,7 +54,8 @@ command :send do |c|
|
|
52
54
|
event: options.event,
|
53
55
|
anonymous_id: options.anonymousId,
|
54
56
|
properties: json_hash(options.properties),
|
55
|
-
context: json_hash(options.context)
|
57
|
+
context: json_hash(options.context),
|
58
|
+
integrations: json_hash(options.integrations)
|
56
59
|
})
|
57
60
|
when "page"
|
58
61
|
Analytics.page({
|
@@ -60,22 +63,25 @@ command :send do |c|
|
|
60
63
|
anonymous_id: options.anonymousId,
|
61
64
|
name: options.name,
|
62
65
|
properties: json_hash(options.properties),
|
63
|
-
context: json_hash(options.context)
|
66
|
+
context: json_hash(options.context),
|
67
|
+
integrations: json_hash(options.integrations)
|
64
68
|
})
|
65
69
|
when "screen"
|
66
70
|
Analytics.screen({
|
67
71
|
user_id: options.userId,
|
68
72
|
anonymous_id: options.anonymousId,
|
69
|
-
name:
|
70
|
-
|
71
|
-
|
73
|
+
name: options.name,
|
74
|
+
properties: json_hash(options.properties),
|
75
|
+
context: json_hash(options.context),
|
76
|
+
integrations: json_hash(options.integrations)
|
72
77
|
})
|
73
78
|
when "identify"
|
74
79
|
Analytics.identify({
|
75
80
|
user_id: options.userId,
|
76
81
|
anonymous_id: options.anonymousId,
|
77
82
|
traits: json_hash(options.traits),
|
78
|
-
context: json_hash(options.context)
|
83
|
+
context: json_hash(options.context),
|
84
|
+
integrations: json_hash(options.integrations)
|
79
85
|
})
|
80
86
|
when "group"
|
81
87
|
Analytics.group({
|
@@ -83,7 +89,16 @@ command :send do |c|
|
|
83
89
|
anonymous_id: options.anonymousId,
|
84
90
|
group_id: options.groupId,
|
85
91
|
traits: json_hash(options.traits),
|
86
|
-
context: json_hash(options.context)
|
92
|
+
context: json_hash(options.context),
|
93
|
+
integrations: json_hash(options.integrations)
|
94
|
+
})
|
95
|
+
when "alias"
|
96
|
+
Analytics.alias({
|
97
|
+
previous_id: options.previousId,
|
98
|
+
user_id: options.userId,
|
99
|
+
anonymous_id: options.anonymousId,
|
100
|
+
context: json_hash(options.context),
|
101
|
+
integrations: json_hash(options.integrations)
|
87
102
|
})
|
88
103
|
else
|
89
104
|
raise "Invalid Message Type #{options.type}"
|
data/lib/segment/analytics.rb
CHANGED
@@ -4,9 +4,10 @@ require 'segment/analytics/utils'
|
|
4
4
|
require 'segment/analytics/field_parser'
|
5
5
|
require 'segment/analytics/client'
|
6
6
|
require 'segment/analytics/worker'
|
7
|
-
require 'segment/analytics/
|
7
|
+
require 'segment/analytics/transport'
|
8
8
|
require 'segment/analytics/response'
|
9
9
|
require 'segment/analytics/logging'
|
10
|
+
require 'segment/analytics/test_queue'
|
10
11
|
|
11
12
|
module Segment
|
12
13
|
class Analytics
|
@@ -18,7 +19,7 @@ module Segment
|
|
18
19
|
# @option options [Boolean] :stub (false) If true, requests don't hit the
|
19
20
|
# server and are stubbed to be successful.
|
20
21
|
def initialize(options = {})
|
21
|
-
|
22
|
+
Transport.stub = options[:stub] if options.has_key?(:stub)
|
22
23
|
@client = Segment::Analytics::Client.new options
|
23
24
|
end
|
24
25
|
|
@@ -21,10 +21,12 @@ module Segment
|
|
21
21
|
symbolize_keys!(opts)
|
22
22
|
|
23
23
|
@queue = Queue.new
|
24
|
+
@test = opts[:test]
|
24
25
|
@write_key = opts[:write_key]
|
25
26
|
@max_queue_size = opts[:max_queue_size] || Defaults::Queue::MAX_SIZE
|
26
27
|
@worker_mutex = Mutex.new
|
27
28
|
@worker = Worker.new(@queue, @write_key, opts)
|
29
|
+
@worker_thread = nil
|
28
30
|
|
29
31
|
check_write_key!
|
30
32
|
|
@@ -142,6 +144,14 @@ module Segment
|
|
142
144
|
@queue.length
|
143
145
|
end
|
144
146
|
|
147
|
+
def test_queue
|
148
|
+
unless @test
|
149
|
+
raise 'Test queue only available when setting :test to true.'
|
150
|
+
end
|
151
|
+
|
152
|
+
@test_queue ||= TestQueue.new
|
153
|
+
end
|
154
|
+
|
145
155
|
private
|
146
156
|
|
147
157
|
# private: Enqueues the action.
|
@@ -151,6 +161,8 @@ module Segment
|
|
151
161
|
# add our request id for tracing purposes
|
152
162
|
action[:messageId] ||= uid
|
153
163
|
|
164
|
+
test_queue << action if @test
|
165
|
+
|
154
166
|
if @queue.length < @max_queue_size
|
155
167
|
@queue << action
|
156
168
|
ensure_worker_running
|
@@ -120,12 +120,15 @@ module Segment
|
|
120
120
|
|
121
121
|
isoify_dates! properties
|
122
122
|
|
123
|
-
common.merge({
|
123
|
+
parsed = common.merge({
|
124
124
|
:type => 'screen',
|
125
125
|
:name => name,
|
126
|
-
:properties => properties
|
127
|
-
:category => category
|
126
|
+
:properties => properties
|
128
127
|
})
|
128
|
+
|
129
|
+
parsed[:category] = category if category
|
130
|
+
|
131
|
+
parsed
|
129
132
|
end
|
130
133
|
|
131
134
|
private
|
@@ -140,15 +143,20 @@ module Segment
|
|
140
143
|
|
141
144
|
add_context! context
|
142
145
|
|
143
|
-
{
|
144
|
-
:anonymousId => fields[:anonymous_id],
|
146
|
+
parsed = {
|
145
147
|
:context => context,
|
146
|
-
:integrations => fields[:integrations],
|
147
148
|
:messageId => message_id,
|
148
|
-
:timestamp => datetime_in_iso8601(timestamp)
|
149
|
-
:userId => fields[:user_id],
|
150
|
-
:options => fields[:options] # Not in spec, retained for backward compatibility
|
149
|
+
:timestamp => datetime_in_iso8601(timestamp)
|
151
150
|
}
|
151
|
+
|
152
|
+
parsed[:userId] = fields[:user_id] if fields[:user_id]
|
153
|
+
parsed[:anonymousId] = fields[:anonymous_id] if fields[:anonymous_id]
|
154
|
+
parsed[:integrations] = fields[:integrations] if fields[:integrations]
|
155
|
+
|
156
|
+
# Not in spec, retained for backward compatibility
|
157
|
+
parsed[:options] = fields[:options] if fields[:options]
|
158
|
+
|
159
|
+
parsed
|
152
160
|
end
|
153
161
|
|
154
162
|
def check_user_id!(fields)
|
@@ -5,6 +5,8 @@ module Segment
|
|
5
5
|
class Analytics
|
6
6
|
# A batch of `Message`s to be sent to the API
|
7
7
|
class MessageBatch
|
8
|
+
class JSONGenerationError < StandardError; end
|
9
|
+
|
8
10
|
extend Forwardable
|
9
11
|
include Segment::Analytics::Logging
|
10
12
|
include Segment::Analytics::Defaults::MessageBatch
|
@@ -16,8 +18,13 @@ module Segment
|
|
16
18
|
end
|
17
19
|
|
18
20
|
def <<(message)
|
19
|
-
|
21
|
+
begin
|
22
|
+
message_json = message.to_json
|
23
|
+
rescue StandardError => e
|
24
|
+
raise JSONGenerationError, "Serialization error: #{e}"
|
25
|
+
end
|
20
26
|
|
27
|
+
message_json_size = message_json.bytesize
|
21
28
|
if message_too_big?(message_json_size)
|
22
29
|
logger.error('a message exceeded the maximum allowed size')
|
23
30
|
else
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Segment
|
2
|
+
class Analytics
|
3
|
+
class TestQueue
|
4
|
+
attr_reader :messages
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
reset!
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](key)
|
11
|
+
all[key]
|
12
|
+
end
|
13
|
+
|
14
|
+
def count
|
15
|
+
all.count
|
16
|
+
end
|
17
|
+
|
18
|
+
def <<(message)
|
19
|
+
all << message
|
20
|
+
send(message[:type]) << message
|
21
|
+
end
|
22
|
+
|
23
|
+
def alias
|
24
|
+
messages[:alias] ||= []
|
25
|
+
end
|
26
|
+
|
27
|
+
def all
|
28
|
+
messages[:all] ||= []
|
29
|
+
end
|
30
|
+
|
31
|
+
def group
|
32
|
+
messages[:group] ||= []
|
33
|
+
end
|
34
|
+
|
35
|
+
def identify
|
36
|
+
messages[:identify] ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
def page
|
40
|
+
messages[:page] ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
def screen
|
44
|
+
messages[:screen] ||= []
|
45
|
+
end
|
46
|
+
|
47
|
+
def track
|
48
|
+
messages[:track] ||= []
|
49
|
+
end
|
50
|
+
|
51
|
+
def reset!
|
52
|
+
@messages = {}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -9,13 +9,11 @@ require 'json'
|
|
9
9
|
|
10
10
|
module Segment
|
11
11
|
class Analytics
|
12
|
-
class
|
12
|
+
class Transport
|
13
13
|
include Segment::Analytics::Defaults::Request
|
14
14
|
include Segment::Analytics::Utils
|
15
15
|
include Segment::Analytics::Logging
|
16
16
|
|
17
|
-
# public: Creates a new request object to send analytics batch
|
18
|
-
#
|
19
17
|
def initialize(options = {})
|
20
18
|
options[:host] ||= HOST
|
21
19
|
options[:port] ||= PORT
|
@@ -34,10 +32,10 @@ module Segment
|
|
34
32
|
@http = http
|
35
33
|
end
|
36
34
|
|
37
|
-
#
|
35
|
+
# Sends a batch of messages to the API
|
38
36
|
#
|
39
|
-
#
|
40
|
-
def
|
37
|
+
# @return [Response] API response
|
38
|
+
def send(write_key, batch)
|
41
39
|
logger.debug("Sending request for #{batch.length} items")
|
42
40
|
|
43
41
|
last_response, exception = retry_with_backoff(@retries) do
|
@@ -59,6 +57,11 @@ module Segment
|
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
60
|
+
# Closes a persistent connection if it exists
|
61
|
+
def shutdown
|
62
|
+
@http.finish if @http.started?
|
63
|
+
end
|
64
|
+
|
62
65
|
private
|
63
66
|
|
64
67
|
def should_retry_request?(status_code, body)
|
@@ -113,10 +116,11 @@ module Segment
|
|
113
116
|
|
114
117
|
if self.class.stub
|
115
118
|
logger.debug "stubbed request to #{@path}: " \
|
116
|
-
"write key = #{write_key}, batch = JSON.generate(
|
119
|
+
"write key = #{write_key}, batch = #{JSON.generate(batch)}"
|
117
120
|
|
118
121
|
[200, '{}']
|
119
122
|
else
|
123
|
+
@http.start unless @http.started? # Maintain a persistent connection
|
120
124
|
response = @http.request(request, payload)
|
121
125
|
[response.code.to_i, response.body]
|
122
126
|
end
|
@@ -64,12 +64,8 @@ module Segment
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
def time_in_iso8601(time
|
68
|
-
|
69
|
-
('.%06i' % time.usec)[0, fraction_digits + 1]
|
70
|
-
end
|
71
|
-
|
72
|
-
"#{time.strftime('%Y-%m-%dT%H:%M:%S')}#{fraction}#{formatted_offset(time, true, 'Z')}"
|
67
|
+
def time_in_iso8601(time)
|
68
|
+
"#{time.strftime('%Y-%m-%dT%H:%M:%S.%6N')}#{formatted_offset(time, true, 'Z')}"
|
73
69
|
end
|
74
70
|
|
75
71
|
def date_in_iso8601(date)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'segment/analytics/defaults'
|
2
2
|
require 'segment/analytics/message_batch'
|
3
|
-
require 'segment/analytics/
|
3
|
+
require 'segment/analytics/transport'
|
4
4
|
require 'segment/analytics/utils'
|
5
5
|
|
6
6
|
module Segment
|
@@ -29,6 +29,7 @@ module Segment
|
|
29
29
|
batch_size = options[:batch_size] || Defaults::MessageBatch::MAX_SIZE
|
30
30
|
@batch = MessageBatch.new(batch_size)
|
31
31
|
@lock = Mutex.new
|
32
|
+
@transport = Transport.new(options)
|
32
33
|
end
|
33
34
|
|
34
35
|
# public: Continuously runs the loop to check for new events
|
@@ -38,15 +39,16 @@ module Segment
|
|
38
39
|
return if @queue.empty?
|
39
40
|
|
40
41
|
@lock.synchronize do
|
41
|
-
|
42
|
+
consume_message_from_queue! until @batch.full? || @queue.empty?
|
42
43
|
end
|
43
44
|
|
44
|
-
res =
|
45
|
-
|
45
|
+
res = @transport.send @write_key, @batch
|
46
46
|
@on_error.call(res.status, res.error) unless res.status == 200
|
47
47
|
|
48
48
|
@lock.synchronize { @batch.clear }
|
49
49
|
end
|
50
|
+
ensure
|
51
|
+
@transport.shutdown
|
50
52
|
end
|
51
53
|
|
52
54
|
# public: Check whether we have outstanding requests.
|
@@ -54,6 +56,14 @@ module Segment
|
|
54
56
|
def is_requesting?
|
55
57
|
@lock.synchronize { !@batch.empty? }
|
56
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def consume_message_from_queue!
|
63
|
+
@batch << @queue.pop
|
64
|
+
rescue MessageBatch::JSONGenerationError => e
|
65
|
+
@on_error.call(-1, e.to_s)
|
66
|
+
end
|
57
67
|
end
|
58
68
|
end
|
59
69
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: analytics-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Segment.io
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|
@@ -139,8 +139,9 @@ files:
|
|
139
139
|
- lib/segment/analytics/field_parser.rb
|
140
140
|
- lib/segment/analytics/logging.rb
|
141
141
|
- lib/segment/analytics/message_batch.rb
|
142
|
-
- lib/segment/analytics/request.rb
|
143
142
|
- lib/segment/analytics/response.rb
|
143
|
+
- lib/segment/analytics/test_queue.rb
|
144
|
+
- lib/segment/analytics/transport.rb
|
144
145
|
- lib/segment/analytics/utils.rb
|
145
146
|
- lib/segment/analytics/version.rb
|
146
147
|
- lib/segment/analytics/worker.rb
|
@@ -156,14 +157,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
157
|
requirements:
|
157
158
|
- - ">="
|
158
159
|
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
160
|
+
version: '2.0'
|
160
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
162
|
requirements:
|
162
163
|
- - ">="
|
163
164
|
- !ruby/object:Gem::Version
|
164
165
|
version: '0'
|
165
166
|
requirements: []
|
166
|
-
rubygems_version: 3.0.
|
167
|
+
rubygems_version: 3.0.8
|
167
168
|
signing_key:
|
168
169
|
specification_version: 4
|
169
170
|
summary: Segment.io analytics library
|