moesif_rack 1.3.10 → 1.4.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 +4 -4
- data/LICENSE +1 -1
- data/README.md +13 -25
- data/lib/moesif_rack/app_config.rb +40 -39
- data/lib/moesif_rack/client_ip.rb +2 -2
- data/lib/moesif_rack/helpers.rb +14 -0
- data/lib/moesif_rack/moesif_middleware.rb +132 -84
- data/moesif_capture_outgoing/httplog/http_log.rb +59 -4
- data/test/moesif_rack_test.rb +2 -0
- metadata +23 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c44fb915ecec7479c930ab41b3b74eeb58a368f387d3fa8d47211e41c4a0c80
|
4
|
+
data.tar.gz: 6974bb001d57faeffc0f58df1a4c4661ac52d4a6f5280d78c1e35c7deb5fb183
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08b7997c9a683384cc7725dff3248a41b5ddb15974be2d259d9553fb1903075814260e8df0cda6a7d1e6340b7d8d27d3c99f725f0dd088caaae28476539f162c'
|
7
|
+
data.tar.gz: c0d75f0f8ab0f8d87d4a86fa4396e4100a94d7a0f37190260bbbe3db91ec40dcaa91f4d1d945f768a1fd0483dde2a816eb388a7e9cfd5fd89c4df33881104639
|
data/LICENSE
CHANGED
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.
|
25
|
+
gem 'moesif_rack', '~> 1.4.2'
|
26
26
|
|
27
27
|
```
|
28
28
|
|
@@ -334,7 +334,7 @@ This method is a convenient helper that calls the Moesif API lib.
|
|
334
334
|
For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby#update-a-user).
|
335
335
|
|
336
336
|
```ruby
|
337
|
-
metadata
|
337
|
+
metadata = {
|
338
338
|
:email => 'john@acmeinc.com',
|
339
339
|
:first_name => 'John',
|
340
340
|
:last_name => 'Doe',
|
@@ -348,7 +348,7 @@ metadata => {
|
|
348
348
|
|
349
349
|
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
350
350
|
# See https://www.moesif.com/docs/api#users for campaign schema
|
351
|
-
campaign = CampaignModel.new()
|
351
|
+
campaign = MoesifApi::CampaignModel.new()
|
352
352
|
campaign.utm_source = "google"
|
353
353
|
campaign.utm_medium = "cpc"
|
354
354
|
campaign.utm_campaign = "adwords"
|
@@ -357,7 +357,7 @@ campaign.utm_content = "landing"
|
|
357
357
|
|
358
358
|
# Only user_id is required.
|
359
359
|
# metadata can be any custom object
|
360
|
-
user = UserModel.new()
|
360
|
+
user = MoesifApi::UserModel.new()
|
361
361
|
user.user_id = "12345"
|
362
362
|
user.company_id = "67890" # If set, associate user with a company object
|
363
363
|
user.campaign = campaign
|
@@ -373,15 +373,9 @@ This method is a convenient helper that calls the Moesif API lib.
|
|
373
373
|
For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby#update-users-in-batch).
|
374
374
|
|
375
375
|
```ruby
|
376
|
-
metadata = JSON.parse('{'\
|
377
|
-
'"email": "testrubyapi@user.com",'\
|
378
|
-
'"name": "ruby api user",'\
|
379
|
-
'"custom": "testdata"'\
|
380
|
-
'}')
|
381
|
-
|
382
376
|
users = []
|
383
377
|
|
384
|
-
metadata
|
378
|
+
metadata = {
|
385
379
|
:email => 'john@acmeinc.com',
|
386
380
|
:first_name => 'John',
|
387
381
|
:last_name => 'Doe',
|
@@ -395,7 +389,7 @@ metadata => {
|
|
395
389
|
|
396
390
|
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
397
391
|
# See https://www.moesif.com/docs/api#users for campaign schema
|
398
|
-
campaign = CampaignModel.new()
|
392
|
+
campaign = MoesifApi::CampaignModel.new()
|
399
393
|
campaign.utm_source = "google"
|
400
394
|
campaign.utm_medium = "cpc"
|
401
395
|
campaign.utm_campaign = "adwords"
|
@@ -404,7 +398,7 @@ campaign.utm_content = "landing"
|
|
404
398
|
|
405
399
|
# Only user_id is required.
|
406
400
|
# metadata can be any custom object
|
407
|
-
user = UserModel.new()
|
401
|
+
user = MoesifApi::UserModel.new()
|
408
402
|
user.user_id = "12345"
|
409
403
|
user.company_id = "67890" # If set, associate user with a company object
|
410
404
|
user.campaign = campaign
|
@@ -425,7 +419,7 @@ This method is a convenient helper that calls the Moesif API lib.
|
|
425
419
|
For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby#update-a-company).
|
426
420
|
|
427
421
|
```ruby
|
428
|
-
metadata
|
422
|
+
metadata = {
|
429
423
|
:org_name => 'Acme, Inc',
|
430
424
|
:plan_name => 'Free',
|
431
425
|
:deal_stage => 'Lead',
|
@@ -438,7 +432,7 @@ metadata => {
|
|
438
432
|
|
439
433
|
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
440
434
|
# See https://www.moesif.com/docs/api#update-a-company for campaign schema
|
441
|
-
campaign = CampaignModel.new()
|
435
|
+
campaign = MoesifApi::CampaignModel.new()
|
442
436
|
campaign.utm_source = "google"
|
443
437
|
campaign.utm_medium = "cpc"
|
444
438
|
campaign.utm_campaign = "adwords"
|
@@ -447,7 +441,7 @@ campaign.utm_content = "landing"
|
|
447
441
|
|
448
442
|
# Only company_id is required.
|
449
443
|
# metadata can be any custom object
|
450
|
-
company = CompanyModel.new()
|
444
|
+
company = MoesifApi::CompanyModel.new()
|
451
445
|
company.company_id = "67890"
|
452
446
|
company.company_domain = "acmeinc.com" # If domain is set, Moesif will enrich your profiles with publicly available info
|
453
447
|
company.campaign = campaign
|
@@ -463,15 +457,9 @@ This method is a convenient helper that calls the Moesif API lib.
|
|
463
457
|
For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby#update-companies-in-batch).
|
464
458
|
|
465
459
|
```ruby
|
466
|
-
metadata = JSON.parse('{'\
|
467
|
-
'"email": "testrubyapi@user.com",'\
|
468
|
-
'"name": "ruby api user",'\
|
469
|
-
'"custom": "testdata"'\
|
470
|
-
'}')
|
471
|
-
|
472
460
|
companies = []
|
473
461
|
|
474
|
-
metadata
|
462
|
+
metadata = {
|
475
463
|
:org_name => 'Acme, Inc',
|
476
464
|
:plan_name => 'Free',
|
477
465
|
:deal_stage => 'Lead',
|
@@ -484,7 +472,7 @@ metadata => {
|
|
484
472
|
|
485
473
|
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
486
474
|
# See https://www.moesif.com/docs/api#update-a-company for campaign schema
|
487
|
-
campaign = CampaignModel.new()
|
475
|
+
campaign = MoesifApi::CampaignModel.new()
|
488
476
|
campaign.utm_source = "google"
|
489
477
|
campaign.utm_medium = "cpc"
|
490
478
|
campaign.utm_campaign = "adwords"
|
@@ -493,7 +481,7 @@ campaign.utm_content = "landing"
|
|
493
481
|
|
494
482
|
# Only company_id is required.
|
495
483
|
# metadata can be any custom object
|
496
|
-
company = CompanyModel.new()
|
484
|
+
company = MoesifApi::CompanyModel.new()
|
497
485
|
company.company_id = "67890"
|
498
486
|
company.company_domain = "acmeinc.com" # If domain is set, Moesif will enrich your profiles with publicly available info
|
499
487
|
company.campaign = campaign
|
@@ -3,66 +3,71 @@ require 'json'
|
|
3
3
|
require 'time'
|
4
4
|
require 'zlib'
|
5
5
|
require 'stringio'
|
6
|
+
require_relative './helpers.rb'
|
6
7
|
|
7
8
|
class AppConfig
|
8
9
|
|
9
|
-
def
|
10
|
+
def initialize debug
|
11
|
+
@debug = debug
|
12
|
+
@helpers = Helpers.new(debug)
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_config(api_controller)
|
10
16
|
# Get Application Config
|
11
17
|
begin
|
12
18
|
config_api_response = api_controller.get_app_config()
|
19
|
+
@helpers.log_debug("new config downloaded")
|
20
|
+
@helpers.log_debug(config_api_response.to_s)
|
13
21
|
return config_api_response
|
14
22
|
rescue MoesifApi::APIException => e
|
15
23
|
if e.response_code.between?(401, 403)
|
16
|
-
|
17
|
-
end
|
18
|
-
if debug
|
19
|
-
puts 'Error getting application configuration, with status code:'
|
20
|
-
puts e.response_code
|
24
|
+
@helpers.log_debug 'Unauthorized access getting application configuration. Please check your Appplication Id.'
|
21
25
|
end
|
26
|
+
@helpers.log_debug 'Error getting application configuration, with status code:'
|
27
|
+
@helpers.log_debug e.response_code
|
28
|
+
rescue => e
|
29
|
+
@helpers.log_debug e.to_s
|
22
30
|
end
|
31
|
+
rescue
|
23
32
|
end
|
24
33
|
|
25
|
-
def parse_configuration(config_api_response
|
34
|
+
def parse_configuration(config_api_response)
|
26
35
|
# Parse configuration object and return Etag, sample rate and last updated time
|
27
36
|
begin
|
28
37
|
# Rails return gzipped compressed response body, so decompressing it and getting JSON response body
|
29
|
-
response_body = decompress_gzip_body(config_api_response
|
38
|
+
response_body = decompress_gzip_body(config_api_response)
|
39
|
+
@helpers.log_debug(response_body.to_s)
|
30
40
|
|
31
41
|
# Check if response body is not nil
|
32
42
|
if !response_body.nil? then
|
33
43
|
# Return Etag, sample rate and last updated time
|
34
|
-
return config_api_response.headers[:x_moesif_config_etag],
|
44
|
+
return response_body, config_api_response.headers[:x_moesif_config_etag], Time.now.utc
|
35
45
|
else
|
36
|
-
|
37
|
-
puts 'Response body is nil, assuming default behavior'
|
38
|
-
end
|
46
|
+
@helpers.log_debug 'Response body is nil, assuming default behavior'
|
39
47
|
# Response body is nil, so assuming default behavior
|
40
48
|
return nil, 100, Time.now.utc
|
41
49
|
end
|
42
50
|
rescue => exception
|
43
|
-
|
44
|
-
|
45
|
-
puts exception.to_s
|
46
|
-
end
|
51
|
+
@helpers.log_debug 'Error while parsing the configuration object, assuming default behavior'
|
52
|
+
@helpers.log_debug exception.to_s
|
47
53
|
# Assuming default behavior
|
48
54
|
return nil, 100, Time.now.utc
|
49
55
|
end
|
50
56
|
end
|
51
57
|
|
52
|
-
def get_sampling_percentage(config_api_response, user_id, company_id
|
58
|
+
def get_sampling_percentage(config_api_response, user_id, company_id)
|
53
59
|
# Get sampling percentage
|
54
60
|
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
61
|
# Check if response body is not nil
|
59
|
-
if !
|
60
|
-
|
62
|
+
if !config_api_response.nil? then
|
63
|
+
@helpers.log_debug("Getting sample rate for user #{user_id} company #{company_id}")
|
64
|
+
@helpers.log_debug(config_api_response.to_s)
|
65
|
+
|
61
66
|
# Get user sample rate object
|
62
|
-
user_sample_rate =
|
67
|
+
user_sample_rate = config_api_response.fetch('user_sample_rate', nil)
|
63
68
|
|
64
69
|
# Get company sample rate object
|
65
|
-
company_sample_rate =
|
70
|
+
company_sample_rate = config_api_response.fetch('company_sample_rate', nil)
|
66
71
|
|
67
72
|
# Get sample rate for the user if exist
|
68
73
|
if !user_id.nil? && !user_sample_rate.nil? && user_sample_rate.key?(user_id)
|
@@ -75,22 +80,18 @@ class AppConfig
|
|
75
80
|
end
|
76
81
|
|
77
82
|
# Return sample rate
|
78
|
-
return
|
83
|
+
return config_api_response.fetch('sample_rate', 100)
|
79
84
|
else
|
80
|
-
|
81
|
-
puts 'Assuming default behavior as response body is nil - '
|
82
|
-
end
|
85
|
+
@helpers.log_debug 'Assuming default behavior as response body is nil - '
|
83
86
|
return 100
|
84
87
|
end
|
85
88
|
rescue => exception
|
86
|
-
|
87
|
-
puts 'Error while geting sampling percentage, assuming default behavior'
|
88
|
-
end
|
89
|
+
@helpers.log_debug 'Error while geting sampling percentage, assuming default behavior'
|
89
90
|
return 100
|
90
91
|
end
|
91
92
|
end
|
92
93
|
|
93
|
-
def decompress_gzip_body(config_api_response
|
94
|
+
def decompress_gzip_body(config_api_response)
|
94
95
|
# Decompress gzip response body
|
95
96
|
begin
|
96
97
|
# Check if the content-encoding header exist and is of type zip
|
@@ -105,17 +106,17 @@ class AppConfig
|
|
105
106
|
# Return the parsed body
|
106
107
|
return JSON.parse( uncompressed_string )
|
107
108
|
else
|
108
|
-
|
109
|
-
puts 'Content Encoding is of type other than gzip, returning nil'
|
110
|
-
end
|
109
|
+
@helpers.log_debug 'Content Encoding is of type other than gzip, returning nil'
|
111
110
|
return nil
|
112
111
|
end
|
113
112
|
rescue => exception
|
114
|
-
|
115
|
-
|
116
|
-
puts exception.to_s
|
117
|
-
end
|
113
|
+
@helpers.log_debug 'Error while decompressing the response body'
|
114
|
+
@helpers.log_debug exception.to_s
|
118
115
|
return nil
|
119
116
|
end
|
120
117
|
end
|
118
|
+
|
119
|
+
def calculate_weight(sample_rate)
|
120
|
+
return sample_rate == 0 ? 1 : (100 / sample_rate).floor
|
121
|
+
end
|
121
122
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
|
2
2
|
def is_ip?(value)
|
3
|
+
ipv4 = /^(?:(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/
|
4
|
+
ipv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
|
3
5
|
if
|
4
|
-
ipv4 = /^(?:(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/
|
5
|
-
ipv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
|
6
6
|
# We use !! to convert the return value to a boolean
|
7
7
|
!!(value =~ ipv4 or value=~ ipv6)
|
8
8
|
end
|
@@ -6,6 +6,9 @@ require_relative './client_ip.rb'
|
|
6
6
|
require_relative './app_config.rb'
|
7
7
|
require_relative './update_user.rb'
|
8
8
|
require_relative './update_company.rb'
|
9
|
+
require_relative './helpers.rb'
|
10
|
+
require 'zlib'
|
11
|
+
require 'stringio'
|
9
12
|
|
10
13
|
module MoesifRack
|
11
14
|
|
@@ -26,30 +29,34 @@ module MoesifRack
|
|
26
29
|
@mask_data = options['mask_data']
|
27
30
|
@skip = options['skip']
|
28
31
|
@debug = options['debug']
|
29
|
-
@app_config = AppConfig.new
|
30
|
-
@
|
32
|
+
@app_config = AppConfig.new(@debug)
|
33
|
+
@helpers = Helpers.new(@debug)
|
34
|
+
@config = @app_config.get_config(@api_controller)
|
31
35
|
@config_etag = nil
|
32
|
-
@
|
33
|
-
@
|
36
|
+
@last_config_download_time = Time.now.utc
|
37
|
+
@last_worker_run = Time.now.utc
|
34
38
|
@config_dict = Hash.new
|
35
39
|
@disable_transaction_id = options['disable_transaction_id'] || false
|
36
40
|
@log_body = options.fetch('log_body', true)
|
41
|
+
@batch_size = options['batch_size'] || 25
|
42
|
+
@batch_max_time = options['batch_max_time'] || 2
|
43
|
+
@events_queue = Queue.new
|
44
|
+
@event_response_config_etag = nil
|
45
|
+
start_worker()
|
46
|
+
|
37
47
|
begin
|
38
|
-
|
39
|
-
|
48
|
+
new_config = @app_config.get_config(@api_controller)
|
49
|
+
if !new_config.nil?
|
50
|
+
@config, @config_etag, @last_config_download_time = @app_config.parse_configuration(new_config)
|
40
51
|
end
|
41
52
|
rescue => exception
|
42
|
-
|
43
|
-
|
44
|
-
puts exception.to_s
|
45
|
-
end
|
53
|
+
@helpers.log_debug 'Error while parsing application configuration on initialization'
|
54
|
+
@helpers.log_debug exception.to_s
|
46
55
|
end
|
47
56
|
@capture_outoing_requests = options['capture_outoing_requests']
|
48
57
|
@capture_outgoing_requests = options['capture_outgoing_requests']
|
49
58
|
if @capture_outoing_requests || @capture_outgoing_requests
|
50
|
-
|
51
|
-
puts 'Start Capturing outgoing requests'
|
52
|
-
end
|
59
|
+
@helpers.log_debug 'Start Capturing outgoing requests'
|
53
60
|
require_relative '../../moesif_capture_outgoing/httplog.rb'
|
54
61
|
MoesifCaptureOutgoing.start_capture_outgoing(options)
|
55
62
|
end
|
@@ -71,12 +78,84 @@ module MoesifRack
|
|
71
78
|
CompanyHelper.new.update_companies_batch(@api_controller, @debug, company_profiles)
|
72
79
|
end
|
73
80
|
|
74
|
-
def
|
75
|
-
|
81
|
+
def start_with_json(body)
|
82
|
+
body.start_with?('{') || body.start_with?('[')
|
83
|
+
end
|
84
|
+
|
85
|
+
def decompress_body(body)
|
86
|
+
Zlib::GzipReader.new(StringIO.new(body)).read
|
87
|
+
end
|
88
|
+
|
89
|
+
def transform_headers(headers)
|
90
|
+
Hash[headers.map { |k, v| [k.downcase, v]}]
|
91
|
+
end
|
92
|
+
|
93
|
+
def base64_encode_body(body)
|
94
|
+
return Base64.encode64(body), 'base64'
|
95
|
+
end
|
76
96
|
|
97
|
+
def @helpers.log_debug(message)
|
77
98
|
if @debug
|
78
|
-
puts
|
99
|
+
puts("#{Time.now.to_s} [Moesif Middleware] PID #{Process.pid} TID #{Thread.current.object_id} #{message}")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def parse_body(body, headers)
|
104
|
+
begin
|
105
|
+
if start_with_json(body)
|
106
|
+
parsed_body = JSON.parse(body)
|
107
|
+
transfer_encoding = 'json'
|
108
|
+
elsif headers.key?('content-encoding') && ((headers['content-encoding'].downcase).include? "gzip")
|
109
|
+
uncompressed_string = decompress_body(body)
|
110
|
+
parsed_body, transfer_encoding = base64_encode_body(uncompressed_string)
|
111
|
+
else
|
112
|
+
parsed_body, transfer_encoding = base64_encode_body(body)
|
113
|
+
end
|
114
|
+
rescue
|
115
|
+
parsed_body, transfer_encoding = base64_encode_body(body)
|
116
|
+
end
|
117
|
+
return parsed_body, transfer_encoding
|
118
|
+
end
|
119
|
+
|
120
|
+
def start_worker
|
121
|
+
Thread::new do
|
122
|
+
@last_worker_run = Time.now.utc
|
123
|
+
loop do
|
124
|
+
begin
|
125
|
+
until @events_queue.empty? do
|
126
|
+
batch_events = []
|
127
|
+
until batch_events.size == @batch_size || @events_queue.empty? do
|
128
|
+
batch_events << @events_queue.pop
|
129
|
+
end
|
130
|
+
@helpers.log_debug("Sending #{batch_events.size.to_s} events to Moesif")
|
131
|
+
event_api_response = @api_controller.create_events_batch(batch_events)
|
132
|
+
@event_response_config_etag = event_api_response[:x_moesif_config_etag]
|
133
|
+
@helpers.log_debug(event_api_response.to_s)
|
134
|
+
@helpers.log_debug("Events successfully sent to Moesif")
|
135
|
+
end
|
136
|
+
|
137
|
+
if @events_queue.empty?
|
138
|
+
@helpers.log_debug("No events to read from the queue")
|
139
|
+
end
|
140
|
+
|
141
|
+
sleep @batch_max_time
|
142
|
+
rescue MoesifApi::APIException => e
|
143
|
+
if e.response_code.between?(401, 403)
|
144
|
+
puts "Unathorized accesss sending event to Moesif. Please verify your Application Id."
|
145
|
+
@helpers.log_debug(e.to_s)
|
146
|
+
end
|
147
|
+
@helpers.log_debug("Error sending event to Moesif, with status code #{e.response_code.to_s}")
|
148
|
+
rescue => e
|
149
|
+
@helpers.log_debug(e.to_s)
|
150
|
+
end
|
151
|
+
end
|
79
152
|
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def call env
|
156
|
+
start_time = Time.now.utc.iso8601
|
157
|
+
|
158
|
+
@helpers.log_debug('Calling Moesif middleware')
|
80
159
|
|
81
160
|
status, headers, body = @app.call env
|
82
161
|
end_time = Time.now.utc.iso8601
|
@@ -86,7 +165,7 @@ module MoesifRack
|
|
86
165
|
complex_copy = env.dup
|
87
166
|
|
88
167
|
req_headers = {}
|
89
|
-
complex_copy.select {|k,v| k.start_with?
|
168
|
+
complex_copy.select {|k,v| k.start_with?('HTTP_', 'CONTENT_') }.each do |key, val|
|
90
169
|
new_key = key.sub(/^HTTP_/, '')
|
91
170
|
new_key = new_key.sub('_', '-')
|
92
171
|
req_headers[new_key] = val
|
@@ -99,12 +178,7 @@ module MoesifRack
|
|
99
178
|
|
100
179
|
if @log_body
|
101
180
|
if req_body_string && req_body_string.length != 0
|
102
|
-
|
103
|
-
req_body = JSON.parse(req_body_string)
|
104
|
-
rescue
|
105
|
-
req_body = Base64.encode64(req_body_string)
|
106
|
-
req_body_transfer_encoding = 'base64'
|
107
|
-
end
|
181
|
+
req_body, req_body_transfer_encoding = parse_body(req_body_string, transform_headers(req_headers))
|
108
182
|
end
|
109
183
|
end
|
110
184
|
|
@@ -116,12 +190,7 @@ module MoesifRack
|
|
116
190
|
|
117
191
|
if @log_body
|
118
192
|
if rsp_body_string && rsp_body_string.length != 0
|
119
|
-
|
120
|
-
rsp_body = JSON.parse(rsp_body_string)
|
121
|
-
rescue
|
122
|
-
rsp_body = Base64.encode64(rsp_body_string)
|
123
|
-
rsp_body_transfer_encoding = 'base64'
|
124
|
-
end
|
193
|
+
rsp_body, rsp_body_transfer_encoding = parse_body(rsp_body_string, transform_headers(rsp_headers))
|
125
194
|
end
|
126
195
|
end
|
127
196
|
|
@@ -181,88 +250,71 @@ module MoesifRack
|
|
181
250
|
event_model.direction = "Incoming"
|
182
251
|
|
183
252
|
if @identify_user
|
184
|
-
|
185
|
-
puts "calling identify user proc"
|
186
|
-
end
|
253
|
+
@helpers.log_debug "calling identify user proc"
|
187
254
|
event_model.user_id = @identify_user.call(env, headers, body)
|
188
255
|
end
|
189
256
|
|
190
257
|
if @identify_company
|
191
|
-
|
192
|
-
puts "calling identify company proc"
|
193
|
-
end
|
258
|
+
@helpers.log_debug "calling identify company proc"
|
194
259
|
event_model.company_id = @identify_company.call(env, headers, body)
|
195
260
|
end
|
196
261
|
|
197
262
|
if @get_metadata
|
198
|
-
|
199
|
-
puts "calling get_metadata proc"
|
200
|
-
end
|
263
|
+
@helpers.log_debug "calling get_metadata proc"
|
201
264
|
event_model.metadata = @get_metadata.call(env, headers, body)
|
202
265
|
end
|
203
266
|
|
204
267
|
if @identify_session
|
205
|
-
|
206
|
-
puts "calling identify session proc"
|
207
|
-
end
|
268
|
+
@helpers.log_debug "calling identify session proc"
|
208
269
|
event_model.session_token = @identify_session.call(env, headers, body)
|
209
270
|
end
|
210
271
|
if @mask_data
|
211
|
-
|
212
|
-
puts "calling mask_data proc"
|
213
|
-
end
|
272
|
+
@helpers.log_debug "calling mask_data proc"
|
214
273
|
event_model = @mask_data.call(event_model)
|
215
274
|
end
|
216
275
|
|
217
|
-
|
218
|
-
|
219
|
-
puts event_model.to_json
|
220
|
-
end
|
276
|
+
@helpers.log_debug "sending data to moesif"
|
277
|
+
@helpers.log_debug event_model.to_json
|
221
278
|
# Perform the API call through the SDK function
|
222
279
|
begin
|
223
|
-
|
280
|
+
random_percentage = Random.rand(0.00..100.00)
|
224
281
|
|
225
282
|
begin
|
226
|
-
|
283
|
+
sampling_percentage = @app_config.get_sampling_percentage(@config, event_model.user_id, event_model.company_id)
|
284
|
+
@helpers.log_debug "Using sample rate #{sampling_percentage}"
|
227
285
|
rescue => exception
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
end
|
232
|
-
@sampling_percentage = 100
|
286
|
+
@helpers.log_debug 'Error while getting sampling percentage, assuming default behavior'
|
287
|
+
@helpers.log_debug exception.to_s
|
288
|
+
sampling_percentage = 100
|
233
289
|
end
|
234
290
|
|
235
|
-
if
|
236
|
-
|
237
|
-
|
291
|
+
if sampling_percentage > random_percentage
|
292
|
+
event_model.weight = @app_config.calculate_weight(sampling_percentage)
|
293
|
+
# Add Event to the queue
|
294
|
+
@events_queue << event_model
|
295
|
+
@helpers.log_debug("Event added to the queue ")
|
296
|
+
if Time.now.utc > (@last_config_download_time + 60)
|
297
|
+
start_worker()
|
298
|
+
end
|
238
299
|
|
239
|
-
if
|
300
|
+
if !@event_response_config_etag.nil? && !@config_etag.nil? && @config_etag != @event_response_config_etag && Time.now.utc > (@last_config_download_time + 300)
|
240
301
|
begin
|
241
|
-
|
242
|
-
|
302
|
+
new_config = @app_config.get_config(@api_controller)
|
303
|
+
if !new_config.nil?
|
304
|
+
@config, @config_etag, @last_config_download_time = @app_config.parse_configuration(new_config)
|
305
|
+
end
|
306
|
+
|
243
307
|
rescue => exception
|
244
|
-
|
245
|
-
|
246
|
-
puts exception.to_s
|
247
|
-
end
|
308
|
+
@helpers.log_debug 'Error while updating the application configuration'
|
309
|
+
@helpers.log_debug exception.to_s
|
248
310
|
end
|
249
311
|
end
|
250
|
-
if @debug
|
251
|
-
puts("Event successfully sent to Moesif")
|
252
|
-
end
|
253
312
|
else
|
254
|
-
|
255
|
-
puts("Skipped Event due to sampling percentage: " + @sampling_percentage.to_s + " and random percentage: " + @random_percentage.to_s)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
rescue MoesifApi::APIException => e
|
259
|
-
if e.response_code.between?(401, 403)
|
260
|
-
puts "Unathorized accesss sending event to Moesif. Please verify your Application Id."
|
261
|
-
end
|
262
|
-
if @debug
|
263
|
-
puts "Error sending event to Moesif, with status code: "
|
264
|
-
puts e.response_code
|
313
|
+
@helpers.log_debug("Skipped Event due to sampling percentage: " + sampling_percentage.to_s + " and random percentage: " + random_percentage .to_s)
|
265
314
|
end
|
315
|
+
rescue => exception
|
316
|
+
@helpers.log_debug "Error adding event to the queue "
|
317
|
+
@helpers.log_debug exception.to_s
|
266
318
|
end
|
267
319
|
|
268
320
|
end
|
@@ -276,11 +328,7 @@ module MoesifRack
|
|
276
328
|
end
|
277
329
|
|
278
330
|
if !should_skip
|
279
|
-
|
280
|
-
process_send.call
|
281
|
-
else
|
282
|
-
Thread.start(&process_send)
|
283
|
-
end
|
331
|
+
process_send.call
|
284
332
|
end
|
285
333
|
|
286
334
|
[status, headers, body]
|
@@ -3,6 +3,7 @@ require 'rack'
|
|
3
3
|
require 'moesif_api'
|
4
4
|
require 'json'
|
5
5
|
require 'base64'
|
6
|
+
require_relative '../../lib/moesif_rack/app_config.rb'
|
6
7
|
|
7
8
|
module MoesifCaptureOutgoing
|
8
9
|
|
@@ -23,6 +24,22 @@ module MoesifCaptureOutgoing
|
|
23
24
|
@skip_outgoing = options['skip_outgoing']
|
24
25
|
@mask_data_outgoing = options['mask_data_outgoing']
|
25
26
|
@log_body_outgoing = options.fetch('log_body_outgoing', true)
|
27
|
+
@app_config = AppConfig.new
|
28
|
+
@config = @app_config.get_config(@api_controller, @debug)
|
29
|
+
@config_etag = nil
|
30
|
+
@sampling_percentage = 100
|
31
|
+
@last_updated_time = Time.now.utc
|
32
|
+
@config_dict = Hash.new
|
33
|
+
begin
|
34
|
+
if !@config.nil?
|
35
|
+
@config_etag, @sampling_percentage, @last_updated_time = @app_config.parse_configuration(@config, @debug)
|
36
|
+
end
|
37
|
+
rescue => exception
|
38
|
+
if @debug
|
39
|
+
puts 'Error while parsing application configuration on initialization'
|
40
|
+
puts exception.to_s
|
41
|
+
end
|
42
|
+
end
|
26
43
|
end
|
27
44
|
|
28
45
|
def call (url, request, request_time, response, response_time)
|
@@ -157,11 +174,45 @@ module MoesifCaptureOutgoing
|
|
157
174
|
|
158
175
|
# Send Event to Moesif
|
159
176
|
begin
|
160
|
-
|
161
|
-
|
162
|
-
|
177
|
+
@random_percentage = Random.rand(0.00..100.00)
|
178
|
+
begin
|
179
|
+
@sampling_percentage = @app_config.get_sampling_percentage(@config, event_model.user_id, event_model.company_id, @debug)
|
180
|
+
rescue => exception
|
181
|
+
if @debug
|
182
|
+
puts 'Error while getting sampling percentage, assuming default behavior'
|
183
|
+
puts exception.to_s
|
184
|
+
end
|
185
|
+
@sampling_percentage = 100
|
186
|
+
end
|
187
|
+
|
188
|
+
if @sampling_percentage > @random_percentage
|
189
|
+
event_model.weight = @app_config.calculate_weight(@sampling_percentage)
|
190
|
+
if @debug
|
191
|
+
puts 'Sending Outgoing Request Data to Moesif'
|
192
|
+
puts event_model.to_json
|
193
|
+
end
|
194
|
+
event_api_response = @api_controller.create_event(event_model)
|
195
|
+
event_response_config_etag = event_api_response[:x_moesif_config_etag]
|
196
|
+
|
197
|
+
if !event_response_config_etag.nil? && !@config_etag.nil? && @config_etag != event_response_config_etag && Time.now.utc > @last_updated_time + 300
|
198
|
+
begin
|
199
|
+
@config = @app_config.get_config(@api_controller, @debug)
|
200
|
+
@config_etag, @sampling_percentage, @last_updated_time = @app_config.parse_configuration(@config, @debug)
|
201
|
+
rescue => exception
|
202
|
+
if @debug
|
203
|
+
puts 'Error while updating the application configuration'
|
204
|
+
puts exception.to_s
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
if @debug
|
209
|
+
puts("Event successfully sent to Moesif")
|
210
|
+
end
|
211
|
+
else
|
212
|
+
if @debug
|
213
|
+
puts("Skipped outgoing Event due to sampling percentage: " + @sampling_percentage.to_s + " and random percentage: " + @random_percentage.to_s)
|
214
|
+
end
|
163
215
|
end
|
164
|
-
@api_controller.create_event(event_model)
|
165
216
|
rescue MoesifApi::APIException => e
|
166
217
|
if e.response_code.between?(401, 403)
|
167
218
|
puts "Unathorized accesss sending event to Moesif. Please verify your Application Id."
|
@@ -170,6 +221,10 @@ module MoesifCaptureOutgoing
|
|
170
221
|
puts "Error sending event to Moesif, with status code: "
|
171
222
|
puts e.response_code
|
172
223
|
end
|
224
|
+
rescue => e
|
225
|
+
if debug
|
226
|
+
puts e.to_s
|
227
|
+
end
|
173
228
|
end
|
174
229
|
else
|
175
230
|
if @debug
|
data/test/moesif_rack_test.rb
CHANGED
@@ -108,6 +108,8 @@ class MoesifRackTest < Test::Unit::TestCase
|
|
108
108
|
|
109
109
|
def test_log_event
|
110
110
|
response = @moesif_rack_app.call(Rack::MockRequest.env_for("https://acmeinc.com/items/42752/reviews"))
|
111
|
+
# Sleep to allow queue to flush for testing purpose
|
112
|
+
sleep 5
|
111
113
|
assert_equal response, @app.call(nil)
|
112
114
|
end
|
113
115
|
|
metadata
CHANGED
@@ -1,28 +1,34 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moesif_rack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Moesif, Inc
|
8
8
|
- Xing Wang
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-06-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: test-unit
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '3.1'
|
21
|
+
- - ">="
|
19
22
|
- !ruby/object:Gem::Version
|
20
23
|
version: 3.1.5
|
21
|
-
type: :
|
24
|
+
type: :development
|
22
25
|
prerelease: false
|
23
26
|
version_requirements: !ruby/object:Gem::Requirement
|
24
27
|
requirements:
|
25
28
|
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '3.1'
|
31
|
+
- - ">="
|
26
32
|
- !ruby/object:Gem::Version
|
27
33
|
version: 3.1.5
|
28
34
|
- !ruby/object:Gem::Dependency
|
@@ -31,15 +37,21 @@ dependencies:
|
|
31
37
|
requirements:
|
32
38
|
- - "~>"
|
33
39
|
- !ruby/object:Gem::Version
|
34
|
-
version: 1.2
|
40
|
+
version: '1.2'
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.2.12
|
35
44
|
type: :runtime
|
36
45
|
prerelease: false
|
37
46
|
version_requirements: !ruby/object:Gem::Requirement
|
38
47
|
requirements:
|
39
48
|
- - "~>"
|
40
49
|
- !ruby/object:Gem::Version
|
41
|
-
version: 1.2
|
42
|
-
|
50
|
+
version: '1.2'
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.2.12
|
54
|
+
description: Rack/Rails middleware to log API calls to Moesif API analytics and monitoring
|
43
55
|
email: xing@moesif.com
|
44
56
|
executables: []
|
45
57
|
extensions: []
|
@@ -50,6 +62,7 @@ files:
|
|
50
62
|
- lib/moesif_rack.rb
|
51
63
|
- lib/moesif_rack/app_config.rb
|
52
64
|
- lib/moesif_rack/client_ip.rb
|
65
|
+
- lib/moesif_rack/helpers.rb
|
53
66
|
- lib/moesif_rack/moesif_middleware.rb
|
54
67
|
- lib/moesif_rack/update_company.rb
|
55
68
|
- lib/moesif_rack/update_user.rb
|
@@ -61,7 +74,7 @@ homepage: https://moesif.com
|
|
61
74
|
licenses:
|
62
75
|
- Apache-2.0
|
63
76
|
metadata: {}
|
64
|
-
post_install_message:
|
77
|
+
post_install_message:
|
65
78
|
rdoc_options: []
|
66
79
|
require_paths:
|
67
80
|
- lib
|
@@ -76,9 +89,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
89
|
- !ruby/object:Gem::Version
|
77
90
|
version: '0'
|
78
91
|
requirements: []
|
79
|
-
rubyforge_project:
|
92
|
+
rubyforge_project:
|
80
93
|
rubygems_version: 2.7.7
|
81
|
-
signing_key:
|
94
|
+
signing_key:
|
82
95
|
specification_version: 4
|
83
96
|
summary: moesif_rack
|
84
97
|
test_files: []
|