fluent-plugin-mixpanel 0.0.8 → 0.0.9

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
  SHA1:
3
- metadata.gz: 1f52ca8a3eeb5cf55c6edafa375a7ef3baa85129
4
- data.tar.gz: f1ec985b547288ee38f281513e5c6b8945a7da60
3
+ metadata.gz: 96a9b1fba6cc39288c0391efc0816839dcc081e7
4
+ data.tar.gz: ffeddf702547a2d981517dcc364af2c31cf89f70
5
5
  SHA512:
6
- metadata.gz: f5bc26f5e50925291e9b46163d2b5c8e838221982441c65eea3f366820a3e199817679e2569c7dfb8f51e961d7543c0859269181f0d924ccd05dbc27511f48a4
7
- data.tar.gz: 52e60e00116aa0668fc56c6a3dfe3971cd964e358800c5881acf1cc817cfe972158f60bf668350324f3375a299377410422c2b75674fc50f4ff8391db1b5f060
6
+ metadata.gz: 77255b4cb64f0dda7774fa891f2a52a5bffb465a4f95cb3c79b18c0449d19e49026871fde9ba41d2a8ca4434e39be362bb48628932483782ed501828237cd5df
7
+ data.tar.gz: e618c0d33e8de6e44dae7503c339f344bc516883941045fe89e0af92e9a975493876578235b30ea4a29b3f02ff367af2aa0662f7dcd6b1f48d7765dfcfc15fe7
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .idea/
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
4
- - 2.1.0
5
- - 2.2.0
3
+ - 2.1.9
4
+ - 2.2.5
5
+ - 2.3.1
data/README.md CHANGED
@@ -62,6 +62,18 @@ tracker.track("123", "event1", { key1: "value1", key2: "value2" })
62
62
 
63
63
  You can use tag name as event name like this. (see additional tag manipulations options below)
64
64
 
65
+ #### Discarding mixpanel errors
66
+
67
+ When delivering events to Mixpanel, Fluent creates a chunk of messages to send. By default, if one event fails to send to Mixpanel, all messages in that chunk are requeued for delivery. Enabling `discard_event_on_send_error` allows you to ignore single delivery failures. The event is logged via `info`, including the record being dropped.
68
+
69
+ ```
70
+ <match output.mixpanel.*>
71
+ ...
72
+ discard_event_on_send_error true
73
+ ...
74
+ </match>
75
+ ```
76
+
65
77
  ##PLEASE NOTE (breaking api change in a future release)
66
78
 
67
79
  The api for remove_tag_prefix will be changing in a future release. There is currently a boolean option,
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "fluent-plugin-mixpanel"
7
- spec.version = "0.0.8"
7
+ spec.version = "0.0.9"
8
8
  spec.authors = ["Kazuyuki Honda"]
9
9
  spec.email = ["hakobera@gmail.com"]
10
10
  spec.summary = %q{Fluentd plugin to input/output event track data to mixpanel}
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_runtime_dependency "fluentd", ">= 0.10.55"
21
- spec.add_runtime_dependency "mixpanel-ruby", "~> 2.1.0"
21
+ spec.add_runtime_dependency "mixpanel-ruby", "~> 2.2.0"
22
22
 
23
23
  spec.add_development_dependency "rake"
24
24
  spec.add_development_dependency "webmock"
@@ -0,0 +1,15 @@
1
+ require 'mixpanel-ruby'
2
+
3
+ class Fluent::MixpanelOutputErrorHandler < Mixpanel::ErrorHandler
4
+ def initialize(logger)
5
+ @logger = logger
6
+ end
7
+
8
+ def handle(error)
9
+ # Default behavior is to not return an error. Mixpanel-ruby gem returns
10
+ # true/false. If there is an error, an optional error handler is called.
11
+ # In this case, here, we only want to log the error for future development
12
+ # of error handling.
13
+ @logger.error "MixpanelOutputErrorHandler:\n\tClass: #{error.class.to_s}\n\tMessage: #{error.message}\n\tBacktrace: #{error.backtrace}"
14
+ end
15
+ end
@@ -1,11 +1,12 @@
1
+ require_relative "mixpanel_ruby_error_handler.rb"
1
2
 
2
3
  class Fluent::MixpanelOutput < Fluent::BufferedOutput
3
4
  Fluent::Plugin.register_output('mixpanel', self)
4
5
 
5
6
  include Fluent::HandleTagNameMixin
6
7
 
7
- config_param :project_token, :string
8
- config_param :api_key, :string, :default => ''
8
+ config_param :project_token, :string, :secret => true
9
+ config_param :api_key, :string, :default => '', :secret => true
9
10
  config_param :use_import, :bool, :default => nil
10
11
  config_param :distinct_id_key, :string
11
12
  config_param :event_key, :string, :default => nil
@@ -13,6 +14,7 @@ class Fluent::MixpanelOutput < Fluent::BufferedOutput
13
14
  config_param :event_map_tag, :bool, :default => false
14
15
  #NOTE: This will be removed in a future release. Please specify the '.' on any prefix
15
16
  config_param :use_legacy_prefix_behavior, :default => true
17
+ config_param :discard_event_on_send_error, :default => false
16
18
 
17
19
  class MixpanelError < StandardError
18
20
  end
@@ -32,6 +34,7 @@ class Fluent::MixpanelOutput < Fluent::BufferedOutput
32
34
  @api_key = conf['api_key']
33
35
  @use_import = conf['use_import']
34
36
  @use_legacy_prefix_behavior = conf['use_legacy_prefix_behavior']
37
+ @discard_event_on_send_error = conf['discard_event_on_send_error']
35
38
 
36
39
  if @event_key.nil? and !@event_map_tag
37
40
  raise Fluent::ConfigError, "'event_key' must be specifed when event_map_tag == false."
@@ -40,7 +43,8 @@ class Fluent::MixpanelOutput < Fluent::BufferedOutput
40
43
 
41
44
  def start
42
45
  super
43
- @tracker = Mixpanel::Tracker.new(@project_token)
46
+ error_handler = Fluent::MixpanelOutputErrorHandler.new(log)
47
+ @tracker = Mixpanel::Tracker.new(@project_token, error_handler)
44
48
  end
45
49
 
46
50
  def shutdown
@@ -68,19 +72,19 @@ class Fluent::MixpanelOutput < Fluent::BufferedOutput
68
72
  data['event'] = record[@event_key]
69
73
  prop.delete(@event_key)
70
74
  else
71
- log.warn('no event')
72
- return
75
+ log.warn("no event, tag: #{tag}, time: #{time.to_s}, record: #{record.to_json}")
76
+ next
73
77
  end
74
78
 
75
79
  # Ignore browswer only special event
76
- return if data['event'].start_with?('mp_')
80
+ next if data['event'].start_with?('mp_')
77
81
 
78
82
  if record[@distinct_id_key]
79
83
  data['distinct_id'] = record[@distinct_id_key]
80
84
  prop.delete(@distinct_id_key)
81
85
  else
82
- log.warn('no distinct_id')
83
- return
86
+ log.warn("no distinct_id, tag: #{tag}, time: #{time.to_s}, record: #{record.to_json}")
87
+ next
84
88
  end
85
89
 
86
90
  if !@ip_key.nil? and record[@ip_key]
@@ -98,13 +102,26 @@ class Fluent::MixpanelOutput < Fluent::BufferedOutput
98
102
  end
99
103
 
100
104
  def send_to_mixpanel(records)
105
+ log.debug("sending #{records.length} to mixpanel")
106
+
101
107
  records.each do |record|
102
- success = if @use_import
103
- @tracker.import(@api_key, record['distinct_id'], record['event'], record['properties'])
104
- else
105
- @tracker.track(record['distinct_id'], record['event'], record['properties'])
106
- end
107
- raise MixpanelError.new("Failed to track event to mixpanel") unless success
108
+ success = true
109
+
110
+ if @use_import
111
+ success = @tracker.import(@api_key, record['distinct_id'], record['event'], record['properties'])
112
+ else
113
+ success = @tracker.track(record['distinct_id'], record['event'], record['properties'])
114
+ end
115
+
116
+ unless success
117
+ if @discard_event_on_send_error
118
+ msg = "Failed to track event to mixpanel:\n"
119
+ msg += "\tRecord: #{record.to_json}"
120
+ log.info(msg)
121
+ else
122
+ raise MixpanelError.new("Failed to track event to mixpanel")
123
+ end
124
+ end
108
125
  end
109
126
  end
110
127
  end
data/test/helper.rb CHANGED
@@ -31,6 +31,7 @@ def unused_port
31
31
  port
32
32
  end
33
33
 
34
+ require 'fluent/plugin/mixpanel_ruby_error_handler'
34
35
  require 'fluent/plugin/out_mixpanel'
35
36
  require 'fluent/plugin/in_http_mixpanel'
36
37
 
@@ -1,9 +1,23 @@
1
1
  require 'helper'
2
2
  require 'net/http'
3
3
  require 'base64'
4
+ require 'fluent/test'
5
+ require 'net/http'
4
6
 
5
7
  class HttpMixpanelInputTest < Test::Unit::TestCase
6
-
8
+
9
+ class << self
10
+ def startup
11
+ socket_manager_path = ServerEngine::SocketManager::Server.generate_path
12
+ @server = ServerEngine::SocketManager::Server.open(socket_manager_path)
13
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
14
+ end
15
+
16
+ def shutdown
17
+ @server.close
18
+ end
19
+ end
20
+
7
21
  def setup
8
22
  Fluent::Test.setup
9
23
  end
@@ -11,13 +25,14 @@ class HttpMixpanelInputTest < Test::Unit::TestCase
11
25
  PORT = unused_port
12
26
  CONFIG = %[
13
27
  port #{PORT}
14
- bind 127.0.0.1
28
+ bind "127.0.0.1"
15
29
  body_size_limit 10m
16
30
  keepalive_timeout 5
31
+ respond_with_empty_img true
17
32
  ]
18
33
 
19
34
  def create_driver(conf=CONFIG)
20
- Fluent::Test::InputTestDriver.new(Fluent::HttpMixpanelInput).configure(conf)
35
+ Fluent::Test::InputTestDriver.new(Fluent::HttpMixpanelInput).configure(conf, true)
21
36
  end
22
37
 
23
38
  def test_configure
@@ -26,7 +41,7 @@ class HttpMixpanelInputTest < Test::Unit::TestCase
26
41
  assert_equal '127.0.0.1', d.instance.bind
27
42
  assert_equal 10*1024*1024, d.instance.body_size_limit
28
43
  assert_equal 5, d.instance.keepalive_timeout
29
- assert_equal false, d.instance.add_http_headers
44
+ assert_equal false, d.instance.add_http_headers
30
45
  end
31
46
 
32
47
  def test_time
@@ -39,16 +54,16 @@ class HttpMixpanelInputTest < Test::Unit::TestCase
39
54
  d.expect_emit "mixpanel.tag2", time, {"a"=>2}
40
55
 
41
56
  d.run do
42
- d.expected_emits.each {|tag,time,record|
57
+ d.expected_emits.each {|tag, record_time, record|
43
58
  res = track("#{tag}", {"json"=>record})
44
59
  assert_equal "200", res.code
45
60
  assert_equal '1', res.body
46
- assert_equal 'true', res.header['access-control-allow-credentials']
47
- assert_equal 'X-Requested-With', res.header['access-control-allow-headers']
48
- assert_equal 'GET, POST, OPTIONS', res.header['access-control-allow-methods']
49
- assert_equal 'http://foo.example', res.header['access-control-allow-origin']
50
- assert_equal '1728000', res.header['access-control-max-age']
51
- assert_equal 'no-cache, no-store', res.header['cache-control']
61
+ assert_equal 'true', res['access-control-allow-credentials']
62
+ assert_equal 'X-Requested-With', res['access-control-allow-headers']
63
+ assert_equal 'GET, POST, OPTIONS', res['access-control-allow-methods']
64
+ assert_equal 'http://foo.example', res['access-control-allow-origin']
65
+ assert_equal '1728000', res['access-control-max-age']
66
+ assert_equal 'no-cache, no-store', res['cache-control']
52
67
  }
53
68
  end
54
69
  end
@@ -62,8 +77,8 @@ class HttpMixpanelInputTest < Test::Unit::TestCase
62
77
  d.expect_emit "mixpanel.tag2", time, {"a"=>2}
63
78
 
64
79
  d.run do
65
- d.expected_emits.each {|tag,time,record|
66
- res = track("#{tag}", {"json"=>record, "time"=>time.to_s})
80
+ d.expected_emits.each {|tag, record_time, record|
81
+ res = track("#{tag}", {"json"=>record, "time"=>record_time.to_s})
67
82
  assert_equal "200", res.code
68
83
  }
69
84
  end
@@ -81,8 +96,8 @@ class HttpMixpanelInputTest < Test::Unit::TestCase
81
96
  records = [["mixpanel.tag1", time, {"a"=>1}], ["mixpanel.tag2", time, {"a"=>2}]]
82
97
 
83
98
  d.run do
84
- records.each {|tag,time,record|
85
- res = track("#{tag}", {"json"=>record, "time"=>time.to_s})
99
+ records.each {|tag, record_time, record|
100
+ res = track("#{tag}", {"json"=>record, "time"=>record_time.to_s})
86
101
  assert_equal "200", res.code
87
102
  }
88
103
  end
@@ -99,7 +114,7 @@ class HttpMixpanelInputTest < Test::Unit::TestCase
99
114
  event: event,
100
115
  properties: params['json']
101
116
  }
102
- data = URI.escape(Base64.encode64(data.to_json))
117
+ data = CGI.escape(Base64.encode64(data.to_json))
103
118
  query = "data=#{data}"
104
119
  path = "/track/?#{query}"
105
120
 
@@ -0,0 +1,16 @@
1
+ require 'helper'
2
+
3
+ class MixpanelRubyErrorHandlerTest < Test::Unit::TestCase
4
+
5
+ def test_handle
6
+ mixpanel_error = Fluent::MixpanelOutput::MixpanelError.new("Foobar failed")
7
+ @io = StringIO.new
8
+ logger = Logger.new(@io)
9
+ error = Fluent::MixpanelOutputErrorHandler.new(logger)
10
+ error.handle(mixpanel_error)
11
+
12
+ output = @io.string
13
+ expected_output = "MixpanelOutputErrorHandler:\n\tClass: Fluent::MixpanelOutput::MixpanelError\n\tMessage: Foobar failed\n\tBacktrace: \n"
14
+ assert_match expected_output, output
15
+ end
16
+ end
@@ -1,5 +1,6 @@
1
1
  require 'helper'
2
2
  require 'uri'
3
+ require 'msgpack'
3
4
 
4
5
  class MixpanelOutputTest < Test::Unit::TestCase
5
6
 
@@ -70,14 +71,14 @@ class MixpanelOutputTest < Test::Unit::TestCase
70
71
  def test_write
71
72
  stub_mixpanel
72
73
  d = create_driver(CONFIG + "event_key event")
73
- time = Time.new('2014-01-01T01:23:45+00:00')
74
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
74
75
  d.emit(sample_record, time)
75
76
  d.run
76
77
 
77
78
  assert_equal "test_token", @out[0]['properties']['token']
78
79
  assert_equal "123", @out[0]['properties']['distinct_id']
79
80
  assert_equal "event1", @out[0]['event']
80
- assert_equal time.to_i, @out[0]['properties']['time']
81
+ assert_equal time, @out[0]['properties']['time']
81
82
  assert_equal "value1", @out[0]['properties']['key1']
82
83
  assert_equal "value2", @out[0]['properties']['key2']
83
84
  end
@@ -85,7 +86,7 @@ class MixpanelOutputTest < Test::Unit::TestCase
85
86
  def test_write_setting_time_via_export
86
87
  stub_mixpanel_import
87
88
  d = create_driver(CONFIG + "use_import true\nevent_key event")
88
- time = Time.new('2014-01-01T01:23:45+00:00')
89
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
89
90
  d.emit(sample_record.merge!('time' => 1435707767), time)
90
91
  d.run
91
92
 
@@ -100,8 +101,8 @@ class MixpanelOutputTest < Test::Unit::TestCase
100
101
  def test_write_multi_request
101
102
  stub_mixpanel_import
102
103
  d = create_driver(IMPORT_CONFIG + "event_key event")
103
- time1 = Time.new('2014-01-01T01:23:45+00:00')
104
- time2 = Time.new('2014-01-02T01:23:45+00:00')
104
+ time1 = Time.new('2014-01-01T01:23:45+00:00').to_i
105
+ time2 = Time.new('2014-01-02T01:23:45+00:00').to_i
105
106
 
106
107
  d.emit(sample_record, time1)
107
108
  d.emit(sample_record.merge(key3: "value3"), time2)
@@ -109,13 +110,13 @@ class MixpanelOutputTest < Test::Unit::TestCase
109
110
 
110
111
  assert_equal "123", @out[0]['properties']['distinct_id']
111
112
  assert_equal "event1", @out[0]['event']
112
- assert_equal time1.to_i, @out[0]['properties']['time']
113
+ assert_equal time1, @out[0]['properties']['time']
113
114
  assert_equal "value1", @out[0]['properties']['key1']
114
115
  assert_equal "value2", @out[0]['properties']['key2']
115
116
 
116
117
  assert_equal "123", @out[1]['properties']['distinct_id']
117
118
  assert_equal "event1", @out[1]['event']
118
- assert_equal time2.to_i, @out[1]['properties']['time']
119
+ assert_equal time2, @out[1]['properties']['time']
119
120
  assert_equal "value1", @out[1]['properties']['key1']
120
121
  assert_equal "value2", @out[1]['properties']['key2']
121
122
  assert_equal "value2", @out[1]['properties']['key2']
@@ -124,13 +125,13 @@ class MixpanelOutputTest < Test::Unit::TestCase
124
125
  def test_write_with_ip_key
125
126
  stub_mixpanel
126
127
  d = create_driver(CONFIG + "event_key event\n ip_key ip_address")
127
- time = Time.new('2014-01-01T01:23:45+00:00')
128
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
128
129
  d.emit(sample_record.merge('ip_address' => '192.168.0.2'), time)
129
130
  d.run
130
131
 
131
132
  assert_equal "123", @out[0]['properties']['distinct_id']
132
133
  assert_equal "event1", @out[0]['event']
133
- assert_equal time.to_i, @out[0]['properties']['time']
134
+ assert_equal time, @out[0]['properties']['time']
134
135
  assert_equal "192.168.0.2", @out[0]['properties']['ip']
135
136
  assert_equal "value1", @out[0]['properties']['key1']
136
137
  assert_equal "value2", @out[0]['properties']['key2']
@@ -139,13 +140,13 @@ class MixpanelOutputTest < Test::Unit::TestCase
139
140
  def test_write_with_no_tag_manipulation
140
141
  stub_mixpanel
141
142
  d = create_driver(CONFIG + "event_map_tag true")
142
- time = Time.new('2014-01-01T01:23:45+00:00')
143
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
143
144
  d.emit(sample_record, time)
144
145
  d.run
145
146
 
146
147
  assert_equal "123", @out[0]['properties']['distinct_id']
147
148
  assert_equal "mixpanel.test", @out[0]['event']
148
- assert_equal time.to_i, @out[0]['properties']['time']
149
+ assert_equal time, @out[0]['properties']['time']
149
150
  assert_equal "value1", @out[0]['properties']['key1']
150
151
  assert_equal "value2", @out[0]['properties']['key2']
151
152
  end
@@ -153,13 +154,13 @@ class MixpanelOutputTest < Test::Unit::TestCase
153
154
  def test_write_with_event_map_tag_removing_prefix
154
155
  stub_mixpanel
155
156
  d = create_driver(CONFIG + "remove_tag_prefix mixpanel.\n event_map_tag true")
156
- time = Time.new('2014-01-01T01:23:45+00:00')
157
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
157
158
  d.emit(sample_record, time)
158
159
  d.run
159
160
 
160
161
  assert_equal "123", @out[0]['properties']['distinct_id']
161
162
  assert_equal "test", @out[0]['event']
162
- assert_equal time.to_i, @out[0]['properties']['time']
163
+ assert_equal time, @out[0]['properties']['time']
163
164
  assert_equal "value1", @out[0]['properties']['key1']
164
165
  assert_equal "value2", @out[0]['properties']['key2']
165
166
  end
@@ -167,13 +168,13 @@ class MixpanelOutputTest < Test::Unit::TestCase
167
168
  def test_write_with_event_map_tag_removing_prefix_LEGACY
168
169
  stub_mixpanel
169
170
  d = create_driver(CONFIG + "remove_tag_prefix mixpanel\n event_map_tag true\n use_legacy_prefix_behavior true")
170
- time = Time.new('2014-01-01T01:23:45+00:00')
171
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
171
172
  d.emit(sample_record, time)
172
173
  d.run
173
174
 
174
175
  assert_equal "123", @out[0]['properties']['distinct_id']
175
176
  assert_equal "test", @out[0]['event']
176
- assert_equal time.to_i, @out[0]['properties']['time']
177
+ assert_equal time, @out[0]['properties']['time']
177
178
  assert_equal "value1", @out[0]['properties']['key1']
178
179
  assert_equal "value2", @out[0]['properties']['key2']
179
180
  end
@@ -181,13 +182,13 @@ class MixpanelOutputTest < Test::Unit::TestCase
181
182
  def test_write_with_event_map_tag_removing_prefix_LEGACY_with_dot
182
183
  stub_mixpanel
183
184
  d = create_driver(CONFIG + "remove_tag_prefix mixpanel.\n event_map_tag true\n use_legacy_prefix_behavior true")
184
- time = Time.new('2014-01-01T01:23:45+00:00')
185
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
185
186
  d.emit(sample_record, time)
186
187
  d.run
187
188
 
188
189
  assert_equal "123", @out[0]['properties']['distinct_id']
189
190
  assert_equal "test", @out[0]['event']
190
- assert_equal time.to_i, @out[0]['properties']['time']
191
+ assert_equal time, @out[0]['properties']['time']
191
192
  assert_equal "value1", @out[0]['properties']['key1']
192
193
  assert_equal "value2", @out[0]['properties']['key2']
193
194
  end
@@ -195,13 +196,13 @@ class MixpanelOutputTest < Test::Unit::TestCase
195
196
  def test_write_with_event_map_tag_removing_suffix
196
197
  stub_mixpanel
197
198
  d = create_driver(CONFIG + "remove_tag_suffix .test\n event_map_tag true")
198
- time = Time.new('2014-01-01T01:23:45+00:00')
199
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
199
200
  d.emit(sample_record, time)
200
201
  d.run
201
202
 
202
203
  assert_equal "123", @out[0]['properties']['distinct_id']
203
204
  assert_equal "mixpanel", @out[0]['event']
204
- assert_equal time.to_i, @out[0]['properties']['time']
205
+ assert_equal time, @out[0]['properties']['time']
205
206
  assert_equal "value1", @out[0]['properties']['key1']
206
207
  assert_equal "value2", @out[0]['properties']['key2']
207
208
  end
@@ -209,13 +210,13 @@ class MixpanelOutputTest < Test::Unit::TestCase
209
210
  def test_write_with_event_map_tag_adding_prefix
210
211
  stub_mixpanel
211
212
  d = create_driver(CONFIG + "add_tag_prefix foo.\n event_map_tag true")
212
- time = Time.new('2014-01-01T01:23:45+00:00')
213
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
213
214
  d.emit(sample_record, time)
214
215
  d.run
215
216
 
216
217
  assert_equal "123", @out[0]['properties']['distinct_id']
217
218
  assert_equal "foo.mixpanel.test", @out[0]['event']
218
- assert_equal time.to_i, @out[0]['properties']['time']
219
+ assert_equal time, @out[0]['properties']['time']
219
220
  assert_equal "value1", @out[0]['properties']['key1']
220
221
  assert_equal "value2", @out[0]['properties']['key2']
221
222
  end
@@ -223,13 +224,13 @@ class MixpanelOutputTest < Test::Unit::TestCase
223
224
  def test_write_with_event_map_tag_adding_suffix
224
225
  stub_mixpanel
225
226
  d = create_driver(CONFIG + "add_tag_suffix .foo\n event_map_tag true")
226
- time = Time.new('2014-01-01T01:23:45+00:00')
227
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
227
228
  d.emit(sample_record, time)
228
229
  d.run
229
230
 
230
231
  assert_equal "123", @out[0]['properties']['distinct_id']
231
232
  assert_equal "mixpanel.test.foo", @out[0]['event']
232
- assert_equal time.to_i, @out[0]['properties']['time']
233
+ assert_equal time, @out[0]['properties']['time']
233
234
  assert_equal "value1", @out[0]['properties']['key1']
234
235
  assert_equal "value2", @out[0]['properties']['key2']
235
236
  end
@@ -237,7 +238,7 @@ class MixpanelOutputTest < Test::Unit::TestCase
237
238
  def test_write_ignore_special_event
238
239
  stub_mixpanel
239
240
  d = create_driver(CONFIG + "event_key event")
240
- time = Time.new('2014-01-01T01:23:45+00:00')
241
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
241
242
  d.emit({ user_id: '123', event: 'mp_page_view' }, time)
242
243
  d.run
243
244
 
@@ -247,14 +248,14 @@ class MixpanelOutputTest < Test::Unit::TestCase
247
248
  def test_write_ignore_special_property
248
249
  stub_mixpanel
249
250
  d = create_driver(CONFIG + "event_key event")
250
- time = Time.new('2014-01-01T01:23:45+00:00')
251
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
251
252
  d.emit(sample_record.merge('mp_event' => '3'), time)
252
253
  d.run
253
254
 
254
255
  assert_equal "test_token", @out[0]['properties']['token']
255
256
  assert_equal "123", @out[0]['properties']['distinct_id']
256
257
  assert_equal "event1", @out[0]['event']
257
- assert_equal time.to_i, @out[0]['properties']['time']
258
+ assert_equal time, @out[0]['properties']['time']
258
259
  assert_equal "value1", @out[0]['properties']['key1']
259
260
  assert_equal "value2", @out[0]['properties']['key2']
260
261
  assert_equal false, @out[0]['properties'].key?('mp_event')
@@ -263,14 +264,14 @@ class MixpanelOutputTest < Test::Unit::TestCase
263
264
  def test_write_delete_supried_token
264
265
  stub_mixpanel
265
266
  d = create_driver(CONFIG + "event_key event")
266
- time = Time.new('2014-01-01T01:23:45+00:00')
267
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
267
268
  d.emit(sample_record.merge('token' => '123'), time)
268
269
  d.run
269
270
 
270
271
  assert_equal "test_token", @out[0]['properties']['token']
271
272
  assert_equal "123", @out[0]['properties']['distinct_id']
272
273
  assert_equal "event1", @out[0]['event']
273
- assert_equal time.to_i, @out[0]['properties']['time']
274
+ assert_equal time, @out[0]['properties']['time']
274
275
  assert_equal "value1", @out[0]['properties']['key1']
275
276
  assert_equal "value2", @out[0]['properties']['key2']
276
277
  assert_equal false, @out[0]['properties'].key?('mp_event')
@@ -284,4 +285,87 @@ class MixpanelOutputTest < Test::Unit::TestCase
284
285
  d.run
285
286
  }
286
287
  end
288
+
289
+ def test_multiple_records_1_missing_event
290
+ stub_mixpanel
291
+ d = create_driver(CONFIG + "event_key event")
292
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
293
+ d.emit(sample_record, time)
294
+
295
+ broken_record = sample_record.dup.delete(:event)
296
+ d.emit(broken_record, time)
297
+
298
+ d.run
299
+
300
+ assert_equal 1, @out.length
301
+
302
+ assert_equal "test_token", @out[0]['properties']['token']
303
+ assert_equal "123", @out[0]['properties']['distinct_id']
304
+ assert_equal "event1", @out[0]['event']
305
+ assert_equal time, @out[0]['properties']['time']
306
+ assert_equal "value1", @out[0]['properties']['key1']
307
+ assert_equal "value2", @out[0]['properties']['key2']
308
+
309
+ end
310
+
311
+ def test_multiple_records_1_missing_distinct_id
312
+ stub_mixpanel
313
+ d = create_driver(CONFIG + "event_key event")
314
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
315
+ d.emit(sample_record, time)
316
+
317
+ broken_record = sample_record.dup.delete(:user_id)
318
+ d.emit(broken_record, time)
319
+
320
+ d.run
321
+
322
+ assert_equal 1, @out.length
323
+
324
+ assert_equal "test_token", @out[0]['properties']['token']
325
+ assert_equal "123", @out[0]['properties']['distinct_id']
326
+ assert_equal "event1", @out[0]['event']
327
+ assert_equal time, @out[0]['properties']['time']
328
+ assert_equal "value1", @out[0]['properties']['key1']
329
+ assert_equal "value2", @out[0]['properties']['key2']
330
+
331
+ end
332
+
333
+ def test_multiple_records_1_having_mp
334
+ stub_mixpanel
335
+ d = create_driver(CONFIG + "event_key event")
336
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
337
+ d.emit(sample_record, time)
338
+
339
+ broken_record = sample_record.dup.merge({ event: 'mp_foo'})
340
+ d.emit(broken_record, time)
341
+
342
+ d.run
343
+
344
+ assert_equal 1, @out.length
345
+
346
+ assert_equal "test_token", @out[0]['properties']['token']
347
+ assert_equal "123", @out[0]['properties']['distinct_id']
348
+ assert_equal "event1", @out[0]['event']
349
+ assert_equal time, @out[0]['properties']['time']
350
+ assert_equal "value1", @out[0]['properties']['key1']
351
+ assert_equal "value2", @out[0]['properties']['key2']
352
+
353
+ end
354
+
355
+ def test_request_error_discard
356
+ stub_mixpanel_unavailable
357
+ d = create_driver(CONFIG + "event_key event\ndiscard_event_on_send_error true")
358
+ time = Time.new('2014-01-01T01:23:45+00:00').to_i
359
+ d.emit(sample_record, time)
360
+ d.run
361
+
362
+ logs = d.instance.log.logs
363
+
364
+ assert_match "MixpanelOutputErrorHandler:", logs[0]
365
+ assert_match "Class: Mixpanel::ServerError", logs[0]
366
+ assert_match "Message: Could not write to Mixpanel, server responded with 503 returning: 'Service Unavailable", logs[0]
367
+ assert_match "Backtrace", logs[0]
368
+ assert_match "Failed to track event to mixpanel", logs[1]
369
+ assert_match 'Record: {"properties":{"key1":"value1","key2":"value2","time":' + time.to_s + '},"event":"event1","distinct_id":"123"}', logs[1]
370
+ end
287
371
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-mixpanel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kazuyuki Honda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-22 00:00:00.000000000 Z
11
+ date: 2016-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 2.1.0
33
+ version: 2.2.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 2.1.0
40
+ version: 2.2.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -98,9 +98,11 @@ files:
98
98
  - example/index.html
99
99
  - fluent-plugin-mixpanel.gemspec
100
100
  - lib/fluent/plugin/in_http_mixpanel.rb
101
+ - lib/fluent/plugin/mixpanel_ruby_error_handler.rb
101
102
  - lib/fluent/plugin/out_mixpanel.rb
102
103
  - test/helper.rb
103
104
  - test/plugin/test_in_http_mixpanel.rb
105
+ - test/plugin/test_mixpanel_ruby_error_handler.rb
104
106
  - test/plugin/test_out_mixpanel.rb
105
107
  homepage: https://github.com/hakobera/fluent-plugin-mixpanel
106
108
  licenses:
@@ -122,11 +124,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
124
  version: '0'
123
125
  requirements: []
124
126
  rubyforge_project:
125
- rubygems_version: 2.4.5
127
+ rubygems_version: 2.5.1
126
128
  signing_key:
127
129
  specification_version: 4
128
130
  summary: Fluentd plugin to input/output event track data to mixpanel
129
131
  test_files:
130
132
  - test/helper.rb
131
133
  - test/plugin/test_in_http_mixpanel.rb
134
+ - test/plugin/test_mixpanel_ruby_error_handler.rb
132
135
  - test/plugin/test_out_mixpanel.rb