moesif_rack 1.4.0 → 1.4.5
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 +17 -17
- data/lib/moesif_rack/app_config.rb +36 -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 -85
- data/moesif_capture_outgoing/httplog/http_log.rb +4 -0
- data/test/moesif_rack_test.rb +2 -0
- metadata +31 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2366969ea63a6f2aeeb37498dc5bbfad99d4ea43753085237af1326689050cc4
|
4
|
+
data.tar.gz: 2ac98efe04dc86f79db515805ed5f45e7beff707c87c82e42fc7adc2eacbc883
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f18420e49b9dbd3f6d8a1cba791a4c235a06d3568e8ed47d5be9059e93b09acdd6a71a7a7382f500daafe1d5d1b6dd3c3eb87b7d99612db042a41a3a881eb65c
|
7
|
+
data.tar.gz: a1a3174c9e701e6ccd809ee0ea113878ca53b0ed8194ca612ba5491f0aaa9aa2761e3b586b3acaf23f6317244700111026e6ae9ce84f212a87dd4a25bdda7619
|
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'
|
25
|
+
gem 'moesif_rack'
|
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
|
@@ -375,7 +375,7 @@ For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby
|
|
375
375
|
```ruby
|
376
376
|
users = []
|
377
377
|
|
378
|
-
metadata
|
378
|
+
metadata = {
|
379
379
|
:email => 'john@acmeinc.com',
|
380
380
|
:first_name => 'John',
|
381
381
|
:last_name => 'Doe',
|
@@ -389,7 +389,7 @@ metadata => {
|
|
389
389
|
|
390
390
|
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
391
391
|
# See https://www.moesif.com/docs/api#users for campaign schema
|
392
|
-
campaign = CampaignModel.new()
|
392
|
+
campaign = MoesifApi::CampaignModel.new()
|
393
393
|
campaign.utm_source = "google"
|
394
394
|
campaign.utm_medium = "cpc"
|
395
395
|
campaign.utm_campaign = "adwords"
|
@@ -398,7 +398,7 @@ campaign.utm_content = "landing"
|
|
398
398
|
|
399
399
|
# Only user_id is required.
|
400
400
|
# metadata can be any custom object
|
401
|
-
user = UserModel.new()
|
401
|
+
user = MoesifApi::UserModel.new()
|
402
402
|
user.user_id = "12345"
|
403
403
|
user.company_id = "67890" # If set, associate user with a company object
|
404
404
|
user.campaign = campaign
|
@@ -419,7 +419,7 @@ This method is a convenient helper that calls the Moesif API lib.
|
|
419
419
|
For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby#update-a-company).
|
420
420
|
|
421
421
|
```ruby
|
422
|
-
metadata
|
422
|
+
metadata = {
|
423
423
|
:org_name => 'Acme, Inc',
|
424
424
|
:plan_name => 'Free',
|
425
425
|
:deal_stage => 'Lead',
|
@@ -432,7 +432,7 @@ metadata => {
|
|
432
432
|
|
433
433
|
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
434
434
|
# See https://www.moesif.com/docs/api#update-a-company for campaign schema
|
435
|
-
campaign = CampaignModel.new()
|
435
|
+
campaign = MoesifApi::CampaignModel.new()
|
436
436
|
campaign.utm_source = "google"
|
437
437
|
campaign.utm_medium = "cpc"
|
438
438
|
campaign.utm_campaign = "adwords"
|
@@ -441,7 +441,7 @@ campaign.utm_content = "landing"
|
|
441
441
|
|
442
442
|
# Only company_id is required.
|
443
443
|
# metadata can be any custom object
|
444
|
-
company = CompanyModel.new()
|
444
|
+
company = MoesifApi::CompanyModel.new()
|
445
445
|
company.company_id = "67890"
|
446
446
|
company.company_domain = "acmeinc.com" # If domain is set, Moesif will enrich your profiles with publicly available info
|
447
447
|
company.campaign = campaign
|
@@ -459,7 +459,7 @@ For details, visit the [Ruby API Reference](https://www.moesif.com/docs/api?ruby
|
|
459
459
|
```ruby
|
460
460
|
companies = []
|
461
461
|
|
462
|
-
metadata
|
462
|
+
metadata = {
|
463
463
|
:org_name => 'Acme, Inc',
|
464
464
|
:plan_name => 'Free',
|
465
465
|
:deal_stage => 'Lead',
|
@@ -472,7 +472,7 @@ metadata => {
|
|
472
472
|
|
473
473
|
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
|
474
474
|
# See https://www.moesif.com/docs/api#update-a-company for campaign schema
|
475
|
-
campaign = CampaignModel.new()
|
475
|
+
campaign = MoesifApi::CampaignModel.new()
|
476
476
|
campaign.utm_source = "google"
|
477
477
|
campaign.utm_medium = "cpc"
|
478
478
|
campaign.utm_campaign = "adwords"
|
@@ -481,7 +481,7 @@ campaign.utm_content = "landing"
|
|
481
481
|
|
482
482
|
# Only company_id is required.
|
483
483
|
# metadata can be any custom object
|
484
|
-
company = CompanyModel.new()
|
484
|
+
company = MoesifApi::CompanyModel.new()
|
485
485
|
company.company_id = "67890"
|
486
486
|
company.company_domain = "acmeinc.com" # If domain is set, Moesif will enrich your profiles with publicly available info
|
487
487
|
company.campaign = campaign
|
@@ -500,11 +500,11 @@ response = MoesifRack::MoesifMiddleware.new(@app, @options).update_companies_bat
|
|
500
500
|
5. Invoke 'ruby test/moesif_rack_test.rb'
|
501
501
|
6. Invoke 'ruby -I test test/moesif_rack_test.rb -n test_capture_outgoing' to test capturing outgoing API calls from your app to third parties like Stripe, Github or to your own dependencies.
|
502
502
|
|
503
|
-
## Example
|
503
|
+
## Example Projects
|
504
504
|
|
505
|
-
[Moesif
|
506
|
-
|
507
|
-
[Moesif Rack Example](https://github.com/Moesif/moesif-rack-example) is an example of Moesif
|
505
|
+
- [Moesif Rails 5 Example](https://github.com/Moesif/moesif-rails5-example) is an example of Moesif with a Ruby on Rails 5 application.
|
506
|
+
- [Moesif Rails 4 Example](https://github.com/Moesif/moesif-rails4-example) is an example of Moesif with a Ruby on Rails 4 application.
|
507
|
+
- [Moesif Rack Example](https://github.com/Moesif/moesif-rack-example) is an example of Moesif applied to a Rack application.
|
508
508
|
|
509
509
|
## Other integrations
|
510
510
|
|
@@ -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,16 +106,12 @@ 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
|
@@ -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,89 +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
|
-
event_model.weight = @app_config.calculate_weight(
|
237
|
-
|
238
|
-
|
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
|
239
299
|
|
240
|
-
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)
|
241
301
|
begin
|
242
|
-
|
243
|
-
|
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
|
+
|
244
307
|
rescue => exception
|
245
|
-
|
246
|
-
|
247
|
-
puts exception.to_s
|
248
|
-
end
|
308
|
+
@helpers.log_debug 'Error while updating the application configuration'
|
309
|
+
@helpers.log_debug exception.to_s
|
249
310
|
end
|
250
311
|
end
|
251
|
-
if @debug
|
252
|
-
puts("Event successfully sent to Moesif")
|
253
|
-
end
|
254
312
|
else
|
255
|
-
|
256
|
-
puts("Skipped Event due to sampling percentage: " + @sampling_percentage.to_s + " and random percentage: " + @random_percentage.to_s)
|
257
|
-
end
|
258
|
-
end
|
259
|
-
rescue MoesifApi::APIException => e
|
260
|
-
if e.response_code.between?(401, 403)
|
261
|
-
puts "Unathorized accesss sending event to Moesif. Please verify your Application Id."
|
262
|
-
end
|
263
|
-
if @debug
|
264
|
-
puts "Error sending event to Moesif, with status code: "
|
265
|
-
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)
|
266
314
|
end
|
315
|
+
rescue => exception
|
316
|
+
@helpers.log_debug "Error adding event to the queue "
|
317
|
+
@helpers.log_debug exception.to_s
|
267
318
|
end
|
268
319
|
|
269
320
|
end
|
@@ -277,11 +328,7 @@ module MoesifRack
|
|
277
328
|
end
|
278
329
|
|
279
330
|
if !should_skip
|
280
|
-
|
281
|
-
process_send.call
|
282
|
-
else
|
283
|
-
Thread.start(&process_send)
|
284
|
-
end
|
331
|
+
process_send.call
|
285
332
|
end
|
286
333
|
|
287
334
|
[status, headers, body]
|
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.
|
4
|
+
version: 1.4.5
|
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
|
@@ -60,8 +73,15 @@ files:
|
|
60
73
|
homepage: https://moesif.com
|
61
74
|
licenses:
|
62
75
|
- Apache-2.0
|
63
|
-
metadata:
|
64
|
-
|
76
|
+
metadata:
|
77
|
+
bug_tracker_uri: https://github.com/Moesif/moesif-rack/issues
|
78
|
+
changelog_uri: https://github.com/Moesif/moesif-rack/releases
|
79
|
+
documentation_uri: https://www.moesif.com/docs/server-integration/rack/
|
80
|
+
homepage_uri: https://www.moesif.com
|
81
|
+
mailing_list_uri: https://github.com/Moesif/moesif-rack
|
82
|
+
source_code_uri: https://github.com/Moesif/moesif-rack
|
83
|
+
wiki_uri: https://github.com/Moesif/moesif-rack
|
84
|
+
post_install_message:
|
65
85
|
rdoc_options: []
|
66
86
|
require_paths:
|
67
87
|
- lib
|
@@ -76,9 +96,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
96
|
- !ruby/object:Gem::Version
|
77
97
|
version: '0'
|
78
98
|
requirements: []
|
79
|
-
|
80
|
-
|
81
|
-
signing_key:
|
99
|
+
rubygems_version: 3.1.4
|
100
|
+
signing_key:
|
82
101
|
specification_version: 4
|
83
102
|
summary: moesif_rack
|
84
103
|
test_files: []
|