logstash-filter-mixpanel 0.1.3 → 0.1.4
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 +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
|