analytics-ruby 2.2.7 → 2.4.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 +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
|