moesif_rack 1.3.5 → 1.3.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +178 -105
- data/lib/moesif_rack/app_config.rb +121 -0
- data/lib/moesif_rack/moesif_middleware.rb +40 -37
- data/moesif_capture_outgoing/httplog/http_log.rb +1 -0
- data/test/moesif_rack_test.rb +18 -4
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5449e55b2da865cdc2bd4d52eef977b45db5a3e7648ee18f67f93795bf1fcd46
|
4
|
+
data.tar.gz: 930c9fb3a9181eec3b12d5aea8073c12646f94f77d16638dfa0422107b8000f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13012b377dac7ca5da3dcaf1d50ef97e71f6515df9e7f94e61b39746b4f29b134efcbc87eaafcb8dcd04dd67e0e052d8f0c5e9c77dd6ea20a7d997f50df3feb6
|
7
|
+
data.tar.gz: d7499b20fa602a2dd1bde29099b5b11755f36421f79c32f59fc1e1aa7f0e1dce7794b7ed1ca703c74ff07f040492b3ecc12f038eb3f52625348b13ae9becb2ec
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ gem install moesif_rack
|
|
22
22
|
and if you have a `Gemfile` in your project, please add this line to
|
23
23
|
|
24
24
|
```
|
25
|
-
gem 'moesif_rack', '~> 1.3.
|
25
|
+
gem 'moesif_rack', '~> 1.3.9'
|
26
26
|
|
27
27
|
```
|
28
28
|
|
@@ -126,12 +126,10 @@ Optional.
|
|
126
126
|
identify_user is a Proc that takes env, headers, and body as arguments and returns a user_id string. This helps us attribute requests to unique users. Even though Moesif can automatically retrieve the user_id without this, this is highly recommended to ensure accurate attribution.
|
127
127
|
|
128
128
|
```ruby
|
129
|
-
|
130
129
|
moesif_options['identify_user'] = Proc.new { |env, headers, body|
|
131
130
|
|
132
|
-
#
|
133
|
-
|
134
|
-
'my_user_id'
|
131
|
+
# Add your custom code that returns a string for user id
|
132
|
+
'12345'
|
135
133
|
}
|
136
134
|
|
137
135
|
```
|
@@ -145,13 +143,24 @@ identify_company is a Proc that takes env, headers, and body as arguments and re
|
|
145
143
|
|
146
144
|
moesif_options['identify_company'] = Proc.new { |env, headers, body|
|
147
145
|
|
148
|
-
#
|
149
|
-
|
150
|
-
'my_company_id'
|
146
|
+
# Add your custom code that returns a string for company id
|
147
|
+
'67890'
|
151
148
|
}
|
152
149
|
|
153
150
|
```
|
154
151
|
|
152
|
+
#### __`identify_session`__
|
153
|
+
|
154
|
+
Optional. A Proc that takes env, headers, body and returns a string.
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
|
158
|
+
moesif_options['identify_session'] = Proc.new { |env, headers, body|
|
159
|
+
# Add your custom code that returns a string for session/API token
|
160
|
+
'XXXXXXXXX'
|
161
|
+
}
|
162
|
+
```
|
163
|
+
|
155
164
|
#### __`get_metadata`__
|
156
165
|
|
157
166
|
Optional.
|
@@ -162,31 +171,15 @@ metadata to this event.
|
|
162
171
|
```ruby
|
163
172
|
|
164
173
|
moesif_options['get_metadata'] = Proc.new { |env, headers, body|
|
165
|
-
|
166
|
-
#snip
|
174
|
+
# Add your custom code that returns a dictionary
|
167
175
|
value = {
|
168
|
-
'
|
169
|
-
'
|
176
|
+
'datacenter' => 'westus',
|
177
|
+
'deployment_version' => 'v1.2.3'
|
170
178
|
}
|
171
|
-
|
172
179
|
value
|
173
180
|
}
|
174
181
|
```
|
175
182
|
|
176
|
-
#### __`identify_session`__
|
177
|
-
|
178
|
-
Optional. A Proc that takes env, headers, body and returns a string.
|
179
|
-
|
180
|
-
```ruby
|
181
|
-
|
182
|
-
moesif_options['identify_session'] = Proc.new { |env, headers, body|
|
183
|
-
|
184
|
-
#snip
|
185
|
-
|
186
|
-
'the_session_token'
|
187
|
-
}
|
188
|
-
|
189
|
-
```
|
190
183
|
|
191
184
|
#### __`mask_data`__
|
192
185
|
|
@@ -196,9 +189,8 @@ With mask_data, you can make modifications to headers or body of the event befor
|
|
196
189
|
```ruby
|
197
190
|
|
198
191
|
moesif_options['mask_data'] = Proc.new { |event_model|
|
199
|
-
|
200
|
-
|
201
|
-
|
192
|
+
# Add your custom code that returns a event_model after modifying any fields
|
193
|
+
event_model.response.body.password = nil
|
202
194
|
event_model
|
203
195
|
}
|
204
196
|
|
@@ -213,9 +205,7 @@ Optional. A Proc that takes env, headers, body and returns a boolean.
|
|
213
205
|
```ruby
|
214
206
|
|
215
207
|
moesif_options['skip'] = Proc.new { |env, headers, body|
|
216
|
-
|
217
|
-
#snip
|
218
|
-
|
208
|
+
# Add your custom code that returns true to skip logging the API call
|
219
209
|
false
|
220
210
|
}
|
221
211
|
|
@@ -232,7 +222,7 @@ Optional. Boolean. Default false. If true, it will print out debug messages. In
|
|
232
222
|
|
233
223
|
Optional. Boolean. Default true. If false, will not log request and response body to Moesif.
|
234
224
|
|
235
|
-
#### __`
|
225
|
+
#### __`capture_outgoing_requests`__
|
236
226
|
Optional. boolean, Default `false`. Set to `true` to capture all outgoing API calls from your app to third parties like Stripe, Github or to your own dependencies while using [Net::HTTP](https://ruby-doc.org/stdlib-2.6.3/libdoc/net/http/rdoc/Net/HTTP.html) package. The options below is applied to outgoing API calls. When the request is outgoing, for options functions that take request and response as input arguments, the request and response objects passed in are [Request](https://www.rubydoc.info/stdlib/net/Net/HTTPRequest) request and [Response](https://www.rubydoc.info/stdlib/net/Net/HTTPResponse) response objects.
|
237
227
|
|
238
228
|
|
@@ -245,9 +235,8 @@ identify_user_outgoing is a Proc that takes request and response as arguments an
|
|
245
235
|
|
246
236
|
moesif_options['identify_user_outgoing'] = Proc.new { |request, response|
|
247
237
|
|
248
|
-
#
|
249
|
-
|
250
|
-
'the_user_id'
|
238
|
+
# Add your custom code that returns a string for user id
|
239
|
+
'12345'
|
251
240
|
}
|
252
241
|
|
253
242
|
```
|
@@ -261,9 +250,8 @@ identify_company_outgoing is a Proc that takes request and response as arguments
|
|
261
250
|
|
262
251
|
moesif_options['identify_company_outgoing'] = Proc.new { |request, response|
|
263
252
|
|
264
|
-
#
|
265
|
-
|
266
|
-
'the_company_id'
|
253
|
+
# Add your custom code that returns a string for company id
|
254
|
+
'67890'
|
267
255
|
}
|
268
256
|
|
269
257
|
```
|
@@ -279,12 +267,11 @@ metadata to this event.
|
|
279
267
|
|
280
268
|
moesif_options['get_metadata_outgoing'] = Proc.new { |request, response|
|
281
269
|
|
282
|
-
#
|
270
|
+
# Add your custom code that returns a dictionary
|
283
271
|
value = {
|
284
|
-
'
|
285
|
-
'
|
272
|
+
'datacenter' => 'westus',
|
273
|
+
'deployment_version' => 'v1.2.3'
|
286
274
|
}
|
287
|
-
|
288
275
|
value
|
289
276
|
}
|
290
277
|
```
|
@@ -297,9 +284,8 @@ Optional. A Proc that takes request, response and returns a string.
|
|
297
284
|
|
298
285
|
moesif_options['identify_session_outgoing'] = Proc.new { |request, response|
|
299
286
|
|
300
|
-
|
301
|
-
|
302
|
-
'the_session_token'
|
287
|
+
# Add your custom code that returns a string for session/API token
|
288
|
+
'XXXXXXXXX'
|
303
289
|
}
|
304
290
|
|
305
291
|
```
|
@@ -312,8 +298,7 @@ Optional. A Proc that takes request, response and returns a boolean. If `true` w
|
|
312
298
|
|
313
299
|
moesif_options['skip_outgoing'] = Proc.new{ |request, response|
|
314
300
|
|
315
|
-
#
|
316
|
-
|
301
|
+
# Add your custom code that returns true to skip logging the API call
|
317
302
|
false
|
318
303
|
}
|
319
304
|
|
@@ -328,8 +313,8 @@ With mask_data_outgoing, you can make modifications to headers or body of the ev
|
|
328
313
|
|
329
314
|
moesif_options['mask_data_outgoing'] = Proc.new { |event_model|
|
330
315
|
|
331
|
-
#
|
332
|
-
|
316
|
+
# Add your custom code that returns a event_model after modifying any fields
|
317
|
+
event_model.response.body.password = nil
|
333
318
|
event_model
|
334
319
|
}
|
335
320
|
|
@@ -341,28 +326,51 @@ Optional. Boolean. Default true. If false, will not log request and response bod
|
|
341
326
|
|
342
327
|
## Update User
|
343
328
|
|
344
|
-
###
|
345
|
-
|
346
|
-
The metadata field can be any
|
329
|
+
### Update a Single User
|
330
|
+
Create or update a user profile in Moesif.
|
331
|
+
The metadata field can be any customer demographic or other info you want to store.
|
332
|
+
Only the `user_id` field is required.
|
333
|
+
This method is a convenient helper that calls the Moesif API lib.
|
334
|
+
For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby#update-a-user).
|
347
335
|
|
348
336
|
```ruby
|
349
|
-
metadata
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
337
|
+
metadata => {
|
338
|
+
:email => 'john@acmeinc.com',
|
339
|
+
:first_name => 'John',
|
340
|
+
:last_name => 'Doe',
|
341
|
+
:title => 'Software Engineer',
|
342
|
+
:salesInfo => {
|
343
|
+
:stage => 'Customer',
|
344
|
+
:lifetime_value => 24000,
|
345
|
+
:accountOwner => 'mary@contoso.com',
|
346
|
+
}
|
347
|
+
}
|
354
348
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
349
|
+
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
350
|
+
# See https://www.moesif.com/docs/api#users for campaign schema
|
351
|
+
campaign = CampaignModel.new()
|
352
|
+
campaign.utm_source = "google"
|
353
|
+
campaign.utm_medium = "cpc"
|
354
|
+
campaign.utm_campaign = "adwords"
|
355
|
+
campaign.utm_term = "api+tooling"
|
356
|
+
campaign.utm_content = "landing"
|
357
|
+
|
358
|
+
# Only user_id is required.
|
359
|
+
# metadata can be any custom object
|
360
|
+
user = UserModel.new()
|
361
|
+
user.user_id = "12345"
|
362
|
+
user.company_id = "67890" # If set, associate user with a company object
|
363
|
+
user.campaign = campaign
|
364
|
+
user.metadata = metadata
|
359
365
|
|
360
366
|
update_user = MoesifRack::MoesifMiddleware.new(@app, @options).update_user(user_model)
|
361
367
|
```
|
362
368
|
|
363
|
-
###
|
364
|
-
|
365
|
-
|
369
|
+
### Update Users in Batch
|
370
|
+
Similar to update_user, but used to update a list of users in one batch.
|
371
|
+
Only the `user_id` field is required.
|
372
|
+
This method is a convenient helper that calls the Moesif API lib.
|
373
|
+
For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby#update-users-in-batch).
|
366
374
|
|
367
375
|
```ruby
|
368
376
|
metadata = JSON.parse('{'\
|
@@ -371,45 +379,88 @@ metadata = JSON.parse('{'\
|
|
371
379
|
'"custom": "testdata"'\
|
372
380
|
'}')
|
373
381
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
382
|
+
users = []
|
383
|
+
|
384
|
+
metadata => {
|
385
|
+
:email => 'john@acmeinc.com',
|
386
|
+
:first_name => 'John',
|
387
|
+
:last_name => 'Doe',
|
388
|
+
:title => 'Software Engineer',
|
389
|
+
:salesInfo => {
|
390
|
+
:stage => 'Customer',
|
391
|
+
:lifetime_value => 24000,
|
392
|
+
:accountOwner => 'mary@contoso.com',
|
393
|
+
}
|
394
|
+
}
|
385
395
|
|
386
|
-
|
387
|
-
|
396
|
+
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
397
|
+
# See https://www.moesif.com/docs/api#users for campaign schema
|
398
|
+
campaign = CampaignModel.new()
|
399
|
+
campaign.utm_source = "google"
|
400
|
+
campaign.utm_medium = "cpc"
|
401
|
+
campaign.utm_campaign = "adwords"
|
402
|
+
campaign.utm_term = "api+tooling"
|
403
|
+
campaign.utm_content = "landing"
|
404
|
+
|
405
|
+
# Only user_id is required.
|
406
|
+
# metadata can be any custom object
|
407
|
+
user = UserModel.new()
|
408
|
+
user.user_id = "12345"
|
409
|
+
user.company_id = "67890" # If set, associate user with a company object
|
410
|
+
user.campaign = campaign
|
411
|
+
user.metadata = metadata
|
412
|
+
|
413
|
+
users << user
|
414
|
+
|
415
|
+
response = MoesifRack::MoesifMiddleware.new(@app, @options).update_users_batch(users)
|
388
416
|
```
|
389
417
|
|
390
418
|
## Update Company
|
391
419
|
|
392
|
-
###
|
393
|
-
|
394
|
-
The metadata field can be any
|
420
|
+
### Update a Single Company
|
421
|
+
Create or update a company profile in Moesif.
|
422
|
+
The metadata field can be any company demographic or other info you want to store.
|
423
|
+
Only the `company_id` field is required.
|
424
|
+
This method is a convenient helper that calls the Moesif API lib.
|
425
|
+
For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby#update-a-company).
|
395
426
|
|
396
427
|
```ruby
|
397
|
-
metadata
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
428
|
+
metadata => {
|
429
|
+
:org_name => 'Acme, Inc',
|
430
|
+
:plan_name => 'Free',
|
431
|
+
:deal_stage => 'Lead',
|
432
|
+
:mrr => 24000,
|
433
|
+
:demographics => {
|
434
|
+
:alexa_ranking => 500000,
|
435
|
+
:employee_count => 47
|
436
|
+
}
|
437
|
+
}
|
402
438
|
|
403
|
-
|
404
|
-
|
405
|
-
|
439
|
+
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
440
|
+
# See https://www.moesif.com/docs/api#update-a-company for campaign schema
|
441
|
+
campaign = CampaignModel.new()
|
442
|
+
campaign.utm_source = "google"
|
443
|
+
campaign.utm_medium = "cpc"
|
444
|
+
campaign.utm_campaign = "adwords"
|
445
|
+
campaign.utm_term = "api+tooling"
|
446
|
+
campaign.utm_content = "landing"
|
447
|
+
|
448
|
+
# Only company_id is required.
|
449
|
+
# metadata can be any custom object
|
450
|
+
company = CompanyModel.new()
|
451
|
+
company.company_id = "67890"
|
452
|
+
company.company_domain = "acmeinc.com" # If domain is set, Moesif will enrich your profiles with publicly available info
|
453
|
+
company.campaign = campaign
|
454
|
+
company.metadata = metadata
|
406
455
|
|
407
456
|
update_company = MoesifRack::MoesifMiddleware.new(@app, @options).update_company(company_model)
|
408
457
|
```
|
409
458
|
|
410
|
-
###
|
411
|
-
|
412
|
-
|
459
|
+
### Update Companies in Batch
|
460
|
+
Similar to update_company, but used to update a list of companies in one batch.
|
461
|
+
Only the `company_id` field is required.
|
462
|
+
This method is a convenient helper that calls the Moesif API lib.
|
463
|
+
For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby#update-companies-in-batch).
|
413
464
|
|
414
465
|
```ruby
|
415
466
|
metadata = JSON.parse('{'\
|
@@ -418,18 +469,38 @@ metadata = JSON.parse('{'\
|
|
418
469
|
'"custom": "testdata"'\
|
419
470
|
'}')
|
420
471
|
|
421
|
-
|
422
|
-
|
423
|
-
company_model_A = { "company_id" => "12345",
|
424
|
-
"company_domain" => "nowhere.com",
|
425
|
-
"metadata" => metadata }
|
472
|
+
companies = []
|
426
473
|
|
427
|
-
|
428
|
-
|
429
|
-
|
474
|
+
metadata => {
|
475
|
+
:org_name => 'Acme, Inc',
|
476
|
+
:plan_name => 'Free',
|
477
|
+
:deal_stage => 'Lead',
|
478
|
+
:mrr => 24000,
|
479
|
+
:demographics => {
|
480
|
+
:alexa_ranking => 500000,
|
481
|
+
:employee_count => 47
|
482
|
+
}
|
483
|
+
}
|
430
484
|
|
431
|
-
|
432
|
-
|
485
|
+
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
486
|
+
# See https://www.moesif.com/docs/api#update-a-company for campaign schema
|
487
|
+
campaign = CampaignModel.new()
|
488
|
+
campaign.utm_source = "google"
|
489
|
+
campaign.utm_medium = "cpc"
|
490
|
+
campaign.utm_campaign = "adwords"
|
491
|
+
campaign.utm_term = "api+tooling"
|
492
|
+
campaign.utm_content = "landing"
|
493
|
+
|
494
|
+
# Only company_id is required.
|
495
|
+
# metadata can be any custom object
|
496
|
+
company = CompanyModel.new()
|
497
|
+
company.company_id = "67890"
|
498
|
+
company.company_domain = "acmeinc.com" # If domain is set, Moesif will enrich your profiles with publicly available info
|
499
|
+
company.campaign = campaign
|
500
|
+
company.metadata = metadata
|
501
|
+
|
502
|
+
companies << company
|
503
|
+
response = MoesifRack::MoesifMiddleware.new(@app, @options).update_companies_batch(companies)
|
433
504
|
```
|
434
505
|
|
435
506
|
## How to test
|
@@ -443,11 +514,13 @@ response = MoesifRack::MoesifMiddleware.new(@app, @options).update_companies_bat
|
|
443
514
|
|
444
515
|
## Example Code
|
445
516
|
|
446
|
-
[Moesif Rack Example](https://github.com/Moesif/moesif-
|
517
|
+
[Moesif Rack Example with Rails](https://github.com/Moesif/moesif-rails-example) is an example of Moesif Rack applied to a Rails application.
|
518
|
+
|
519
|
+
[Moesif Rack Example](https://github.com/Moesif/moesif-rack-example) is an example of Moesif Rack applied to a Rack application.
|
447
520
|
|
448
521
|
## Other integrations
|
449
522
|
|
450
|
-
To view more
|
523
|
+
To view more documentation on integration options, please visit [the Integration Options Documentation](https://www.moesif.com/docs/getting-started/integration-options/).
|
451
524
|
|
452
525
|
[ico-built-for]: https://img.shields.io/badge/built%20for-rack-blue.svg
|
453
526
|
[ico-version]: https://img.shields.io/gem/v/moesif_rack.svg
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'moesif_api'
|
2
|
+
require 'json'
|
3
|
+
require 'time'
|
4
|
+
require 'zlib'
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
class AppConfig
|
8
|
+
|
9
|
+
def get_config(api_controller, debug)
|
10
|
+
# Get Application Config
|
11
|
+
begin
|
12
|
+
config_api_response = api_controller.get_app_config()
|
13
|
+
return config_api_response
|
14
|
+
rescue MoesifApi::APIException => e
|
15
|
+
if e.response_code.between?(401, 403)
|
16
|
+
puts 'Unauthorized access getting application configuration. Please check your Appplication Id.'
|
17
|
+
end
|
18
|
+
if debug
|
19
|
+
puts 'Error getting application configuration, with status code:'
|
20
|
+
puts e.response_code
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_configuration(config_api_response, debug)
|
26
|
+
# Parse configuration object and return Etag, sample rate and last updated time
|
27
|
+
begin
|
28
|
+
# Rails return gzipped compressed response body, so decompressing it and getting JSON response body
|
29
|
+
response_body = decompress_gzip_body(config_api_response, debug)
|
30
|
+
|
31
|
+
# Check if response body is not nil
|
32
|
+
if !response_body.nil? then
|
33
|
+
# Return Etag, sample rate and last updated time
|
34
|
+
return config_api_response.headers[:x_moesif_config_etag], response_body.fetch("sample_rate", 100), Time.now.utc
|
35
|
+
else
|
36
|
+
if debug
|
37
|
+
puts 'Response body is nil, assuming default behavior'
|
38
|
+
end
|
39
|
+
# Response body is nil, so assuming default behavior
|
40
|
+
return nil, 100, Time.now.utc
|
41
|
+
end
|
42
|
+
rescue => exception
|
43
|
+
if debug
|
44
|
+
puts 'Error while parsing the configuration object, assuming default behavior'
|
45
|
+
puts exception.to_s
|
46
|
+
end
|
47
|
+
# Assuming default behavior
|
48
|
+
return nil, 100, Time.now.utc
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_sampling_percentage(config_api_response, user_id, company_id, debug)
|
53
|
+
# Get sampling percentage
|
54
|
+
begin
|
55
|
+
# Rails return gzipped compressed response body, so decompressing it and getting JSON response body
|
56
|
+
response_body = decompress_gzip_body(config_api_response, debug)
|
57
|
+
|
58
|
+
# Check if response body is not nil
|
59
|
+
if !response_body.nil? then
|
60
|
+
|
61
|
+
# Get user sample rate object
|
62
|
+
user_sample_rate = response_body.fetch('user_sample_rate', nil)
|
63
|
+
|
64
|
+
# Get company sample rate object
|
65
|
+
company_sample_rate = response_body.fetch('company_sample_rate', nil)
|
66
|
+
|
67
|
+
# Get sample rate for the user if exist
|
68
|
+
if !user_id.nil? && !user_sample_rate.nil? && user_sample_rate.key?(user_id)
|
69
|
+
return user_sample_rate.fetch(user_id)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Get sample rate for the company if exist
|
73
|
+
if !company_id.nil? && !company_sample_rate.nil? && company_sample_rate.key?(company_id)
|
74
|
+
return company_sample_rate.fetch(company_id)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return sample rate
|
78
|
+
return response_body.fetch('sample_rate', 100)
|
79
|
+
else
|
80
|
+
if debug
|
81
|
+
puts 'Assuming default behavior as response body is nil - '
|
82
|
+
end
|
83
|
+
return 100
|
84
|
+
end
|
85
|
+
rescue => exception
|
86
|
+
if debug
|
87
|
+
puts 'Error while geting sampling percentage, assuming default behavior'
|
88
|
+
end
|
89
|
+
return 100
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def decompress_gzip_body(config_api_response, debug)
|
94
|
+
# Decompress gzip response body
|
95
|
+
begin
|
96
|
+
# Check if the content-encoding header exist and is of type zip
|
97
|
+
if config_api_response.headers.key?(:content_encoding) && config_api_response.headers[:content_encoding].eql?( 'gzip' ) then
|
98
|
+
|
99
|
+
# Create a GZipReader object to read data
|
100
|
+
gzip_reader = Zlib::GzipReader.new(StringIO.new(config_api_response.raw_body.to_s))
|
101
|
+
|
102
|
+
# Read the body
|
103
|
+
uncompressed_string = gzip_reader.read
|
104
|
+
|
105
|
+
# Return the parsed body
|
106
|
+
return JSON.parse( uncompressed_string )
|
107
|
+
else
|
108
|
+
if debug
|
109
|
+
puts 'Content Encoding is of type other than gzip, returning nil'
|
110
|
+
end
|
111
|
+
return nil
|
112
|
+
end
|
113
|
+
rescue => exception
|
114
|
+
if debug
|
115
|
+
puts 'Error while decompressing the response body'
|
116
|
+
puts exception.to_s
|
117
|
+
end
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -3,6 +3,7 @@ require 'json'
|
|
3
3
|
require 'time'
|
4
4
|
require 'base64'
|
5
5
|
require_relative './client_ip.rb'
|
6
|
+
require_relative './app_config.rb'
|
6
7
|
require_relative './update_user.rb'
|
7
8
|
require_relative './update_company.rb'
|
8
9
|
|
@@ -12,7 +13,7 @@ module MoesifRack
|
|
12
13
|
def initialize app, options = {}
|
13
14
|
@app = app
|
14
15
|
if not options['application_id']
|
15
|
-
raise 'application_id
|
16
|
+
raise 'application_id required for Moesif Middleware'
|
16
17
|
end
|
17
18
|
@api_client = MoesifApi::MoesifAPIClient.new(options['application_id'])
|
18
19
|
@api_controller = @api_client.api
|
@@ -25,15 +26,27 @@ module MoesifRack
|
|
25
26
|
@mask_data = options['mask_data']
|
26
27
|
@skip = options['skip']
|
27
28
|
@debug = options['debug']
|
29
|
+
@app_config = AppConfig.new
|
30
|
+
@config = @app_config.get_config(@api_controller, @debug)
|
31
|
+
@config_etag = nil
|
32
|
+
@sampling_percentage = 100
|
33
|
+
@last_updated_time = Time.now.utc
|
28
34
|
@config_dict = Hash.new
|
29
35
|
@disable_transaction_id = options['disable_transaction_id'] || false
|
30
36
|
@log_body = options.fetch('log_body', true)
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
begin
|
38
|
+
if !@config.nil?
|
39
|
+
@config_etag, @sampling_percentage, @last_updated_time = @app_config.parse_configuration(@config, @debug)
|
40
|
+
end
|
41
|
+
rescue => exception
|
42
|
+
if @debug
|
43
|
+
puts 'Error while parsing application configuration on initialization'
|
44
|
+
puts exception.to_s
|
45
|
+
end
|
34
46
|
end
|
35
47
|
@capture_outoing_requests = options['capture_outoing_requests']
|
36
|
-
|
48
|
+
@capture_outgoing_requests = options['capture_outgoing_requests']
|
49
|
+
if @capture_outoing_requests || @capture_outgoing_requests
|
37
50
|
if @debug
|
38
51
|
puts 'Start Capturing outgoing requests'
|
39
52
|
end
|
@@ -42,35 +55,6 @@ module MoesifRack
|
|
42
55
|
end
|
43
56
|
end
|
44
57
|
|
45
|
-
def get_config(cached_config_etag)
|
46
|
-
sample_rate = 100
|
47
|
-
begin
|
48
|
-
# Calling the api
|
49
|
-
config_api_response = @api_controller.get_app_config()
|
50
|
-
# Fetch the response ETag
|
51
|
-
response_config_etag = JSON.parse( config_api_response.to_json )["headers"]["x_moesif_config_etag"]
|
52
|
-
# Remove ETag from the global dict if exist
|
53
|
-
if !cached_config_etag.nil? && @config_dict.key?(cached_config_etag)
|
54
|
-
@config_dict.delete(cached_config_etag)
|
55
|
-
end
|
56
|
-
# Fetch the response body
|
57
|
-
@config_dict[response_config_etag] = JSON.parse(JSON.parse( config_api_response.to_json )["raw_body"])
|
58
|
-
#
|
59
|
-
app_config = @config_dict[response_config_etag]
|
60
|
-
# Fetch the sample rate
|
61
|
-
if !app_config.nil?
|
62
|
-
sample_rate = app_config.fetch("sample_rate", 100)
|
63
|
-
end
|
64
|
-
# Set the last updated time
|
65
|
-
@last_updated_time = Time.now.utc
|
66
|
-
rescue
|
67
|
-
# Set the last updated time
|
68
|
-
@last_updated_time = Time.now.utc
|
69
|
-
end
|
70
|
-
# Return the sample rate
|
71
|
-
return sample_rate
|
72
|
-
end
|
73
|
-
|
74
58
|
def update_user(user_profile)
|
75
59
|
UserHelper.new.update_user(@api_controller, @debug, user_profile)
|
76
60
|
end
|
@@ -194,6 +178,7 @@ module MoesifRack
|
|
194
178
|
event_model = MoesifApi::EventModel.new()
|
195
179
|
event_model.request = event_req
|
196
180
|
event_model.response = event_rsp
|
181
|
+
event_model.direction = "Incoming"
|
197
182
|
|
198
183
|
if @identify_user
|
199
184
|
if @debug
|
@@ -236,13 +221,31 @@ module MoesifRack
|
|
236
221
|
# Perform the API call through the SDK function
|
237
222
|
begin
|
238
223
|
@random_percentage = Random.rand(0.00..100.00)
|
224
|
+
|
225
|
+
begin
|
226
|
+
@sampling_percentage = @app_config.get_sampling_percentage(@config, event_model.user_id, event_model.company_id, @debug)
|
227
|
+
rescue => exception
|
228
|
+
if @debug
|
229
|
+
puts 'Error while getting sampling percentage, assuming default behavior'
|
230
|
+
puts exception.to_s
|
231
|
+
end
|
232
|
+
@sampling_percentage = 100
|
233
|
+
end
|
234
|
+
|
239
235
|
if @sampling_percentage > @random_percentage
|
240
236
|
event_api_response = @api_controller.create_event(event_model)
|
241
|
-
cached_config_etag = @config_dict.keys[0]
|
242
237
|
event_response_config_etag = event_api_response[:x_moesif_config_etag]
|
243
238
|
|
244
|
-
if !event_response_config_etag.nil? &&
|
245
|
-
|
239
|
+
if !event_response_config_etag.nil? && !@config_etag.nil? && @config_etag != event_response_config_etag && Time.now.utc > @last_updated_time + 300
|
240
|
+
begin
|
241
|
+
@config = @app_config.get_config(@api_controller, @debug)
|
242
|
+
@config_etag, @sampling_percentage, @last_updated_time = @app_config.parse_configuration(@config, @debug)
|
243
|
+
rescue => exception
|
244
|
+
if @debug
|
245
|
+
puts 'Error while updating the application configuration'
|
246
|
+
puts exception.to_s
|
247
|
+
end
|
248
|
+
end
|
246
249
|
end
|
247
250
|
if @debug
|
248
251
|
puts("Event successfully sent to Moesif")
|
@@ -102,6 +102,7 @@ module MoesifCaptureOutgoing
|
|
102
102
|
event_model = MoesifApi::EventModel.new()
|
103
103
|
event_model.request = event_req
|
104
104
|
event_model.response = event_rsp
|
105
|
+
event_model.direction = "Outgoing"
|
105
106
|
|
106
107
|
# Metadata for Outgoing Request
|
107
108
|
if @get_metadata_outgoing
|
data/test/moesif_rack_test.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require 'rack'
|
3
3
|
require 'net/http'
|
4
|
+
require_relative '../lib/moesif_rack/app_config.rb'
|
4
5
|
require_relative '../lib/moesif_rack'
|
5
6
|
|
6
7
|
class MoesifRackTest < Test::Unit::TestCase
|
@@ -9,7 +10,7 @@ class MoesifRackTest < Test::Unit::TestCase
|
|
9
10
|
@options = { 'application_id' => 'Your Moesif Application Id',
|
10
11
|
'debug' => true,
|
11
12
|
'disable_transaction_id' => true,
|
12
|
-
'
|
13
|
+
'capture_outgoing_requests' => true,
|
13
14
|
'get_metadata' => Proc.new {|request, response|
|
14
15
|
{
|
15
16
|
'foo' => 'abc',
|
@@ -45,6 +46,7 @@ class MoesifRackTest < Test::Unit::TestCase
|
|
45
46
|
}
|
46
47
|
}
|
47
48
|
@moesif_rack_app = MoesifRack::MoesifMiddleware.new(@app, @options)
|
49
|
+
@app_config = AppConfig.new
|
48
50
|
end
|
49
51
|
|
50
52
|
def test_capture_outgoing
|
@@ -67,10 +69,14 @@ class MoesifRackTest < Test::Unit::TestCase
|
|
67
69
|
'"custom": "testdata"'\
|
68
70
|
'}')
|
69
71
|
|
72
|
+
campaign_model = {"utm_source" => "Newsletter",
|
73
|
+
"utm_medium" => "Email"}
|
74
|
+
|
70
75
|
user_model = { "user_id" => "12345",
|
71
76
|
"company_id" => "67890",
|
72
77
|
"modified_time" => Time.now.utc.iso8601,
|
73
|
-
"metadata" => metadata
|
78
|
+
"metadata" => metadata,
|
79
|
+
"campaign" => campaign_model}
|
74
80
|
|
75
81
|
response = @moesif_rack_app.update_user(user_model)
|
76
82
|
assert_equal response, nil
|
@@ -106,7 +112,11 @@ class MoesifRackTest < Test::Unit::TestCase
|
|
106
112
|
end
|
107
113
|
|
108
114
|
def test_get_config
|
109
|
-
|
115
|
+
@api_client = MoesifApi::MoesifAPIClient.new(@options['application_id'])
|
116
|
+
@api_controller = @api_client.api
|
117
|
+
@config = @app_config.get_config(@api_controller, @debug)
|
118
|
+
@config_etag, @sampling_percentage, @last_updated_time = @app_config.parse_configuration(@config, @debug)
|
119
|
+
assert_operator 100, :>=, @sampling_percentage
|
110
120
|
end
|
111
121
|
|
112
122
|
def test_update_company
|
@@ -116,9 +126,13 @@ class MoesifRackTest < Test::Unit::TestCase
|
|
116
126
|
'"custom": "testdata"'\
|
117
127
|
'}')
|
118
128
|
|
129
|
+
campaign_model = {"utm_source" => "Adwords",
|
130
|
+
"utm_medium" => "Twitter"}
|
131
|
+
|
119
132
|
company_model = { "company_id" => "12345",
|
120
133
|
"company_domain" => "acmeinc.com",
|
121
|
-
|
134
|
+
"metadata" => metadata,
|
135
|
+
"campaign" => campaign_model }
|
122
136
|
|
123
137
|
response = @moesif_rack_app.update_company(company_model)
|
124
138
|
assert_equal response, nil
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moesif_rack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Moesif, Inc
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-12-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: test-unit
|
@@ -31,14 +31,14 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 1.2.
|
34
|
+
version: 1.2.10
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 1.2.
|
41
|
+
version: 1.2.10
|
42
42
|
description: Collection/Data Ingestion SDK for Rack (also Rails) Middleware / RoR
|
43
43
|
email: xing@moesif.com
|
44
44
|
executables: []
|
@@ -48,6 +48,7 @@ files:
|
|
48
48
|
- LICENSE
|
49
49
|
- README.md
|
50
50
|
- lib/moesif_rack.rb
|
51
|
+
- lib/moesif_rack/app_config.rb
|
51
52
|
- lib/moesif_rack/client_ip.rb
|
52
53
|
- lib/moesif_rack/moesif_middleware.rb
|
53
54
|
- lib/moesif_rack/update_company.rb
|