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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5449e55b2da865cdc2bd4d52eef977b45db5a3e7648ee18f67f93795bf1fcd46
4
- data.tar.gz: 930c9fb3a9181eec3b12d5aea8073c12646f94f77d16638dfa0422107b8000f3
3
+ metadata.gz: 8c44fb915ecec7479c930ab41b3b74eeb58a368f387d3fa8d47211e41c4a0c80
4
+ data.tar.gz: 6974bb001d57faeffc0f58df1a4c4661ac52d4a6f5280d78c1e35c7deb5fb183
5
5
  SHA512:
6
- metadata.gz: 13012b377dac7ca5da3dcaf1d50ef97e71f6515df9e7f94e61b39746b4f29b134efcbc87eaafcb8dcd04dd67e0e052d8f0c5e9c77dd6ea20a7d997f50df3feb6
7
- data.tar.gz: d7499b20fa602a2dd1bde29099b5b11755f36421f79c32f59fc1e1aa7f0e1dce7794b7ed1ca703c74ff07f040492b3ecc12f038eb3f52625348b13ae9becb2ec
6
+ metadata.gz: '08b7997c9a683384cc7725dff3248a41b5ddb15974be2d259d9553fb1903075814260e8df0cda6a7d1e6340b7d8d27d3c99f725f0dd088caaae28476539f162c'
7
+ data.tar.gz: c0d75f0f8ab0f8d87d4a86fa4396e4100a94d7a0f37190260bbbe3db91ec40dcaa91f4d1d945f768a1fd0483dde2a816eb388a7e9cfd5fd89c4df33881104639
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2019 Moesif, Inc
1
+ Copyright (c) 2020 Moesif, Inc
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
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.9'
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 get_config(api_controller, debug)
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
- 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
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, debug)
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, debug)
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], response_body.fetch("sample_rate", 100), Time.now.utc
44
+ return response_body, config_api_response.headers[:x_moesif_config_etag], Time.now.utc
35
45
  else
36
- if debug
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
- if debug
44
- puts 'Error while parsing the configuration object, assuming default behavior'
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, debug)
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 !response_body.nil? then
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 = response_body.fetch('user_sample_rate', nil)
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 = response_body.fetch('company_sample_rate', nil)
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 response_body.fetch('sample_rate', 100)
83
+ return config_api_response.fetch('sample_rate', 100)
79
84
  else
80
- if debug
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
- if debug
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, debug)
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
- if debug
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
- if debug
115
- puts 'Error while decompressing the response body'
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
@@ -0,0 +1,14 @@
1
+ require 'time'
2
+
3
+ class Helpers
4
+
5
+ def initialize debug
6
+ @debug = debug
7
+ end
8
+
9
+ def log_debug(message)
10
+ if @debug
11
+ puts("#{Time.now.to_s} [Moesif Middleware] PID #{Process.pid} TID #{Thread.current.object_id} #{message}")
12
+ end
13
+ end
14
+ 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
- @config = @app_config.get_config(@api_controller, @debug)
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
- @sampling_percentage = 100
33
- @last_updated_time = Time.now.utc
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
- if !@config.nil?
39
- @config_etag, @sampling_percentage, @last_updated_time = @app_config.parse_configuration(@config, @debug)
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
- if @debug
43
- puts 'Error while parsing application configuration on initialization'
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
- if @debug
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 call env
75
- start_time = Time.now.utc.iso8601
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 'inside moesif middleware'
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? 'HTTP_'}.each do |key, val|
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
- begin
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
- begin
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
- if @debug
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
- if @debug
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
- if @debug
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
- if @debug
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
- if @debug
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
- if @debug
218
- puts "sending data to moesif"
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
- @random_percentage = Random.rand(0.00..100.00)
280
+ random_percentage = Random.rand(0.00..100.00)
224
281
 
225
282
  begin
226
- @sampling_percentage = @app_config.get_sampling_percentage(@config, event_model.user_id, event_model.company_id, @debug)
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
- if @debug
229
- puts 'Error while getting sampling percentage, assuming default behavior'
230
- puts exception.to_s
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 @sampling_percentage > @random_percentage
236
- event_api_response = @api_controller.create_event(event_model)
237
- event_response_config_etag = event_api_response[:x_moesif_config_etag]
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 !event_response_config_etag.nil? && !@config_etag.nil? && @config_etag != event_response_config_etag && Time.now.utc > @last_updated_time + 300
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
- @config = @app_config.get_config(@api_controller, @debug)
242
- @config_etag, @sampling_percentage, @last_updated_time = @app_config.parse_configuration(@config, @debug)
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
- if @debug
245
- puts 'Error while updating the application configuration'
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
- if @debug
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
- if @debug
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
- if @debug
161
- puts 'Sending Outgoing Request Data to Moesif'
162
- puts event_model.to_json
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
@@ -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.3.10
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: 2019-12-16 00:00:00.000000000 Z
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: :runtime
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.10
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.10
42
- description: Collection/Data Ingestion SDK for Rack (also Rails) Middleware / RoR
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: []