ff-ruby-server-sdk 1.2.1 → 1.3.1
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/api.yaml +319 -30
- data/lib/ff/ruby/server/generated/lib/openapi_client/api/client_api.rb +27 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/api/metrics_api.rb +13 -10
- data/lib/ff/ruby/server/generated/lib/openapi_client/api/proxy_api.rb +159 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/configuration.rb +7 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/clause.rb +6 -5
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/distribution.rb +3 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/error.rb +16 -4
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/group_serving_rule.rb +257 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/inline_object.rb +223 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/pagination.rb +5 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/prerequisite.rb +3 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/proxy_config.rb +299 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/proxy_config_all_of.rb +220 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/proxy_config_all_of_environments.rb +251 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/segment.rb +23 -4
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/serve.rb +1 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/serving_rule.rb +4 -5
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/tag.rb +15 -8
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/target.rb +11 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/target_map.rb +8 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/variation.rb +5 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/variation_map.rb +4 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/weighted_variation.rb +3 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client.rb +6 -0
- data/lib/ff/ruby/server/sdk/api/config.rb +1 -1
- data/lib/ff/ruby/server/sdk/api/evaluator.rb +32 -78
- data/lib/ff/ruby/server/sdk/api/metrics_processor.rb +95 -50
- data/lib/ff/ruby/server/sdk/api/storage_repository.rb +14 -0
- data/lib/ff/ruby/server/sdk/common/sdk_codes.rb +9 -0
- data/lib/ff/ruby/server/sdk/connector/harness_connector.rb +12 -3
- data/lib/ff/ruby/server/sdk/version.rb +1 -1
- data/scripts/sdk_specs.sh +1 -1
- metadata +9 -3
@@ -10,15 +10,12 @@ class Evaluator < Evaluation
|
|
10
10
|
def initialize(repository, logger = nil)
|
11
11
|
|
12
12
|
unless repository.kind_of?(Repository)
|
13
|
-
|
14
13
|
raise "The 'repository' parameter must be of '" + Repository.to_s + "' data type"
|
15
14
|
end
|
16
15
|
|
17
16
|
if logger != nil
|
18
|
-
|
19
17
|
@logger = logger
|
20
18
|
else
|
21
|
-
|
22
19
|
@logger = Logger.new(STDOUT)
|
23
20
|
end
|
24
21
|
|
@@ -30,7 +27,6 @@ class Evaluator < Evaluation
|
|
30
27
|
variation = evaluate(identifier, target, "boolean", callback)
|
31
28
|
|
32
29
|
if variation != nil
|
33
|
-
|
34
30
|
return variation.value == "true"
|
35
31
|
end
|
36
32
|
|
@@ -43,7 +39,6 @@ class Evaluator < Evaluation
|
|
43
39
|
variation = evaluate(identifier, target, "string", callback)
|
44
40
|
|
45
41
|
if variation != nil
|
46
|
-
|
47
42
|
return variation.value
|
48
43
|
end
|
49
44
|
|
@@ -56,7 +51,6 @@ class Evaluator < Evaluation
|
|
56
51
|
variation = evaluate(identifier, target, "int", callback)
|
57
52
|
|
58
53
|
if variation != nil
|
59
|
-
|
60
54
|
return variation.value.to_i
|
61
55
|
end
|
62
56
|
|
@@ -68,7 +62,6 @@ class Evaluator < Evaluation
|
|
68
62
|
variation = evaluate(identifier, target, "int", callback)
|
69
63
|
|
70
64
|
if variation != nil
|
71
|
-
|
72
65
|
return variation.value.to_f
|
73
66
|
end
|
74
67
|
|
@@ -81,7 +74,6 @@ class Evaluator < Evaluation
|
|
81
74
|
variation = evaluate(identifier, target, "json", callback)
|
82
75
|
|
83
76
|
if variation != nil
|
84
|
-
|
85
77
|
return JSON.parse(variation.value)
|
86
78
|
end
|
87
79
|
|
@@ -92,9 +84,7 @@ class Evaluator < Evaluation
|
|
92
84
|
def evaluate(identifier, target, expected, callback)
|
93
85
|
|
94
86
|
if callback != nil
|
95
|
-
|
96
87
|
unless callback.kind_of?(FlagEvaluateCallback)
|
97
|
-
|
98
88
|
raise "The 'callback' parameter must be of '" + FlagEvaluateCallback.to_s + "' data type"
|
99
89
|
end
|
100
90
|
end
|
@@ -102,13 +92,9 @@ class Evaluator < Evaluation
|
|
102
92
|
flag = @repository.get_flag(identifier)
|
103
93
|
|
104
94
|
if flag != nil && flag.kind == expected
|
105
|
-
|
106
95
|
unless flag.prerequisites.empty?
|
107
|
-
|
108
96
|
pre_req = check_pre_requisite(flag, target)
|
109
|
-
|
110
97
|
unless pre_req
|
111
|
-
|
112
98
|
return find_variation(flag.variations, flag.off_variation)
|
113
99
|
end
|
114
100
|
end
|
@@ -116,12 +102,9 @@ class Evaluator < Evaluation
|
|
116
102
|
variation = evaluate_flag(flag, target)
|
117
103
|
|
118
104
|
if variation != nil
|
119
|
-
|
120
105
|
if callback != nil
|
121
|
-
|
122
106
|
callback.process_evaluation(flag, target, variation)
|
123
107
|
end
|
124
|
-
|
125
108
|
return variation
|
126
109
|
end
|
127
110
|
end
|
@@ -134,24 +117,16 @@ class Evaluator < Evaluation
|
|
134
117
|
def get_attr_value(target, attribute)
|
135
118
|
|
136
119
|
if attribute != nil && !attribute.empty?
|
137
|
-
|
138
120
|
if target.respond_to?(attribute, :include_private)
|
139
|
-
|
140
121
|
@logger.debug "The attribute " + attribute.to_s + " exists (1)"
|
141
|
-
|
142
122
|
return target.send(attribute)
|
143
123
|
else
|
144
124
|
|
145
125
|
@logger.debug "target attrs: " + target.attributes.to_s
|
146
|
-
|
147
126
|
result = target.attributes[attribute.to_sym]
|
148
|
-
|
149
127
|
if result == nil
|
150
|
-
|
151
128
|
@logger.debug "The attribute " + attribute.to_s + " does not exist"
|
152
|
-
|
153
129
|
else
|
154
|
-
|
155
130
|
@logger.debug "The attribute " + attribute.to_s + " exists (2)"
|
156
131
|
end
|
157
132
|
|
@@ -167,11 +142,8 @@ class Evaluator < Evaluation
|
|
167
142
|
def find_variation(variations, identifier)
|
168
143
|
|
169
144
|
if identifier != nil && !identifier.empty?
|
170
|
-
|
171
145
|
variations.each do |v|
|
172
|
-
|
173
146
|
if v.identifier == identifier
|
174
|
-
|
175
147
|
return v
|
176
148
|
end
|
177
149
|
end
|
@@ -225,12 +197,26 @@ class Evaluator < Evaluation
|
|
225
197
|
nil
|
226
198
|
end
|
227
199
|
|
200
|
+
|
201
|
+
def evaluate_clauses_v2(clauses, target)
|
202
|
+
if clauses.empty?
|
203
|
+
return false
|
204
|
+
end
|
205
|
+
|
206
|
+
# New style rules require that all clauses are true
|
207
|
+
clauses.each do |clause|
|
208
|
+
if !evaluate_clause(clause, target)
|
209
|
+
return false
|
210
|
+
end
|
211
|
+
end
|
212
|
+
true
|
213
|
+
end
|
214
|
+
|
228
215
|
def evaluate_clauses(clauses, target)
|
229
216
|
|
230
217
|
clauses.each do |clause|
|
231
218
|
|
232
219
|
if evaluate_clause(clause, target)
|
233
|
-
|
234
220
|
return true
|
235
221
|
end
|
236
222
|
end
|
@@ -241,24 +227,20 @@ class Evaluator < Evaluation
|
|
241
227
|
def evaluate_clause(clause, target)
|
242
228
|
|
243
229
|
if clause == nil
|
244
|
-
|
245
230
|
return false
|
246
231
|
end
|
247
232
|
|
248
233
|
operator = clause.op
|
249
234
|
|
250
235
|
if operator == nil || operator.empty?
|
251
|
-
|
252
236
|
return false
|
253
237
|
end
|
254
238
|
|
255
239
|
if operator == "segmentMatch"
|
256
|
-
|
257
240
|
return is_target_included_or_excluded_in_segment(clause.values, target)
|
258
241
|
end
|
259
242
|
|
260
243
|
if clause.values.empty?
|
261
|
-
|
262
244
|
return false
|
263
245
|
end
|
264
246
|
|
@@ -266,50 +248,41 @@ class Evaluator < Evaluation
|
|
266
248
|
attr_value = get_attr_value(target, clause.attribute)
|
267
249
|
|
268
250
|
if attr_value == nil
|
269
|
-
|
270
251
|
return false
|
271
252
|
end
|
272
253
|
|
273
254
|
object = attr_value.to_s
|
274
255
|
|
275
256
|
if operator == "starts_with"
|
276
|
-
|
277
257
|
return object.start_with?(value)
|
278
258
|
end
|
279
259
|
|
280
260
|
if operator == "ends_with"
|
281
|
-
|
282
261
|
return object.end_with?(value)
|
283
262
|
end
|
284
263
|
|
285
264
|
if operator == "match"
|
286
|
-
|
287
265
|
match = object.match?(value)
|
288
266
|
return match != nil && !match.empty?
|
289
267
|
end
|
290
268
|
|
291
269
|
if operator == "contains"
|
292
|
-
|
293
270
|
return object.include?(value)
|
294
271
|
end
|
295
272
|
|
296
273
|
if operator == "equal"
|
297
|
-
|
298
274
|
return object.casecmp?(value)
|
299
275
|
end
|
300
276
|
|
301
277
|
if operator == "equal_sensitive"
|
302
|
-
|
303
278
|
return object == value
|
304
279
|
end
|
305
280
|
|
306
281
|
if operator == "in"
|
307
|
-
|
308
282
|
return clause.values.include?(object)
|
309
283
|
end
|
310
284
|
|
311
285
|
if operator == "segmentMatch"
|
312
|
-
|
313
286
|
return is_target_included_or_excluded_in_segment(clause.values, target)
|
314
287
|
end
|
315
288
|
|
@@ -325,27 +298,34 @@ class Evaluator < Evaluation
|
|
325
298
|
if segment != nil
|
326
299
|
|
327
300
|
if is_target_in_list(target, segment.excluded)
|
328
|
-
|
329
301
|
@logger.debug "Target " + target.name.to_s + " excluded from segment " + segment.name.to_s + " via exclude list"
|
330
|
-
|
331
302
|
return false
|
332
303
|
end
|
333
304
|
|
334
305
|
if is_target_in_list(target, segment.included)
|
335
|
-
|
336
306
|
@logger.debug "Target " + target.name.to_s + " included in segment " + segment.name.to_s + " via include list"
|
337
|
-
|
338
307
|
return true
|
339
308
|
end
|
340
309
|
|
341
|
-
|
342
|
-
|
343
|
-
|
310
|
+
new_serving_rules = segment.serving_rules
|
311
|
+
if new_serving_rules != nil && !new_serving_rules.empty?
|
312
|
+
# Use enhanced rules first if they're available
|
344
313
|
|
345
|
-
|
314
|
+
new_serving_rules.each do |serving_rule|
|
315
|
+
if evaluate_clauses_v2(serving_rule.clauses, target)
|
316
|
+
return true
|
317
|
+
end
|
318
|
+
end
|
346
319
|
|
347
|
-
|
320
|
+
else
|
321
|
+
# Fall back to old rules
|
322
|
+
rules = segment.rules
|
323
|
+
if rules != nil && !rules.empty? && evaluate_clauses(rules, target)
|
324
|
+
@logger.debug "Target " + target.name.to_s + " included in segment " + segment.name.to_s + " via rules"
|
325
|
+
return true
|
326
|
+
end
|
348
327
|
end
|
328
|
+
|
349
329
|
end
|
350
330
|
end
|
351
331
|
|
@@ -355,26 +335,17 @@ class Evaluator < Evaluation
|
|
355
335
|
def evaluate_rules(serving_rules, target)
|
356
336
|
|
357
337
|
if target == nil || serving_rules == nil
|
358
|
-
|
359
338
|
return nil
|
360
339
|
end
|
361
340
|
|
362
|
-
|
363
|
-
|
364
|
-
b.priority <=> a.priority
|
365
|
-
end
|
366
|
-
|
367
|
-
sorted.each do |rule|
|
368
|
-
|
341
|
+
serving_rules.each do |rule|
|
369
342
|
next unless evaluate_rule(rule, target)
|
370
343
|
|
371
344
|
if rule.serve.distribution != nil
|
372
|
-
|
373
345
|
return evaluate_distribution(rule.serve.distribution, target)
|
374
346
|
end
|
375
347
|
|
376
348
|
if rule.serve.variation != nil
|
377
|
-
|
378
349
|
return rule.serve.variation
|
379
350
|
end
|
380
351
|
end
|
@@ -383,14 +354,12 @@ class Evaluator < Evaluation
|
|
383
354
|
end
|
384
355
|
|
385
356
|
def evaluate_rule(serving_rule, target)
|
386
|
-
|
387
357
|
evaluate_clauses(serving_rule.clauses, target)
|
388
358
|
end
|
389
359
|
|
390
360
|
def evaluate_variation_map(variation_maps, target)
|
391
361
|
|
392
362
|
if target == nil
|
393
|
-
|
394
363
|
return nil
|
395
364
|
end
|
396
365
|
|
@@ -399,20 +368,15 @@ class Evaluator < Evaluation
|
|
399
368
|
targets = variation_map.targets
|
400
369
|
|
401
370
|
if targets != nil
|
402
|
-
|
403
371
|
found = nil
|
404
|
-
|
405
372
|
targets.each do |t|
|
406
|
-
|
407
373
|
if t.identifier != nil && t.identifier == target.identifier
|
408
|
-
|
409
374
|
found = t
|
410
375
|
break
|
411
376
|
end
|
412
377
|
end
|
413
378
|
|
414
379
|
if found != nil
|
415
|
-
|
416
380
|
return variation_map.variation
|
417
381
|
end
|
418
382
|
end
|
@@ -420,7 +384,6 @@ class Evaluator < Evaluation
|
|
420
384
|
segment_identifiers = variation_map.target_segments
|
421
385
|
|
422
386
|
if segment_identifiers != nil && is_target_included_or_excluded_in_segment(segment_identifiers, target)
|
423
|
-
|
424
387
|
return variation_map.variation
|
425
388
|
end
|
426
389
|
end
|
@@ -433,32 +396,26 @@ class Evaluator < Evaluation
|
|
433
396
|
variation = feature_config.off_variation
|
434
397
|
|
435
398
|
if feature_config.state == OpenapiClient::FeatureState::ON
|
436
|
-
|
437
399
|
variation = nil
|
438
400
|
|
439
401
|
if feature_config.variation_to_target_map != nil
|
440
|
-
|
441
402
|
variation = evaluate_variation_map(feature_config.variation_to_target_map, target)
|
442
403
|
end
|
443
404
|
|
444
405
|
if variation == nil
|
445
|
-
|
446
406
|
variation = evaluate_rules(feature_config.rules, target)
|
447
407
|
end
|
448
408
|
|
449
409
|
if variation == nil
|
450
|
-
|
451
410
|
variation = evaluate_distribution(feature_config.default_serve.distribution, target)
|
452
411
|
end
|
453
412
|
|
454
413
|
if variation == nil
|
455
|
-
|
456
414
|
variation = feature_config.default_serve.variation
|
457
415
|
end
|
458
416
|
end
|
459
417
|
|
460
418
|
if variation != nil
|
461
|
-
|
462
419
|
return find_variation(feature_config.variations, variation)
|
463
420
|
end
|
464
421
|
|
@@ -519,11 +476,8 @@ class Evaluator < Evaluation
|
|
519
476
|
def is_target_in_list(target, list_of_targets)
|
520
477
|
|
521
478
|
if list_of_targets != nil
|
522
|
-
|
523
479
|
list_of_targets.each do |included_target|
|
524
|
-
|
525
480
|
if included_target.identifier.include?(target.identifier)
|
526
|
-
|
527
481
|
return true
|
528
482
|
end
|
529
483
|
end
|
@@ -17,7 +17,11 @@ class MetricsProcessor < Closeable
|
|
17
17
|
|
18
18
|
def increment(key)
|
19
19
|
compute(key) do |old_value|
|
20
|
-
if old_value == nil;
|
20
|
+
if old_value == nil;
|
21
|
+
1
|
22
|
+
else
|
23
|
+
old_value + 1
|
24
|
+
end
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
@@ -39,7 +43,6 @@ class MetricsProcessor < Closeable
|
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
|
-
|
43
46
|
def init(connector, config, callback)
|
44
47
|
|
45
48
|
unless connector.kind_of?(Connector)
|
@@ -59,14 +62,12 @@ class MetricsProcessor < Closeable
|
|
59
62
|
@connector = connector
|
60
63
|
|
61
64
|
@sdk_type = "SDK_TYPE"
|
62
|
-
@global_target_set = Set[]
|
63
|
-
@staging_target_set = Set[]
|
64
65
|
@target_attribute = "target"
|
65
|
-
@
|
66
|
+
@global_target_identifier = "__global__cf_target" # <--- This target identifier is used to aggregate and send data for all
|
66
67
|
# targets as a summary
|
67
|
-
|
68
|
+
@global_target = Target.new("RubySDK1", identifier = @global_target_identifier, name = @global_target_name)
|
68
69
|
@ready = false
|
69
|
-
@jar_version =
|
70
|
+
@jar_version = Ff::Ruby::Server::Sdk::VERSION
|
70
71
|
@server = "server"
|
71
72
|
@sdk_version = "SDK_VERSION"
|
72
73
|
@sdk_language = "SDK_LANGUAGE"
|
@@ -76,10 +77,20 @@ class MetricsProcessor < Closeable
|
|
76
77
|
|
77
78
|
@executor = Concurrent::FixedThreadPool.new(10)
|
78
79
|
|
79
|
-
@
|
80
|
+
@evaluation_metrics = FrequencyMap.new
|
81
|
+
@target_metrics = Concurrent::Map.new
|
82
|
+
|
83
|
+
# Keep track of targets that have already been sent to avoid sending them again
|
84
|
+
@seen_targets = Concurrent::Map.new
|
80
85
|
|
81
86
|
@max_buffer_size = config.buffer_size - 1
|
82
87
|
|
88
|
+
# Max 100k targets per interval
|
89
|
+
@max_targets_buffer_size = 100000
|
90
|
+
|
91
|
+
@evaluation_warning_issued = Concurrent::AtomicBoolean.new
|
92
|
+
@target_warning_issued = Concurrent::AtomicBoolean.new
|
93
|
+
|
83
94
|
@callback.on_metrics_ready
|
84
95
|
end
|
85
96
|
|
@@ -99,30 +110,70 @@ class MetricsProcessor < Closeable
|
|
99
110
|
end
|
100
111
|
|
101
112
|
def register_evaluation(target, feature_config, variation)
|
113
|
+
register_evaluation_metric(feature_config, variation)
|
114
|
+
register_target_metric(target)
|
115
|
+
end
|
102
116
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
117
|
+
private
|
118
|
+
|
119
|
+
def register_evaluation_metric(feature_config, variation)
|
120
|
+
if @evaluation_metrics.size > @max_buffer_size
|
121
|
+
unless @evaluation_warning_issued.true?
|
122
|
+
SdkCodes.warn_metrics_evaluations_max_size_exceeded(@config.logger)
|
123
|
+
@evaluation_warning_issued.make_true
|
107
124
|
end
|
125
|
+
return
|
108
126
|
end
|
109
127
|
|
110
|
-
event = MetricsEvent.new(feature_config,
|
111
|
-
@
|
128
|
+
event = MetricsEvent.new(feature_config, @global_target, variation)
|
129
|
+
@evaluation_metrics.increment event
|
112
130
|
end
|
113
131
|
|
114
|
-
|
132
|
+
def register_target_metric(target)
|
133
|
+
if @target_metrics.size > @max_targets_buffer_size
|
134
|
+
unless @target_warning_issued.true?
|
135
|
+
SdkCodes.warn_metrics_targets_max_size_exceeded(@config.logger)
|
136
|
+
@target_warning_issued.make_true
|
137
|
+
end
|
138
|
+
return
|
139
|
+
end
|
140
|
+
|
141
|
+
if target.is_private
|
142
|
+
return
|
143
|
+
end
|
144
|
+
|
145
|
+
already_seen = @seen_targets.put_if_absent(target.identifier, true)
|
146
|
+
|
147
|
+
if already_seen
|
148
|
+
return
|
149
|
+
end
|
150
|
+
|
151
|
+
@target_metrics.put(target.identifier, target)
|
152
|
+
end
|
115
153
|
|
116
154
|
def run_one_iteration
|
117
|
-
send_data_and_reset_cache @
|
155
|
+
send_data_and_reset_cache(@evaluation_metrics, @target_metrics)
|
118
156
|
|
119
|
-
@config.logger.debug "metrics: frequency map size #{@
|
157
|
+
@config.logger.debug "metrics: frequency map size #{@evaluation_metrics.size}. targets map size #{@target_metrics.size} global target size #{@seen_targets.size}"
|
120
158
|
end
|
121
159
|
|
122
|
-
def send_data_and_reset_cache(
|
123
|
-
|
160
|
+
def send_data_and_reset_cache(evaluation_metrics_map, target_metrics_map)
|
161
|
+
evaluation_metrics_map_clone = evaluation_metrics_map.drain_to_map
|
162
|
+
|
163
|
+
target_metrics_map_clone = Concurrent::Map.new
|
164
|
+
|
165
|
+
target_metrics_map.each_pair do |key, value|
|
166
|
+
target_metrics_map_clone[key] = value
|
167
|
+
end
|
168
|
+
|
169
|
+
target_metrics_map.clear
|
170
|
+
|
171
|
+
@evaluation_warning_issued.make_false
|
172
|
+
@target_warning_issued.make_false
|
173
|
+
|
174
|
+
metrics = prepare_summary_metrics_body(evaluation_metrics_map_clone, target_metrics_map_clone)
|
124
175
|
|
125
|
-
|
176
|
+
unless metrics.metrics_data.empty?
|
126
177
|
start_time = (Time.now.to_f * 1000).to_i
|
127
178
|
@connector.post_metrics(metrics)
|
128
179
|
end_time = (Time.now.to_f * 1000).to_i
|
@@ -130,20 +181,13 @@ class MetricsProcessor < Closeable
|
|
130
181
|
@config.logger.debug "Metrics service API duration=[" + (end_time - start_time).to_s + "]"
|
131
182
|
end
|
132
183
|
end
|
133
|
-
|
134
|
-
@global_target_set.merge(@staging_target_set)
|
135
|
-
@staging_target_set.clear
|
136
|
-
|
137
184
|
end
|
138
185
|
|
139
|
-
def prepare_summary_metrics_body(
|
186
|
+
def prepare_summary_metrics_body(evaluation_metrics_map, target_metrics_map)
|
140
187
|
metrics = OpenapiClient::Metrics.new({ :target_data => [], :metrics_data => [] })
|
141
|
-
|
142
|
-
freq_map.each_key do |key|
|
143
|
-
add_target_data(metrics, key.target)
|
144
|
-
end
|
188
|
+
|
145
189
|
total_count = 0
|
146
|
-
|
190
|
+
evaluation_metrics_map.each do |key, value|
|
147
191
|
total_count += value
|
148
192
|
metrics_data = OpenapiClient::MetricsData.new({ :attributes => [] })
|
149
193
|
metrics_data.timestamp = (Time.now.to_f * 1000).to_i
|
@@ -151,13 +195,17 @@ class MetricsProcessor < Closeable
|
|
151
195
|
metrics_data.metrics_type = "FFMETRICS"
|
152
196
|
metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @feature_name_attribute, :value => key.feature_config.feature }))
|
153
197
|
metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @variation_identifier_attribute, :value => key.variation.identifier }))
|
154
|
-
metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @target_attribute, :value => @
|
198
|
+
metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @target_attribute, :value => @global_target_identifier }))
|
155
199
|
metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @sdk_type, :value => @server }))
|
156
200
|
metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @sdk_language, :value => "ruby" }))
|
157
201
|
metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @sdk_version, :value => @jar_version }))
|
158
202
|
metrics.metrics_data.push(metrics_data)
|
159
203
|
end
|
160
|
-
@config.logger.debug "Pushed #{total_count} metric evaluations to server. metrics_data count is #{
|
204
|
+
@config.logger.debug "Pushed #{total_count} metric evaluations to server. metrics_data count is #{evaluation_metrics_map.size}. target_data count is #{target_metrics_map.size}"
|
205
|
+
|
206
|
+
target_metrics_map.each_pair do |_, value|
|
207
|
+
add_target_data(metrics, value)
|
208
|
+
end
|
161
209
|
|
162
210
|
metrics
|
163
211
|
end
|
@@ -167,28 +215,25 @@ class MetricsProcessor < Closeable
|
|
167
215
|
target_data = OpenapiClient::TargetData.new({ :attributes => [] })
|
168
216
|
private_attributes = target.private_attributes
|
169
217
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
if !private_attributes.empty?
|
176
|
-
unless private_attributes.include?(k)
|
177
|
-
key_value = OpenapiClient::KeyValue.new({ :key => k, :value => v.to_s })
|
178
|
-
end
|
179
|
-
else
|
218
|
+
attributes = target.attributes
|
219
|
+
attributes.each do |k, v|
|
220
|
+
key_value = OpenapiClient::KeyValue.new
|
221
|
+
if !private_attributes.empty?
|
222
|
+
unless private_attributes.include?(k)
|
180
223
|
key_value = OpenapiClient::KeyValue.new({ :key => k, :value => v.to_s })
|
181
224
|
end
|
182
|
-
target_data.attributes.push(key_value)
|
183
|
-
end
|
184
|
-
target_data.identifier = target.identifier
|
185
|
-
if target.name == nil || target.name == ""
|
186
|
-
target_data.name = target.identifier
|
187
225
|
else
|
188
|
-
|
226
|
+
key_value = OpenapiClient::KeyValue.new({ :key => k, :value => v.to_s })
|
189
227
|
end
|
190
|
-
|
228
|
+
target_data.attributes.push(key_value)
|
229
|
+
end
|
230
|
+
target_data.identifier = target.identifier
|
231
|
+
if target.name == nil || target.name == ""
|
232
|
+
target_data.name = target.identifier
|
233
|
+
else
|
234
|
+
target_data.name = target.name
|
191
235
|
end
|
236
|
+
metrics.target_data.push(target_data)
|
192
237
|
end
|
193
238
|
|
194
239
|
def start_async
|
@@ -218,7 +263,7 @@ class MetricsProcessor < Closeable
|
|
218
263
|
end
|
219
264
|
|
220
265
|
def get_frequency_map
|
221
|
-
@
|
266
|
+
@evaluation_metrics
|
222
267
|
end
|
223
268
|
|
224
269
|
end
|
@@ -107,6 +107,7 @@ class StorageRepository < Repository
|
|
107
107
|
return
|
108
108
|
end
|
109
109
|
|
110
|
+
sort_flag_rules(feature_config)
|
110
111
|
flag_key = format_flag_key(identifier)
|
111
112
|
|
112
113
|
if @store != nil
|
@@ -141,6 +142,7 @@ class StorageRepository < Repository
|
|
141
142
|
return
|
142
143
|
end
|
143
144
|
|
145
|
+
sort_segment_serving_rules(segment)
|
144
146
|
segment_key = format_segment_key(identifier)
|
145
147
|
|
146
148
|
if @store != nil
|
@@ -240,6 +242,18 @@ class StorageRepository < Repository
|
|
240
242
|
false
|
241
243
|
end
|
242
244
|
|
245
|
+
def sort_flag_rules(flag)
|
246
|
+
if flag.rules && flag.rules.length > 1
|
247
|
+
flag.rules.sort_by!(&:priority)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def sort_segment_serving_rules(segment)
|
252
|
+
if segment.serving_rules && segment.serving_rules.length > 1
|
253
|
+
segment.serving_rules.sort_by!(&:priority)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
243
257
|
def is_segment_outdated(identifier, new_segment)
|
244
258
|
|
245
259
|
segment = get_segment(identifier, false)
|
@@ -34,6 +34,13 @@ class SdkCodes
|
|
34
34
|
logger.info SdkCodes.sdk_err_msg(7000)
|
35
35
|
end
|
36
36
|
|
37
|
+
def self.warn_metrics_targets_max_size_exceeded(logger)
|
38
|
+
logger.warn SdkCodes.sdk_err_msg(7004)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.warn_metrics_evaluations_max_size_exceeded(logger)
|
42
|
+
logger.warn SdkCodes.sdk_err_msg(7007)
|
43
|
+
end
|
37
44
|
def self.warn_auth_failed_srv_defaults(logger)
|
38
45
|
logger.warn SdkCodes.sdk_err_msg(2001)
|
39
46
|
end
|
@@ -89,6 +96,8 @@ class SdkCodes
|
|
89
96
|
7000 => "Metrics thread started",
|
90
97
|
7001 => "Metrics thread exited",
|
91
98
|
7002 => "Posting metrics failed, reason:",
|
99
|
+
7004 => "Target metrics exceeded max size, remaining targets for this analytics interval will not be sent",
|
100
|
+
7007 => "Evaluation metrics exceeded max size, remaining evaluations for this analytics interval will not be sent"
|
92
101
|
}
|
93
102
|
|
94
103
|
def self.sdk_err_msg(error_code, append_text = "")
|