vwo-fme-ruby-sdk 1.6.1 → 1.8.0
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/lib/resources/error_messages.json +46 -18
- data/lib/resources/info_messages.json +4 -2
- data/lib/vwo/api/get_flag.rb +13 -8
- data/lib/vwo/api/track_event.rb +2 -2
- data/lib/vwo/constants/constants.rb +24 -1
- data/lib/vwo/decorators/storage_decorator.rb +1 -5
- data/lib/vwo/enums/api_enum.rb +7 -3
- data/lib/vwo/enums/debug_category_enum.rb +20 -0
- data/lib/vwo/enums/event_enum.rb +1 -0
- data/lib/vwo/models/user/context_model.rb +36 -2
- data/lib/vwo/models/vwo_options_model.rb +14 -3
- data/lib/vwo/packages/network_layer/client/network_client.rb +189 -34
- data/lib/vwo/packages/network_layer/manager/network_manager.rb +71 -6
- data/lib/vwo/packages/network_layer/models/request_model.rb +38 -4
- data/lib/vwo/packages/network_layer/models/response_model.rb +10 -1
- data/lib/vwo/packages/segmentation_evaluator/core/segmentation_manager.rb +2 -1
- data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_evaluator.rb +5 -3
- data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_operand_evaluator.rb +3 -2
- data/lib/vwo/services/logger_service.rb +21 -1
- data/lib/vwo/services/settings_service.rb +37 -9
- data/lib/vwo/services/storage_service.rb +5 -4
- data/lib/vwo/utils/{batch_event_dispatcher.rb → batch_event_dispatcher_util.rb} +70 -9
- data/lib/vwo/utils/campaign_util.rb +35 -0
- data/lib/vwo/utils/debugger_service_util.rb +40 -0
- data/lib/vwo/utils/event_util.rb +8 -2
- data/lib/vwo/utils/function_util.rb +14 -0
- data/lib/vwo/utils/gateway_service_util.rb +5 -5
- data/lib/vwo/utils/impression_util.rb +16 -2
- data/lib/vwo/utils/meg_util.rb +29 -22
- data/lib/vwo/utils/network_util.rb +145 -38
- data/lib/vwo/utils/rule_evaluation_util.rb +1 -1
- data/lib/vwo/vwo_builder.rb +15 -11
- data/lib/vwo/vwo_client.rb +11 -25
- metadata +5 -4
- data/lib/vwo/utils/url_util.rb +0 -53
|
@@ -20,6 +20,10 @@ require_relative '../../../utils/network_util'
|
|
|
20
20
|
require 'net/http'
|
|
21
21
|
require 'concurrent-ruby'
|
|
22
22
|
require_relative '../../../constants/constants'
|
|
23
|
+
require_relative '../../../services/logger_service'
|
|
24
|
+
require_relative '../../../enums/log_level_enum'
|
|
25
|
+
require_relative '../../../enums/event_enum'
|
|
26
|
+
require_relative '../../../utils/function_util'
|
|
23
27
|
|
|
24
28
|
class NetworkClient
|
|
25
29
|
HTTPS_SCHEME = 'https'
|
|
@@ -48,61 +52,181 @@ class NetworkClient
|
|
|
48
52
|
end
|
|
49
53
|
|
|
50
54
|
def get(request_model)
|
|
51
|
-
|
|
55
|
+
execute_with_retry(request_model, :get_request)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def post(request_model)
|
|
59
|
+
execute_with_retry(request_model, :post_request)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def execute_with_retry(request_model, request_type)
|
|
52
65
|
url = request_model.get_url + request_model.get_path
|
|
53
66
|
uri = URI(url)
|
|
67
|
+
attempt = 0
|
|
68
|
+
|
|
69
|
+
# Get retry config from request model or use defaults
|
|
70
|
+
retry_config = request_model.get_retry_config || Constants::DEFAULT_RETRY_CONFIG.dup
|
|
71
|
+
extra_data = request_model.get_extra_info
|
|
72
|
+
endpoint = request_model.get_path.split('?')[0]
|
|
54
73
|
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# Send the GET request and get the response
|
|
61
|
-
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
|
62
|
-
http.request(request)
|
|
74
|
+
# If retry is disabled, execute without retry logic
|
|
75
|
+
unless retry_config[:should_retry]
|
|
76
|
+
response_model, _should_retry, _last_error_message =
|
|
77
|
+
perform_single_attempt(uri, request_model, request_type, attempt, retry_config)
|
|
78
|
+
return response_model
|
|
63
79
|
end
|
|
64
|
-
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
80
|
+
|
|
81
|
+
# Attempt loop: initial attempt (0) + configured retries
|
|
82
|
+
last_error_message = nil
|
|
83
|
+
last_response_model = nil
|
|
84
|
+
|
|
85
|
+
(0..retry_config[:max_retries] - 1).each do |attempt_index|
|
|
86
|
+
attempt = attempt_index
|
|
87
|
+
|
|
88
|
+
# Perform a single attempt
|
|
89
|
+
response_model, should_retry, last_error_message =
|
|
90
|
+
perform_single_attempt(uri, request_model, request_type, attempt, retry_config, last_error_message)
|
|
91
|
+
|
|
92
|
+
last_response_model = response_model
|
|
93
|
+
|
|
94
|
+
# If there is no retry needed, return immediately
|
|
95
|
+
return response_model unless should_retry
|
|
96
|
+
|
|
97
|
+
# Calculate delay before next retry (in seconds)
|
|
98
|
+
delay_seconds = calculate_retry_delay(attempt_index, retry_config)
|
|
99
|
+
|
|
100
|
+
# Log retry attempt
|
|
101
|
+
LoggerService.log(
|
|
102
|
+
LogLevelEnum::ERROR,
|
|
103
|
+
"ATTEMPTING_RETRY_FOR_FAILED_NETWORK_CALL",
|
|
104
|
+
{
|
|
105
|
+
endPoint: endpoint,
|
|
106
|
+
err: last_error_message,
|
|
107
|
+
delay: delay_seconds,
|
|
108
|
+
attempt: attempt_index + 1,
|
|
109
|
+
maxRetries: retry_config[:max_retries]
|
|
110
|
+
}.merge(extra_data), false
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Store last error on request for diagnostics
|
|
114
|
+
request_model.set_last_error(last_error_message)
|
|
115
|
+
|
|
116
|
+
sleep(delay_seconds)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# All attempts exhausted
|
|
120
|
+
total_attempts = retry_config[:max_retries]
|
|
121
|
+
final_error_message = last_error_message || 'Unknown error'
|
|
122
|
+
|
|
123
|
+
# Log failure after max retries (skip for debugger events)
|
|
124
|
+
unless endpoint.include?(EventEnum::VWO_DEBUGGER_EVENT)
|
|
125
|
+
LoggerService.log(
|
|
126
|
+
LogLevelEnum::ERROR,
|
|
127
|
+
"NETWORK_CALL_FAILURE_AFTER_MAX_RETRIES",
|
|
128
|
+
{
|
|
129
|
+
extraData: endpoint,
|
|
130
|
+
attempts: total_attempts,
|
|
131
|
+
err: final_error_message
|
|
132
|
+
}.merge(extra_data),
|
|
133
|
+
false
|
|
134
|
+
)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
if last_response_model
|
|
138
|
+
last_response_model.set_total_attempts(total_attempts)
|
|
139
|
+
last_response_model.set_error(final_error_message)
|
|
140
|
+
last_response_model
|
|
141
|
+
else
|
|
142
|
+
response_model = ResponseModel.new
|
|
143
|
+
response_model.set_error(final_error_message)
|
|
144
|
+
response_model.set_total_attempts(total_attempts)
|
|
145
|
+
response_model
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Performs a single HTTP attempt (GET/POST) and returns:
|
|
150
|
+
# [ResponseModel, should_retry (Boolean), last_error_message (String or nil)]
|
|
151
|
+
def perform_single_attempt(uri, request_model, request_type, attempt, retry_config, prev_error_message = nil)
|
|
69
152
|
begin
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
153
|
+
# Low-level HTTP call
|
|
154
|
+
response = if request_type == :get_request
|
|
155
|
+
perform_get_request(uri, request_model)
|
|
156
|
+
else
|
|
157
|
+
perform_post_request(uri, request_model)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
response_model = build_response_model(response)
|
|
161
|
+
|
|
162
|
+
# Success (2xx)
|
|
163
|
+
if response.is_a?(Net::HTTPSuccess)
|
|
164
|
+
# On retries, echo back last error and attempts (for diagnostics)
|
|
165
|
+
if attempt.positive?
|
|
166
|
+
response_model.set_total_attempts(attempt)
|
|
167
|
+
response_model.set_error(request_model.get_last_error)
|
|
168
|
+
end
|
|
169
|
+
return [response_model, false, nil]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Client error 400 → do not retry
|
|
173
|
+
if response.code.to_i == 400
|
|
174
|
+
error_message = "#{response.body}, Status Code: #{response.code.to_i}"
|
|
175
|
+
response_model.set_error(error_message)
|
|
176
|
+
response_model.set_total_attempts(attempt)
|
|
177
|
+
return [response_model, false, error_message]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Non-2xx/400 status → decide if we should retry based on status code
|
|
181
|
+
should_retry = should_retry(response, attempt, retry_config)
|
|
182
|
+
error_message = "#{response.body}, Status Code: #{response.code.to_i}"
|
|
183
|
+
response_model.set_error(error_message)
|
|
184
|
+
response_model.set_total_attempts(attempt)
|
|
185
|
+
[response_model, should_retry, error_message]
|
|
73
186
|
rescue StandardError => e
|
|
74
|
-
#
|
|
75
|
-
|
|
187
|
+
# Network / timeout / other exceptions
|
|
188
|
+
error_message = get_formatted_error_message(e)
|
|
189
|
+
response_model = ResponseModel.new
|
|
190
|
+
response_model.set_error(error_message)
|
|
191
|
+
response_model.set_total_attempts(attempt)
|
|
192
|
+
|
|
193
|
+
should_retry = should_retry_on_error(e, attempt, retry_config)
|
|
194
|
+
[response_model, should_retry, error_message]
|
|
76
195
|
end
|
|
77
|
-
|
|
78
|
-
# Return the response model
|
|
79
|
-
response_model
|
|
80
196
|
end
|
|
81
197
|
|
|
82
|
-
def
|
|
83
|
-
|
|
84
|
-
|
|
198
|
+
def perform_get_request(uri, request_model)
|
|
199
|
+
request = Net::HTTP::Get.new(uri)
|
|
200
|
+
request_model.get_headers.each { |k, v| request[k] = v }
|
|
201
|
+
|
|
202
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https', open_timeout: Constants::REQUEST_TIMEOUT, read_timeout: Constants::REQUEST_TIMEOUT) do |http|
|
|
203
|
+
http.request(request)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def perform_post_request(uri, request_model)
|
|
85
208
|
headers = request_model.get_headers
|
|
86
209
|
body = JSON.dump(request_model.get_body)
|
|
87
210
|
|
|
88
211
|
request = Net::HTTP::Post.new(uri, headers)
|
|
89
212
|
request.body = body
|
|
90
213
|
|
|
91
|
-
|
|
214
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https', open_timeout: Constants::REQUEST_TIMEOUT, read_timeout: Constants::REQUEST_TIMEOUT) do |http|
|
|
215
|
+
http.request(request)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
92
218
|
|
|
219
|
+
def build_response_model(response)
|
|
93
220
|
response_model = ResponseModel.new
|
|
94
221
|
response_model.set_status_code(response.code.to_i)
|
|
95
222
|
|
|
96
|
-
# Check if the response body is empty or invalid before parsing
|
|
97
223
|
if response.is_a?(Net::HTTPSuccess) && !response.body.strip.empty?
|
|
98
|
-
# Check if the response body is JSON
|
|
99
224
|
content_type = response['Content-Type']&.downcase
|
|
100
225
|
if content_type&.include?('application/json')
|
|
101
226
|
begin
|
|
102
227
|
parsed_data = JSON.parse(response.body)
|
|
103
228
|
response_model.set_data(parsed_data)
|
|
104
229
|
rescue JSON::ParserError => e
|
|
105
|
-
# Handle invalid JSON response
|
|
106
230
|
response_model.set_error("Invalid JSON response: #{e.message}")
|
|
107
231
|
end
|
|
108
232
|
else
|
|
@@ -111,11 +235,42 @@ class NetworkClient
|
|
|
111
235
|
end
|
|
112
236
|
|
|
113
237
|
response_model
|
|
114
|
-
rescue StandardError => e
|
|
115
|
-
LoggerService.log(LogLevelEnum::ERROR, "POST request failed: #{e.message}", nil)
|
|
116
|
-
response_model = ResponseModel.new
|
|
117
|
-
response_model.set_error(e.message)
|
|
118
|
-
response_model
|
|
119
238
|
end
|
|
239
|
+
|
|
240
|
+
def should_retry(response, attempt, retry_config)
|
|
241
|
+
# Retry on server errors (5xx) or network timeouts
|
|
242
|
+
status_code = response.code.to_i
|
|
243
|
+
status_code < 200 || status_code > 300
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def should_retry_on_error(error, attempt, retry_config)
|
|
247
|
+
return false if attempt >= retry_config[:max_retries]
|
|
248
|
+
|
|
249
|
+
# Retry on network errors, timeouts, and connection errors
|
|
250
|
+
# Check for specific error types that indicate transient network issues
|
|
251
|
+
retryable = error.is_a?(Net::OpenTimeout) ||
|
|
252
|
+
error.is_a?(Net::ReadTimeout) ||
|
|
253
|
+
error.is_a?(Errno::ECONNREFUSED) ||
|
|
254
|
+
error.is_a?(Errno::ETIMEDOUT) ||
|
|
255
|
+
error.is_a?(Errno::EHOSTUNREACH) ||
|
|
256
|
+
error.is_a?(Errno::ENETUNREACH) ||
|
|
257
|
+
error.is_a?(Errno::ECONNRESET) ||
|
|
258
|
+
error.is_a?(Errno::EPIPE) ||
|
|
259
|
+
error.is_a?(SocketError) ||
|
|
260
|
+
(error.respond_to?(:message) && error.message &&
|
|
261
|
+
(error.message.downcase.include?('timeout') ||
|
|
262
|
+
error.message.downcase.include?('connection') ||
|
|
263
|
+
error.message.downcase.include?('connection refused') ||
|
|
264
|
+
error.message.downcase.include?('getaddrinfo') ||
|
|
265
|
+
error.message.downcase.include?('connection reset') ||
|
|
266
|
+
error.message.downcase.include?('broken pipe')))
|
|
267
|
+
|
|
268
|
+
retryable
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def calculate_retry_delay(attempt, retry_config)
|
|
272
|
+
retry_config[:initial_delay] * (retry_config[:backoff_multiplier] ** attempt)
|
|
273
|
+
end
|
|
274
|
+
|
|
120
275
|
|
|
121
276
|
end
|
|
@@ -18,6 +18,9 @@ require_relative '../models/global_request_model'
|
|
|
18
18
|
require_relative '../../../services/logger_service'
|
|
19
19
|
require_relative '../../../enums/log_level_enum'
|
|
20
20
|
require_relative '../../../constants/constants'
|
|
21
|
+
require_relative '../../../enums/api_enum'
|
|
22
|
+
require_relative '../../../utils/data_type_util'
|
|
23
|
+
|
|
21
24
|
class NetworkManager
|
|
22
25
|
@instance = nil
|
|
23
26
|
|
|
@@ -25,14 +28,73 @@ class NetworkManager
|
|
|
25
28
|
@client = NetworkClient.new(options)
|
|
26
29
|
@config = GlobalRequestModel.new(nil, {}, {}, {})
|
|
27
30
|
@should_use_threading = options.key?(:enabled) ? options[:enabled] : Constants::SHOULD_USE_THREADING
|
|
31
|
+
@retry_config = nil
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def self.instance(options = {})
|
|
31
35
|
@instance ||= new(options)
|
|
32
36
|
end
|
|
33
37
|
|
|
34
|
-
def attach_client(client = nil)
|
|
35
|
-
|
|
38
|
+
def attach_client(client = nil, retry_config = nil)
|
|
39
|
+
# Only set retry configuration if it's not already initialized or if a new config is provided
|
|
40
|
+
if !@retry_config || retry_config
|
|
41
|
+
# Define default retry configuration
|
|
42
|
+
default_retry_config = Constants::DEFAULT_RETRY_CONFIG.dup
|
|
43
|
+
|
|
44
|
+
# Merge provided retry_config with defaults, giving priority to provided values
|
|
45
|
+
merged_config = default_retry_config.merge(retry_config || {})
|
|
46
|
+
|
|
47
|
+
# Validate the merged configuration
|
|
48
|
+
@retry_config = validate_retry_config(merged_config)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def get_retry_config
|
|
53
|
+
@retry_config ? @retry_config.dup : nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def validate_retry_config(retry_config)
|
|
57
|
+
validated_config = retry_config.dup
|
|
58
|
+
is_invalid_config = false
|
|
59
|
+
|
|
60
|
+
# Validate should_retry: should be a boolean value
|
|
61
|
+
if !DataTypeUtil.is_boolean(validated_config[:should_retry])
|
|
62
|
+
validated_config[:should_retry] = Constants::DEFAULT_RETRY_CONFIG[:should_retry]
|
|
63
|
+
is_invalid_config = true
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Validate max_retries: should be a non-negative integer and should not be less than 1
|
|
67
|
+
if !DataTypeUtil.is_number(validated_config[:max_retries]) ||
|
|
68
|
+
!validated_config[:max_retries].is_a?(Integer) ||
|
|
69
|
+
validated_config[:max_retries] < 1
|
|
70
|
+
validated_config[:max_retries] = Constants::DEFAULT_RETRY_CONFIG[:max_retries]
|
|
71
|
+
is_invalid_config = true
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Validate initial_delay: should be a non-negative integer and should not be less than 1
|
|
75
|
+
if !DataTypeUtil.is_number(validated_config[:initial_delay]) ||
|
|
76
|
+
!validated_config[:initial_delay].is_a?(Integer) ||
|
|
77
|
+
validated_config[:initial_delay] < 1
|
|
78
|
+
validated_config[:initial_delay] = Constants::DEFAULT_RETRY_CONFIG[:initial_delay]
|
|
79
|
+
is_invalid_config = true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Validate backoff_multiplier: should be a non-negative integer and should not be less than 2
|
|
83
|
+
if !DataTypeUtil.is_number(validated_config[:backoff_multiplier]) ||
|
|
84
|
+
!validated_config[:backoff_multiplier].is_a?(Integer) ||
|
|
85
|
+
validated_config[:backoff_multiplier] < 2
|
|
86
|
+
validated_config[:backoff_multiplier] = Constants::DEFAULT_RETRY_CONFIG[:backoff_multiplier]
|
|
87
|
+
is_invalid_config = true
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if is_invalid_config
|
|
91
|
+
LoggerService.log(LogLevelEnum::ERROR, "INVALID_RETRY_CONFIG", {
|
|
92
|
+
retryConfig: validated_config.to_json,
|
|
93
|
+
an: ApiEnum::INIT
|
|
94
|
+
})
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
is_invalid_config ? Constants::DEFAULT_RETRY_CONFIG.dup : validated_config
|
|
36
98
|
end
|
|
37
99
|
|
|
38
100
|
def get_client
|
|
@@ -48,7 +110,12 @@ class NetworkManager
|
|
|
48
110
|
end
|
|
49
111
|
|
|
50
112
|
def create_request(request)
|
|
51
|
-
RequestHandler.new.create_request(request, @config)
|
|
113
|
+
network_request = RequestHandler.new.create_request(request, @config)
|
|
114
|
+
# Set retry config from network manager if not already set in request
|
|
115
|
+
if @retry_config && (!network_request.get_retry_config || network_request.get_retry_config.nil?)
|
|
116
|
+
network_request.set_retry_config(@retry_config.dup)
|
|
117
|
+
end
|
|
118
|
+
network_request
|
|
52
119
|
end
|
|
53
120
|
|
|
54
121
|
def get(request)
|
|
@@ -59,8 +126,7 @@ class NetworkManager
|
|
|
59
126
|
response = @client.get(network_options)
|
|
60
127
|
response
|
|
61
128
|
rescue => e
|
|
62
|
-
|
|
63
|
-
raise e
|
|
129
|
+
return ResponseModel.new.set_error(e.message)
|
|
64
130
|
end
|
|
65
131
|
end
|
|
66
132
|
|
|
@@ -73,7 +139,6 @@ class NetworkManager
|
|
|
73
139
|
response = @client.post(network_options) # Return the response
|
|
74
140
|
response
|
|
75
141
|
rescue => e
|
|
76
|
-
LoggerService.log(LogLevelEnum::ERROR, "Error posting: #{e.message}", nil)
|
|
77
142
|
return ResponseModel.new.set_error(e.message) # Return error response
|
|
78
143
|
end
|
|
79
144
|
end
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
class RequestModel
|
|
16
|
-
attr_accessor :url, :method, :path, :query, :timeout, :body, :headers, :scheme, :port
|
|
16
|
+
attr_accessor :url, :method, :path, :query, :timeout, :body, :headers, :scheme, :port, :last_error, :retry_config, :event_name, :uuid, :campaign_id, :event_properties
|
|
17
17
|
|
|
18
|
-
def initialize(url, method = 'GET', path = '', query = {}, body = {}, headers = {}, scheme = 'https', port = nil)
|
|
18
|
+
def initialize(url, method = 'GET', path = '', query = {}, body = {}, headers = {}, scheme = 'https', port = nil, retry_config = nil)
|
|
19
19
|
@url = scheme + '://' + url
|
|
20
20
|
@method = method
|
|
21
21
|
@path = path
|
|
@@ -25,6 +25,12 @@ class RequestModel
|
|
|
25
25
|
@headers = headers
|
|
26
26
|
@scheme = scheme
|
|
27
27
|
@port = port
|
|
28
|
+
@last_error = nil
|
|
29
|
+
@retry_config = retry_config
|
|
30
|
+
@event_name = nil
|
|
31
|
+
@uuid = nil
|
|
32
|
+
@campaign_id = nil
|
|
33
|
+
@event_properties = nil
|
|
28
34
|
if !@port.nil?
|
|
29
35
|
@url = @url + ':' + @port.to_s
|
|
30
36
|
end
|
|
@@ -33,7 +39,7 @@ class RequestModel
|
|
|
33
39
|
end
|
|
34
40
|
|
|
35
41
|
def parse_options
|
|
36
|
-
|
|
42
|
+
_hostname, collection_prefix = @url.split('/')
|
|
37
43
|
|
|
38
44
|
# Process body if present
|
|
39
45
|
if !@body.nil?
|
|
@@ -141,5 +147,33 @@ class RequestModel
|
|
|
141
147
|
def get_url
|
|
142
148
|
@url
|
|
143
149
|
end
|
|
144
|
-
|
|
150
|
+
|
|
151
|
+
def set_last_error(last_error)
|
|
152
|
+
@last_error = last_error
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def get_last_error
|
|
156
|
+
@last_error
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def get_retry_config
|
|
160
|
+
@retry_config
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def set_retry_config(retry_config)
|
|
164
|
+
@retry_config = retry_config
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def get_extra_info
|
|
168
|
+
extra_info = {}
|
|
169
|
+
white_listed_keys = [:event_name, :uuid, :campaign_id, :event_properties]
|
|
170
|
+
|
|
171
|
+
white_listed_keys.each do |key|
|
|
172
|
+
value = instance_variable_get("@#{key}")
|
|
173
|
+
extra_info[key] = value if !value.nil?
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
extra_info
|
|
177
|
+
end
|
|
178
|
+
end
|
|
145
179
|
|
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
class ResponseModel
|
|
16
|
-
attr_accessor :status_code, :error, :headers, :data
|
|
16
|
+
attr_accessor :status_code, :error, :headers, :data, :total_attempts
|
|
17
17
|
|
|
18
18
|
def initialize
|
|
19
19
|
@status_code = nil
|
|
20
20
|
@error = nil
|
|
21
21
|
@headers = {}
|
|
22
22
|
@data = nil
|
|
23
|
+
@total_attempts = 0
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
def set_status_code(code)
|
|
@@ -49,5 +50,13 @@ class ResponseModel
|
|
|
49
50
|
def get_status_code
|
|
50
51
|
@status_code
|
|
51
52
|
end
|
|
53
|
+
|
|
54
|
+
def set_total_attempts(total_attempts)
|
|
55
|
+
@total_attempts = total_attempts
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def get_total_attempts
|
|
59
|
+
@total_attempts
|
|
60
|
+
end
|
|
52
61
|
end
|
|
53
62
|
|
|
@@ -23,6 +23,7 @@ require_relative '../../../models/user/context_vwo_model'
|
|
|
23
23
|
require_relative '../../../services/settings_service'
|
|
24
24
|
require_relative '../../../utils/data_type_util'
|
|
25
25
|
require_relative '../../../enums/log_level_enum'
|
|
26
|
+
require_relative '../../../enums/api_enum'
|
|
26
27
|
class SegmentationManager
|
|
27
28
|
@@instance = nil # Singleton instance
|
|
28
29
|
|
|
@@ -64,7 +65,7 @@ class SegmentationManager
|
|
|
64
65
|
vwo_data = get_from_gateway_service(params, UrlEnum::GET_USER_DATA)
|
|
65
66
|
context.set_vwo(ContextVWOModel.new.model_from_dictionary(vwo_data))
|
|
66
67
|
rescue StandardError => e
|
|
67
|
-
LoggerService.log(LogLevelEnum::ERROR, "
|
|
68
|
+
LoggerService.log(LogLevelEnum::ERROR, "ERROR_SETTING_SEGMENTATION_CONTEXT", { err: e.message, an: ApiEnum::GET_FLAG, sId: context.get_session_id, uuid: context.get_uuid})
|
|
68
69
|
end
|
|
69
70
|
end
|
|
70
71
|
end
|
|
@@ -24,6 +24,8 @@ require_relative '../core/segmentation_manager'
|
|
|
24
24
|
require_relative '../utils/segment_util'
|
|
25
25
|
require_relative './segment_operand_evaluator'
|
|
26
26
|
require_relative '../../../enums/log_level_enum'
|
|
27
|
+
require_relative '../../../enums/api_enum'
|
|
28
|
+
|
|
27
29
|
class SegmentEvaluator
|
|
28
30
|
attr_accessor :context, :settings, :feature
|
|
29
31
|
|
|
@@ -100,7 +102,7 @@ class SegmentEvaluator
|
|
|
100
102
|
return !result if feature_id_value == 'off'
|
|
101
103
|
return result
|
|
102
104
|
else
|
|
103
|
-
LoggerService.log(LogLevelEnum::
|
|
105
|
+
LoggerService.log(LogLevelEnum::INFO, "Feature not found with featureIdKey: #{feature_id_key}", nil)
|
|
104
106
|
return nil
|
|
105
107
|
end
|
|
106
108
|
end
|
|
@@ -146,7 +148,7 @@ class SegmentEvaluator
|
|
|
146
148
|
# @return [Boolean] True if the location pre-segmentation is valid, false otherwise
|
|
147
149
|
def check_location_pre_segmentation(location_map)
|
|
148
150
|
unless @context&.get_ip_address
|
|
149
|
-
LoggerService.log(LogLevelEnum::ERROR, '
|
|
151
|
+
LoggerService.log(LogLevelEnum::ERROR, 'INVALID_IP_ADDRESS_IN_CONTEXT_FOR_PRE_SEGMENTATION', { an: ApiEnum::GET_FLAG, sId: @context.get_session_id, uuid: @context.get_uuid})
|
|
150
152
|
return false
|
|
151
153
|
end
|
|
152
154
|
|
|
@@ -162,7 +164,7 @@ class SegmentEvaluator
|
|
|
162
164
|
# @return [Boolean] True if the user agent parser is valid, false otherwise
|
|
163
165
|
def check_user_agent_parser(ua_parser_map)
|
|
164
166
|
unless @context&.get_user_agent
|
|
165
|
-
LoggerService.log(LogLevelEnum::ERROR, '
|
|
167
|
+
LoggerService.log(LogLevelEnum::ERROR, 'INVALID_USER_AGENT_IN_CONTEXT_FOR_PRE_SEGMENTATION', { an: ApiEnum::GET_FLAG, sId: @context.get_session_id, uuid: @context.get_uuid})
|
|
166
168
|
return false
|
|
167
169
|
end
|
|
168
170
|
|
|
@@ -22,6 +22,7 @@ require_relative '../../../enums/url_enum'
|
|
|
22
22
|
require_relative '../../../services/logger_service'
|
|
23
23
|
require_relative '../../../models/user/context_model'
|
|
24
24
|
require_relative '../../../enums/log_level_enum'
|
|
25
|
+
require_relative '../../../enums/api_enum'
|
|
25
26
|
|
|
26
27
|
# SegmentOperandEvaluator class provides methods to evaluate different types of DSL (Domain Specific Language)
|
|
27
28
|
# expressions based on the segment conditions defined for custom variables, user IDs, and user agents.
|
|
@@ -45,7 +46,7 @@ class SegmentOperandEvaluator
|
|
|
45
46
|
if operand.include?('inlist')
|
|
46
47
|
match = operand.match(/inlist\(([^)]+)\)/)
|
|
47
48
|
unless match
|
|
48
|
-
LoggerService.log(LogLevelEnum::ERROR, "
|
|
49
|
+
LoggerService.log(LogLevelEnum::ERROR, "INVALID_ATTRIBUTE_LIST_FORMAT", { an: ApiEnum::GET_FLAG, sId: @context.get_session_id, uuid: @context.get_uuid})
|
|
49
50
|
return false
|
|
50
51
|
end
|
|
51
52
|
|
|
@@ -62,7 +63,7 @@ class SegmentOperandEvaluator
|
|
|
62
63
|
end
|
|
63
64
|
return res
|
|
64
65
|
rescue StandardError => e
|
|
65
|
-
LoggerService.log(LogLevelEnum::ERROR, "
|
|
66
|
+
LoggerService.log(LogLevelEnum::ERROR, "ERROR_FETCHING_DATA_FROM_GATEWAY", { err: e.message, an: ApiEnum::GET_FLAG, sId: @context.get_session_id, uuid: @context.get_uuid})
|
|
66
67
|
return false
|
|
67
68
|
end
|
|
68
69
|
|
|
@@ -17,13 +17,15 @@ require_relative '../vwo_client'
|
|
|
17
17
|
require_relative '../packages/logger/core/log_manager'
|
|
18
18
|
require_relative '../enums/log_level_enum'
|
|
19
19
|
require_relative '../utils/log_message_util'
|
|
20
|
+
require_relative '../enums/debug_category_enum'
|
|
21
|
+
require_relative '../utils/debugger_service_util'
|
|
20
22
|
|
|
21
23
|
class LoggerService
|
|
22
24
|
class << self
|
|
23
25
|
attr_accessor :debug_messages, :info_messages, :error_messages, :warning_messages
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
def self.log(level, key = nil, map = {})
|
|
28
|
+
def self.log(level, key = nil, map = {}, should_send_to_vwo = true)
|
|
27
29
|
log_manager = LogManager.instance
|
|
28
30
|
|
|
29
31
|
if key && map
|
|
@@ -41,6 +43,10 @@ class LoggerService
|
|
|
41
43
|
log_manager.warn(message)
|
|
42
44
|
else
|
|
43
45
|
log_manager.error(message)
|
|
46
|
+
if should_send_to_vwo
|
|
47
|
+
# print log
|
|
48
|
+
self.send_log_to_vwo(key, message, map)
|
|
49
|
+
end
|
|
44
50
|
end
|
|
45
51
|
end
|
|
46
52
|
|
|
@@ -80,4 +86,18 @@ class LoggerService
|
|
|
80
86
|
@error_messages
|
|
81
87
|
end
|
|
82
88
|
end
|
|
89
|
+
|
|
90
|
+
def self.send_log_to_vwo(template, message, debug_props = {})
|
|
91
|
+
# send debugger event to VWO
|
|
92
|
+
begin
|
|
93
|
+
debug_props[:msg_t] = template
|
|
94
|
+
debug_props[:msg] = message
|
|
95
|
+
debug_props[:lt] = LogLevelEnum::ERROR
|
|
96
|
+
debug_props[:cg] = DebugCategoryEnum::ERROR
|
|
97
|
+
|
|
98
|
+
DebuggerServiceUtil.send_debugger_event(debug_props)
|
|
99
|
+
rescue StandardError => e
|
|
100
|
+
puts "[VWO-SDK] ERROR: Error sending log to VWO: #{e.message}"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
83
103
|
end
|