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 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