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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c8742471c22e19783a69dee3403ddbd1ac2785b7bbd9608840432e34f4d50a5
4
- data.tar.gz: dad6dfe750ebf0746e2228cd29551afc23e4ce38d40c7df00184994e6d16db8b
3
+ metadata.gz: 51f3f02afed05c9c8461b454e0a3067962a75b8efde0930db0098eebf4a62829
4
+ data.tar.gz: e7d486d6c6186535e9a005c4d950e6e29d2dd9937f9b6da625191d786f76846a
5
5
  SHA512:
6
- metadata.gz: c5d305d7a968088a3ef5488faa360ce06ad6d97072bde0d6b068aae11bcb1824814f87fe1a18e8f09a231cbe34be2954b4565605cdb8a6b8e0d370ee56a6b492
7
- data.tar.gz: 154b45294bff8f12f2dd8bc338742889d11017983f5e516cca36e9446bbb3c0e6aa61ac35252aaf20ba39ececa96a58c264990f9a1dece39d6d5b39435ab1ad3
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: option.name,
70
- traits: json_hash(options.traits),
71
- properties: json_hash(option.properties)
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}"
@@ -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/request'
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
- Request.stub = options[:stub] if options.has_key?(:stub)
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
- message_json_size = message.to_json.bytesize
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 Request
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
- # public: Posts the write key and batch of messages to the API.
35
+ # Sends a batch of messages to the API
38
36
  #
39
- # returns - Response of the status and error if it exists
40
- def post(write_key, batch)
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(#{batch})"
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, fraction_digits = 3)
68
- fraction = if fraction_digits > 0
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,5 +1,5 @@
1
1
  module Segment
2
2
  class Analytics
3
- VERSION = '2.2.7'
3
+ VERSION = '2.4.0'
4
4
  end
5
5
  end
@@ -1,6 +1,6 @@
1
1
  require 'segment/analytics/defaults'
2
2
  require 'segment/analytics/message_batch'
3
- require 'segment/analytics/request'
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
- @batch << @queue.pop until @batch.full? || @queue.empty?
42
+ consume_message_from_queue! until @batch.full? || @queue.empty?
42
43
  end
43
44
 
44
- res = Request.new.post @write_key, @batch
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.2.7
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: 2019-05-10 00:00:00.000000000 Z
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.3
167
+ rubygems_version: 3.0.8
167
168
  signing_key:
168
169
  specification_version: 4
169
170
  summary: Segment.io analytics library