logstash-filter-mixpanel 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/logstash/filters/mixpanel.rb +19 -7
- data/logstash-filter-mixpanel.gemspec +1 -1
- data/spec/filters/mixpanel_spec.rb +189 -72
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZDU0ODI4YTRjYjk1YzRiNDk5YTdkZTNhMWRmM2U4MjMyNzNmMmMxNA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
Y2E2ZDE0OGNjOGQ0MGQwNDBjNDhlZGRkYjEzMDc5ODcyNmQ1MTA5ZQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NmFjMmI3MTdkMjAxOWVkY2RlNzBmOWJiMTc0MDU0OWQzZGFmODZiZWRhYjE1
|
10
|
+
ZThlMTI1NGNlMjU0NTIxMmQ3NDE4Njk4OWFjODNlZmNjNmNlZGFiMTdlNGNh
|
11
|
+
YTg0ZTIxNjU5NGNkNmExNmJhODVlZmMzYjFmYzY1YzUzZWYzMmE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ODViNGM2ZDU0NjhlYmQ0NGYwYjkyZjVkM2UxODkyMmEyYzUwNGQ2ZmI1MDQ4
|
14
|
+
MTgwOTMzYjY5NDRmNzdkOGVhZjk3NWNiYTE1ZWUxMTJkNjJlOTFkODI4N2Mw
|
15
|
+
YTY2OTE4NDQ5ZmI0ZjJkZmMwZDg2YjUxODNiN2JiZGJiZGYwZjY=
|
@@ -24,9 +24,11 @@ class LogStash::Filters::Mixpanel < LogStash::Filters::Base
|
|
24
24
|
config :api_key, :validate => :string, :required => true
|
25
25
|
config :api_secret, :validate => :string, :required => true
|
26
26
|
config :where, :validate => :array, :required => true
|
27
|
+
config :use_or, :validate => :boolean, :default => false
|
27
28
|
config :source, :validate => :string, :default => 'message'
|
28
29
|
config :target, :validate => :string, :default => 'mixpanel'
|
29
30
|
config :tag_on_failure, :validate => :array, :default => ['_mixpanelfilterfailure']
|
31
|
+
config :tag_on_multiresults, :validate => :array, :default => ['_mixpanelfiltermultiresults']
|
30
32
|
|
31
33
|
|
32
34
|
public
|
@@ -40,7 +42,7 @@ class LogStash::Filters::Mixpanel < LogStash::Filters::Base
|
|
40
42
|
public
|
41
43
|
def filter(event)
|
42
44
|
|
43
|
-
result = fetch_data
|
45
|
+
result = fetch_data event
|
44
46
|
if !result.nil?
|
45
47
|
event[@target] = result
|
46
48
|
|
@@ -55,12 +57,18 @@ class LogStash::Filters::Mixpanel < LogStash::Filters::Base
|
|
55
57
|
end # def filter
|
56
58
|
|
57
59
|
private
|
58
|
-
def fetch_data
|
60
|
+
def fetch_data(event)
|
59
61
|
options = {}
|
60
62
|
options['where'] = prepare_where @where if @where
|
61
63
|
|
62
64
|
response = @mp.request('engage', options)
|
63
|
-
if response['results'].size
|
65
|
+
if response['results'].size == 1
|
66
|
+
single_res = response['results'][0]
|
67
|
+
elsif response['results'].size > 1
|
68
|
+
@tag_on_multiresults.each do |tag|
|
69
|
+
event['tags'] ||= []
|
70
|
+
event['tags'] << tag unless event['tags'].include?(tag)
|
71
|
+
end
|
64
72
|
single_res = response['results'][0]
|
65
73
|
else
|
66
74
|
return nil
|
@@ -72,18 +80,22 @@ class LogStash::Filters::Mixpanel < LogStash::Filters::Base
|
|
72
80
|
end
|
73
81
|
|
74
82
|
private
|
75
|
-
def prepare_where
|
83
|
+
def prepare_where(wheredata)
|
76
84
|
special_properties = %w(email first_name last_name last_seen created)
|
77
85
|
res_array = []
|
78
86
|
wheredata.each { |constraint|
|
79
87
|
constraint.each { |key, value|
|
80
88
|
# prepend key with dollar sigh if key is in special_properties
|
81
|
-
# TODO: add test for special properties without dollar sign
|
82
89
|
key = "$#{key}" if special_properties.include? key
|
83
90
|
|
84
91
|
res_array.push "properties[\"#{key}\"] == \"#{value}\""
|
85
92
|
}
|
86
93
|
}
|
87
|
-
|
94
|
+
if @use_or
|
95
|
+
result = res_array.join ' or '
|
96
|
+
else
|
97
|
+
result = res_array.join ' and '
|
98
|
+
end
|
99
|
+
result
|
88
100
|
end
|
89
|
-
end # class LogStash::Filters::
|
101
|
+
end # class LogStash::Filters::Mixpanel
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-filter-mixpanel'
|
3
|
-
s.version = '0.1.
|
3
|
+
s.version = '0.1.4'
|
4
4
|
s.version = "#{s.version}.pre.#{ENV['TRAVIS_BUILD_NUMBER']}" if ENV['TRAVIS'] and ENV['TRAVIS_BRANCH'] != 'master'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "This filter checks mixpanel for additional people data and adds it to the event data"
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require File.absolute_path(File.join(File.dirname(__FILE__), '../../spec/spec_helper'))
|
2
2
|
require File.absolute_path(File.join(File.dirname(__FILE__), '../../lib/logstash/filters/mixpanel'))
|
3
|
+
require 'rspec'
|
3
4
|
require 'mixpanel_client'
|
4
5
|
require 'mixpanel-ruby'
|
5
6
|
require 'ffaker'
|
@@ -7,39 +8,6 @@ require 'base64'
|
|
7
8
|
|
8
9
|
|
9
10
|
describe LogStash::Filters::Mixpanel do
|
10
|
-
before(:all) do
|
11
|
-
@mp = Mixpanel::Tracker.new(ENV['MP_PROJECT_TOKEN'])
|
12
|
-
|
13
|
-
@user_1_id = FFaker::Guid.guid
|
14
|
-
@user_1_ip = FFaker::Internet.ip_v4_address
|
15
|
-
@user_1_email = FFaker::Internet.safe_email
|
16
|
-
@user_1_first_name = FFaker::NameDE.first_name
|
17
|
-
@user_1_last_name = FFaker::NameDE.last_name
|
18
|
-
@user_1_data = {
|
19
|
-
:$first_name => @user_1_first_name,
|
20
|
-
:$last_name => @user_1_last_name,
|
21
|
-
:$email => @user_1_email,
|
22
|
-
'Device ID' => @user_1_id
|
23
|
-
}
|
24
|
-
@mp.people.set(@user_1_id, @user_1_data, ip=@user_1_ip)
|
25
|
-
@mp.track(@user_1_id, 'user 1 created')
|
26
|
-
|
27
|
-
@user_2_id = FFaker::Guid.guid
|
28
|
-
@user_2_ip = FFaker::Internet.ip_v4_address
|
29
|
-
@user_2_email = FFaker::Internet.safe_email
|
30
|
-
@user_2_first_name = @user_1_first_name
|
31
|
-
@user_2_last_name = @user_1_last_name
|
32
|
-
@user_2_data = {
|
33
|
-
:$first_name => @user_2_first_name,
|
34
|
-
:$last_name => @user_2_last_name,
|
35
|
-
:$email => @user_2_email,
|
36
|
-
'Device ID' => @user_2_id
|
37
|
-
}
|
38
|
-
@mp.people.set(@user_2_id, @user_2_data, ip=@user_2_ip)
|
39
|
-
@mp.track(@user_2_id, 'user 2 created')
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
11
|
|
44
12
|
context 'raise error' do
|
45
13
|
context 'on wrong api key config' do
|
@@ -106,95 +74,244 @@ describe LogStash::Filters::Mixpanel do
|
|
106
74
|
|
107
75
|
context 'fetch created user' do
|
108
76
|
context 'by device id' do
|
77
|
+
before {
|
78
|
+
@id = FFaker::Guid.guid
|
79
|
+
@expected_result = {
|
80
|
+
'page' => 0,
|
81
|
+
'page_size' => 1000,
|
82
|
+
'results' => [{ '$distinc_id' => 123124,
|
83
|
+
'$properties' => { '$created' => '2008-12-12T11:20:47',
|
84
|
+
'$email' => 'example@mixpanel.com',
|
85
|
+
'$first_name' => 'Example',
|
86
|
+
'$last_name' => 'Name',
|
87
|
+
'Device ID' => @id,
|
88
|
+
'$last_seen' => '2008-06-09T23:08:40' }
|
89
|
+
}]
|
90
|
+
}
|
91
|
+
Mixpanel::Client.any_instance.stub(:request).and_return(@expected_result)
|
92
|
+
}
|
93
|
+
|
109
94
|
let(:config) do <<-CONFIG
|
110
95
|
filter {
|
111
96
|
mixpanel {
|
112
97
|
api_key => '#{ENV['MP_PROJECT_KEY']}'
|
113
98
|
api_secret => '#{ENV['MP_PROJECT_SECRET']}'
|
114
|
-
where => [{'Device ID' => '#{@
|
99
|
+
where => [{'Device ID' => '#{@id}'}]
|
115
100
|
}
|
116
101
|
}
|
117
102
|
CONFIG
|
118
103
|
end
|
119
104
|
|
120
|
-
sample(
|
105
|
+
sample('message' => '123') do
|
121
106
|
expect(subject).to include('mixpanel')
|
122
107
|
expect(subject['mixpanel']).to include('Device ID')
|
123
108
|
expect(subject['mixpanel']).to include('$distinct_id')
|
124
109
|
expect(subject['mixpanel']).to include('$email')
|
125
110
|
expect(subject['mixpanel']).to include('$last_name')
|
126
111
|
expect(subject['mixpanel']).to include('Device ID')
|
112
|
+
expect(subject['mixpanel']['Device ID']).to eq(@id)
|
113
|
+
expect(subject['mixpanel']).to eq(@expected_result['results'][0]['$properties'])
|
127
114
|
insist { subject['tags'] }.nil?
|
128
115
|
end
|
129
116
|
end
|
130
117
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
118
|
+
# TODO: Create Unit test for "by email if it has no dollar char"
|
119
|
+
# context 'by email if it has no dollar char' do
|
120
|
+
# before {
|
121
|
+
# @id = FFaker::Guid.guid
|
122
|
+
# @expected_result = {
|
123
|
+
# 'page' => 0,
|
124
|
+
# 'page_size' => 1000,
|
125
|
+
# 'results' => [{ '$distinc_id' => 123124,
|
126
|
+
# '$properties' => { '$created' => '2008-12-12T11:20:47',
|
127
|
+
# '$email' => 'example@mixpanel.com',
|
128
|
+
# '$first_name' => 'Example',
|
129
|
+
# '$last_name' => 'Name',
|
130
|
+
# 'Device ID' => @id,
|
131
|
+
# '$last_seen' => '2008-06-09T23:08:40' }
|
132
|
+
# }]
|
133
|
+
# }
|
134
|
+
# Mixpanel::Client.any_instance.stub(:request).and_return(@expected_result)
|
135
|
+
# }
|
136
|
+
#
|
137
|
+
# let(:config) do <<-CONFIG
|
138
|
+
# filter {
|
139
|
+
# mixpanel {
|
140
|
+
# api_key => '#{ENV['MP_PROJECT_KEY']}'
|
141
|
+
# api_secret => '#{ENV['MP_PROJECT_SECRET']}'
|
142
|
+
# where => [{'email' => '#{@id}'}]
|
143
|
+
# }
|
144
|
+
# }
|
145
|
+
# CONFIG
|
146
|
+
# end
|
147
|
+
#
|
148
|
+
# sample('message' => '123') do
|
149
|
+
# expect(subject).to include("mixpanel")
|
150
|
+
# expect(subject['mixpanel']).to include('Device ID')
|
151
|
+
# expect(subject['mixpanel']).to include('$distinct_id')
|
152
|
+
# expect(subject['mixpanel']).to include('$email')
|
153
|
+
# expect(subject['mixpanel']).to include('$last_name')
|
154
|
+
# expect(subject['mixpanel']).to include('Device ID')
|
155
|
+
# insist { subject['tags'] }.nil?
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# TODO: Create Unit test for "by email if it has dollar char"
|
160
|
+
# context 'by email if it has dollar char' do
|
161
|
+
# let(:config) do <<-CONFIG
|
162
|
+
# filter {
|
163
|
+
# mixpanel {
|
164
|
+
# api_key => '#{ENV['MP_PROJECT_KEY']}'
|
165
|
+
# api_secret => '#{ENV['MP_PROJECT_SECRET']}'
|
166
|
+
# where => [{'$email' => '#{@user_1_email}'}]
|
167
|
+
# }
|
168
|
+
# }
|
169
|
+
# CONFIG
|
170
|
+
# end
|
171
|
+
#
|
172
|
+
# sample('message' => '123') do
|
173
|
+
# expect(subject).to include("mixpanel")
|
174
|
+
# expect(subject['mixpanel']).to include('Device ID')
|
175
|
+
# expect(subject['mixpanel']).to include('$distinct_id')
|
176
|
+
# expect(subject['mixpanel']).to include('$email')
|
177
|
+
# expect(subject['mixpanel']).to include('$last_name')
|
178
|
+
# expect(subject['mixpanel']).to include('Device ID')
|
179
|
+
# insist { subject['tags'] }.nil?
|
180
|
+
# end
|
181
|
+
# end
|
182
|
+
end
|
183
|
+
|
184
|
+
context 'test on multiple returns' do
|
185
|
+
context 'with and constraint' do
|
186
|
+
before {
|
187
|
+
@first_name = FFaker::NameDE.first_name
|
188
|
+
@expected_result = {
|
189
|
+
'page' => 0,
|
190
|
+
'page_size' => 1000,
|
191
|
+
'results' => [{ '$distinc_id' => 123124,
|
192
|
+
'$properties' => { '$created' => '2008-12-12T11:20:47',
|
193
|
+
'$email' => 'example1@mixpanel.com',
|
194
|
+
'$first_name' => @first_name,
|
195
|
+
'$last_name' => 'Name1',
|
196
|
+
'Device ID' => '123',
|
197
|
+
'$last_seen' => '2008-06-09T23:08:40' }
|
198
|
+
}, { '$distinc_id' => 1231244,
|
199
|
+
'$properties' => { '$created' => '2008-12-12T11:20:47',
|
200
|
+
'$email' => 'example2@mixpanel.com',
|
201
|
+
'$first_name' => @first_name,
|
202
|
+
'$last_name' => 'Name2',
|
203
|
+
'Device ID' => '1234',
|
204
|
+
'$last_seen' => '2008-06-09T23:08:40' }
|
205
|
+
}]
|
138
206
|
}
|
207
|
+
Mixpanel::Client.any_instance.stub(:request).and_return(@expected_result)
|
139
208
|
}
|
140
|
-
|
209
|
+
|
210
|
+
let(:config) do <<-CONFIG
|
211
|
+
filter {
|
212
|
+
mixpanel {
|
213
|
+
api_key => '#{ENV['MP_PROJECT_KEY']}'
|
214
|
+
api_secret => '#{ENV['MP_PROJECT_SECRET']}'
|
215
|
+
where => [{'first_name' => '#{@first_name}'}]
|
216
|
+
}
|
217
|
+
}
|
218
|
+
CONFIG
|
141
219
|
end
|
142
220
|
|
143
|
-
sample(
|
144
|
-
expect(subject).to include(
|
221
|
+
sample('message' => '123') do
|
222
|
+
expect(subject).to include("mixpanel")
|
145
223
|
expect(subject['mixpanel']).to include('Device ID')
|
146
224
|
expect(subject['mixpanel']).to include('$distinct_id')
|
147
225
|
expect(subject['mixpanel']).to include('$email')
|
226
|
+
expect(subject['mixpanel']).to include('$first_name')
|
148
227
|
expect(subject['mixpanel']).to include('$last_name')
|
149
228
|
expect(subject['mixpanel']).to include('Device ID')
|
150
|
-
|
229
|
+
expect(subject).to include('tags')
|
230
|
+
|
231
|
+
expect(subject['tags']).to include('_mixpanelfiltermultiresults')
|
232
|
+
expect(subject['mixpanel']).to eq(@expected_result['results'][0]['$properties'])
|
233
|
+
# expect(subject['mixpanel']['$first_name']).to eq(@first_name)
|
234
|
+
# expect(subject['mixpanel']['$last_name']).to eq('Name1')
|
151
235
|
end
|
152
236
|
end
|
153
|
-
end
|
154
237
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
238
|
+
context 'with or constraint' do
|
239
|
+
before {
|
240
|
+
@email1 = FFaker::Internet.safe_email
|
241
|
+
@email2 = FFaker::Internet.safe_email
|
242
|
+
@expected_result = {
|
243
|
+
'page' => 0,
|
244
|
+
'page_size' => 1000,
|
245
|
+
'results' => [{ '$distinc_id' => 123124,
|
246
|
+
'$properties' => { '$created' => '2008-12-12T11:20:47',
|
247
|
+
'$email' => 'example1@mixpanel.com',
|
248
|
+
'$first_name' => 'Firstname1',
|
249
|
+
'$last_name' => 'Name1',
|
250
|
+
'Device ID' => '123',
|
251
|
+
'$last_seen' => '2008-06-09T23:08:40' }
|
252
|
+
}, { '$distinc_id' => 1231244,
|
253
|
+
'$properties' => { '$created' => '2008-12-12T11:20:47',
|
254
|
+
'$email' => 'example1@mixpanel.com',
|
255
|
+
'$first_name' => 'Firstname2',
|
256
|
+
'$last_name' => 'Name2',
|
257
|
+
'Device ID' => '1234',
|
258
|
+
'$last_seen' => '2008-06-09T23:08:40' }
|
259
|
+
}]
|
162
260
|
}
|
261
|
+
Mixpanel::Client.any_instance.stub(:request).and_return(@expected_result)
|
163
262
|
}
|
164
|
-
CONFIG
|
165
|
-
end
|
166
263
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
264
|
+
let(:config) do <<-CONFIG
|
265
|
+
filter {
|
266
|
+
mixpanel {
|
267
|
+
api_key => '#{ENV['MP_PROJECT_KEY']}'
|
268
|
+
api_secret => '#{ENV['MP_PROJECT_SECRET']}'
|
269
|
+
where => [{'email' => '#{@email1}'}, {'email' => '#{@email2}'}]
|
270
|
+
use_or => true
|
271
|
+
}
|
272
|
+
}
|
273
|
+
CONFIG
|
274
|
+
end
|
275
|
+
|
276
|
+
sample('message' => '123') do
|
277
|
+
expect(subject).to include('mixpanel')
|
278
|
+
expect(subject['mixpanel']).to include('Device ID')
|
279
|
+
expect(subject['mixpanel']).to include('$distinct_id')
|
280
|
+
expect(subject['mixpanel']).to include('$email')
|
281
|
+
expect(subject['mixpanel']).to include('$last_name')
|
282
|
+
expect(subject['mixpanel']).to include('Device ID')
|
283
|
+
|
284
|
+
expect(subject).to include('tags')
|
285
|
+
expect(subject['tags']).to include('_mixpanelfiltermultiresults')
|
286
|
+
expect(subject['mixpanel']).to eq(@expected_result['results'][0]['$properties'])
|
287
|
+
end
|
175
288
|
end
|
176
289
|
end
|
177
290
|
|
178
291
|
context 'test on no returns' do
|
292
|
+
before {
|
293
|
+
@expected_result = {
|
294
|
+
'page' => 0,
|
295
|
+
'page_size' => 1000,
|
296
|
+
'results' => []
|
297
|
+
}
|
298
|
+
Mixpanel::Client.any_instance.stub(:request).and_return(@expected_result)
|
299
|
+
}
|
300
|
+
|
179
301
|
let(:config) do <<-CONFIG
|
180
302
|
filter {
|
181
303
|
mixpanel {
|
182
304
|
api_key => '#{ENV['MP_PROJECT_KEY']}'
|
183
305
|
api_secret => '#{ENV['MP_PROJECT_SECRET']}'
|
184
|
-
where => [{'first_name' => '
|
306
|
+
where => [{'$first_name' => 'thisfirstnameshouldneverbeseen123'}]
|
185
307
|
}
|
186
308
|
}
|
187
309
|
CONFIG
|
188
310
|
end
|
189
311
|
|
190
|
-
sample(
|
191
|
-
insist { subject[
|
312
|
+
sample('message' => '123') do
|
313
|
+
insist { subject['tags'] }.include?('_mixpanelfilterfailure')
|
192
314
|
reject { subject }.include?('mixpanel')
|
193
315
|
end
|
194
316
|
end
|
195
|
-
|
196
|
-
after(:all) do
|
197
|
-
@mp.people.delete_user(@user_1_id)
|
198
|
-
@mp.people.delete_user(@user_2_id)
|
199
|
-
end
|
200
317
|
end
|