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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/resources/error_messages.json +46 -18
  3. data/lib/resources/info_messages.json +4 -2
  4. data/lib/vwo/api/get_flag.rb +13 -8
  5. data/lib/vwo/api/track_event.rb +2 -2
  6. data/lib/vwo/constants/constants.rb +24 -1
  7. data/lib/vwo/decorators/storage_decorator.rb +1 -5
  8. data/lib/vwo/enums/api_enum.rb +7 -3
  9. data/lib/vwo/enums/debug_category_enum.rb +20 -0
  10. data/lib/vwo/enums/event_enum.rb +1 -0
  11. data/lib/vwo/models/user/context_model.rb +36 -2
  12. data/lib/vwo/models/vwo_options_model.rb +14 -3
  13. data/lib/vwo/packages/network_layer/client/network_client.rb +189 -34
  14. data/lib/vwo/packages/network_layer/manager/network_manager.rb +71 -6
  15. data/lib/vwo/packages/network_layer/models/request_model.rb +38 -4
  16. data/lib/vwo/packages/network_layer/models/response_model.rb +10 -1
  17. data/lib/vwo/packages/segmentation_evaluator/core/segmentation_manager.rb +2 -1
  18. data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_evaluator.rb +5 -3
  19. data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_operand_evaluator.rb +3 -2
  20. data/lib/vwo/services/logger_service.rb +21 -1
  21. data/lib/vwo/services/settings_service.rb +37 -9
  22. data/lib/vwo/services/storage_service.rb +5 -4
  23. data/lib/vwo/utils/{batch_event_dispatcher.rb → batch_event_dispatcher_util.rb} +70 -9
  24. data/lib/vwo/utils/campaign_util.rb +35 -0
  25. data/lib/vwo/utils/debugger_service_util.rb +40 -0
  26. data/lib/vwo/utils/event_util.rb +8 -2
  27. data/lib/vwo/utils/function_util.rb +14 -0
  28. data/lib/vwo/utils/gateway_service_util.rb +5 -5
  29. data/lib/vwo/utils/impression_util.rb +16 -2
  30. data/lib/vwo/utils/meg_util.rb +29 -22
  31. data/lib/vwo/utils/network_util.rb +145 -38
  32. data/lib/vwo/utils/rule_evaluation_util.rb +1 -1
  33. data/lib/vwo/vwo_builder.rb +15 -11
  34. data/lib/vwo/vwo_client.rb +11 -25
  35. metadata +5 -4
  36. 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
- # Build the URL and headers
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
- # Create the HTTP GET request
56
- request = Net::HTTP::Get.new(uri)
57
- # Add headers to the request
58
- request_model.get_headers.each { |k, v| request[k] = v }
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
- # Process the response
66
- response_model = ResponseModel.new
67
- response_model.set_status_code(response.code.to_i) # Convert status code to integer
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
- # Parse the response body as JSON
71
- parsed_data = JSON.parse(response.body)
72
- response_model.set_data(parsed_data)
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
- # Handle any JSON parsing errors
75
- response_model.set_error(e.message)
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 post(request_model)
83
- url = request_model.get_url + request_model.get_path
84
- uri = URI(url)
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
- response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(request) }
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
- @client = client || NetworkClient.new(@should_use_threading)
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
- LoggerService.log(LogLevelEnum::ERROR, "Error getting: #{e.message}", nil)
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
- hostname, collection_prefix = @url.split('/')
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
- end
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, "Error in setting contextual data for segmentation. Got error: #{e.message}", nil)
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::ERROR, "Feature not found with featureIdKey: #{feature_id_key}", nil)
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, 'To evaluate location pre Segment, please pass ipAddress in context object', nil)
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, 'To evaluate user agent related segments, please pass userAgent in context object', nil)
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, "Invalid 'inList' operand format", nil)
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, "Error while fetching data: #{e}", nil)
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