launchdarkly-server-sdk 6.3.1 → 6.3.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 +4 -4
- data/README.md +1 -2
- data/lib/ldclient-rb/config.rb +17 -0
- data/lib/ldclient-rb/events.rb +201 -107
- data/lib/ldclient-rb/flags_state.rb +23 -12
- data/lib/ldclient-rb/impl/evaluator.rb +18 -13
- data/lib/ldclient-rb/impl/evaluator_operators.rb +1 -1
- data/lib/ldclient-rb/impl/event_summarizer.rb +63 -0
- data/lib/ldclient-rb/impl/event_types.rb +90 -0
- data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +1 -1
- data/lib/ldclient-rb/integrations/consul.rb +1 -1
- data/lib/ldclient-rb/integrations/dynamodb.rb +1 -1
- data/lib/ldclient-rb/integrations/redis.rb +1 -1
- data/lib/ldclient-rb/ldclient.rb +106 -28
- data/lib/ldclient-rb/stream.rb +2 -1
- data/lib/ldclient-rb/util.rb +9 -0
- data/lib/ldclient-rb/version.rb +1 -1
- data/lib/ldclient-rb.rb +0 -1
- metadata +9 -9
- data/lib/ldclient-rb/event_summarizer.rb +0 -55
- data/lib/ldclient-rb/impl/event_factory.rb +0 -126
@@ -0,0 +1,63 @@
|
|
1
|
+
require "ldclient-rb/impl/event_types"
|
2
|
+
|
3
|
+
module LaunchDarkly
|
4
|
+
module Impl
|
5
|
+
EventSummary = Struct.new(:start_date, :end_date, :counters)
|
6
|
+
|
7
|
+
EventSummaryFlagInfo = Struct.new(:default, :versions)
|
8
|
+
|
9
|
+
EventSummaryFlagVariationCounter = Struct.new(:value, :count)
|
10
|
+
|
11
|
+
# Manages the state of summarizable information for the EventProcessor, including the
|
12
|
+
# event counters and user deduplication. Note that the methods of this class are
|
13
|
+
# deliberately not thread-safe; the EventProcessor is responsible for enforcing
|
14
|
+
# synchronization across both the summarizer and the event queue.
|
15
|
+
class EventSummarizer
|
16
|
+
class Counter
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
clear
|
21
|
+
end
|
22
|
+
|
23
|
+
# Adds this event to our counters, if it is a type of event we need to count.
|
24
|
+
def summarize_event(event)
|
25
|
+
return if !event.is_a?(LaunchDarkly::Impl::EvalEvent)
|
26
|
+
|
27
|
+
counters_for_flag = @counters[event.key]
|
28
|
+
if counters_for_flag.nil?
|
29
|
+
counters_for_flag = EventSummaryFlagInfo.new(event.default, Hash.new)
|
30
|
+
@counters[event.key] = counters_for_flag
|
31
|
+
end
|
32
|
+
counters_for_flag_version = counters_for_flag.versions[event.version]
|
33
|
+
if counters_for_flag_version.nil?
|
34
|
+
counters_for_flag_version = Hash.new
|
35
|
+
counters_for_flag.versions[event.version] = counters_for_flag_version
|
36
|
+
end
|
37
|
+
variation_counter = counters_for_flag_version[event.variation]
|
38
|
+
if variation_counter.nil?
|
39
|
+
counters_for_flag_version[event.variation] = EventSummaryFlagVariationCounter.new(event.value, 1)
|
40
|
+
else
|
41
|
+
variation_counter.count = variation_counter.count + 1
|
42
|
+
end
|
43
|
+
time = event.timestamp
|
44
|
+
if !time.nil?
|
45
|
+
@start_date = time if @start_date == 0 || time < @start_date
|
46
|
+
@end_date = time if time > @end_date
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns a snapshot of the current summarized event data, and resets this state.
|
51
|
+
def snapshot
|
52
|
+
ret = EventSummary.new(@start_date, @end_date, @counters)
|
53
|
+
ret
|
54
|
+
end
|
55
|
+
|
56
|
+
def clear
|
57
|
+
@start_date = 0
|
58
|
+
@end_date = 0
|
59
|
+
@counters = {}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module LaunchDarkly
|
2
|
+
module Impl
|
3
|
+
class Event
|
4
|
+
def initialize(timestamp, user)
|
5
|
+
@timestamp = timestamp
|
6
|
+
@user = user
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :timestamp
|
10
|
+
attr_reader :kind
|
11
|
+
attr_reader :user
|
12
|
+
end
|
13
|
+
|
14
|
+
class EvalEvent < Event
|
15
|
+
def initialize(timestamp, user, key, version = nil, variation = nil, value = nil, reason = nil, default = nil,
|
16
|
+
track_events = false, debug_until = nil, prereq_of = nil)
|
17
|
+
super(timestamp, user)
|
18
|
+
@key = key
|
19
|
+
@version = version
|
20
|
+
@variation = variation
|
21
|
+
@value = value
|
22
|
+
@reason = reason
|
23
|
+
@default = default
|
24
|
+
# avoid setting rarely-used attributes if they have no value - this saves a little space per instance
|
25
|
+
@track_events = track_events if track_events
|
26
|
+
@debug_until = debug_until if debug_until
|
27
|
+
@prereq_of = prereq_of if prereq_of
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :key
|
31
|
+
attr_reader :version
|
32
|
+
attr_reader :variation
|
33
|
+
attr_reader :value
|
34
|
+
attr_reader :reason
|
35
|
+
attr_reader :default
|
36
|
+
attr_reader :track_events
|
37
|
+
attr_reader :debug_until
|
38
|
+
attr_reader :prereq_of
|
39
|
+
end
|
40
|
+
|
41
|
+
class IdentifyEvent < Event
|
42
|
+
def initialize(timestamp, user)
|
43
|
+
super(timestamp, user)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class CustomEvent < Event
|
48
|
+
def initialize(timestamp, user, key, data = nil, metric_value = nil)
|
49
|
+
super(timestamp, user)
|
50
|
+
@key = key
|
51
|
+
@data = data if !data.nil?
|
52
|
+
@metric_value = metric_value if !metric_value.nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_reader :key
|
56
|
+
attr_reader :data
|
57
|
+
attr_reader :metric_value
|
58
|
+
end
|
59
|
+
|
60
|
+
class AliasEvent < Event
|
61
|
+
def initialize(timestamp, key, context_kind, previous_key, previous_context_kind)
|
62
|
+
super(timestamp, nil)
|
63
|
+
@key = key
|
64
|
+
@context_kind = context_kind
|
65
|
+
@previous_key = previous_key
|
66
|
+
@previous_context_kind = previous_context_kind
|
67
|
+
end
|
68
|
+
|
69
|
+
attr_reader :key
|
70
|
+
attr_reader :context_kind
|
71
|
+
attr_reader :previous_key
|
72
|
+
attr_reader :previous_context_kind
|
73
|
+
end
|
74
|
+
|
75
|
+
class IndexEvent < Event
|
76
|
+
def initialize(timestamp, user)
|
77
|
+
super(timestamp, user)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class DebugEvent < Event
|
82
|
+
def initialize(eval_event)
|
83
|
+
super(eval_event.timestamp, eval_event.user)
|
84
|
+
@eval_event = eval_event
|
85
|
+
end
|
86
|
+
|
87
|
+
attr_reader :eval_event
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -35,7 +35,7 @@ module LaunchDarkly
|
|
35
35
|
@client = Aws::DynamoDB::Client.new(opts[:dynamodb_opts] || {})
|
36
36
|
end
|
37
37
|
|
38
|
-
@logger.info("
|
38
|
+
@logger.info("#{description}: using DynamoDB table \"#{table_name}\"")
|
39
39
|
end
|
40
40
|
|
41
41
|
def stop
|
@@ -36,7 +36,7 @@ module LaunchDarkly
|
|
36
36
|
# @option opts [Integer] :capacity (1000) maximum number of items in the cache
|
37
37
|
# @return [LaunchDarkly::Interfaces::FeatureStore] a feature store object
|
38
38
|
#
|
39
|
-
def self.new_feature_store(opts
|
39
|
+
def self.new_feature_store(opts = {})
|
40
40
|
core = LaunchDarkly::Impl::Integrations::Consul::ConsulFeatureStoreCore.new(opts)
|
41
41
|
return LaunchDarkly::Integrations::Util::CachingStoreWrapper.new(core, opts)
|
42
42
|
end
|
@@ -46,7 +46,7 @@ module LaunchDarkly
|
|
46
46
|
# @option opts [Integer] :capacity (1000) maximum number of items in the cache
|
47
47
|
# @return [LaunchDarkly::Interfaces::FeatureStore] a feature store object
|
48
48
|
#
|
49
|
-
def self.new_feature_store(table_name, opts)
|
49
|
+
def self.new_feature_store(table_name, opts = {})
|
50
50
|
core = LaunchDarkly::Impl::Integrations::DynamoDB::DynamoDBFeatureStoreCore.new(table_name, opts)
|
51
51
|
LaunchDarkly::Integrations::Util::CachingStoreWrapper.new(core, opts)
|
52
52
|
end
|
@@ -58,7 +58,7 @@ module LaunchDarkly
|
|
58
58
|
# lifecycle to be independent of the SDK client
|
59
59
|
# @return [LaunchDarkly::Interfaces::FeatureStore] a feature store object
|
60
60
|
#
|
61
|
-
def self.new_feature_store(opts)
|
61
|
+
def self.new_feature_store(opts = {})
|
62
62
|
return RedisFeatureStore.new(opts)
|
63
63
|
end
|
64
64
|
|
data/lib/ldclient-rb/ldclient.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require "ldclient-rb/impl/big_segments"
|
2
2
|
require "ldclient-rb/impl/diagnostic_events"
|
3
3
|
require "ldclient-rb/impl/evaluator"
|
4
|
-
require "ldclient-rb/impl/event_factory"
|
5
4
|
require "ldclient-rb/impl/store_client_wrapper"
|
6
5
|
require "concurrent/atomics"
|
7
6
|
require "digest/sha1"
|
@@ -46,9 +45,6 @@ module LaunchDarkly
|
|
46
45
|
|
47
46
|
@sdk_key = sdk_key
|
48
47
|
|
49
|
-
@event_factory_default = EventFactory.new(false)
|
50
|
-
@event_factory_with_reasons = EventFactory.new(true)
|
51
|
-
|
52
48
|
# We need to wrap the feature store object with a FeatureStoreClientWrapper in order to add
|
53
49
|
# some necessary logic around updates. Unfortunately, we have code elsewhere that accesses
|
54
50
|
# the feature store through the Config object, so we need to make a new Config that uses
|
@@ -65,7 +61,7 @@ module LaunchDarkly
|
|
65
61
|
get_segment = lambda { |key| @store.get(SEGMENTS, key) }
|
66
62
|
get_big_segments_membership = lambda { |key| @big_segment_store_manager.get_user_membership(key) }
|
67
63
|
@evaluator = LaunchDarkly::Impl::Evaluator.new(get_flag, get_segment, get_big_segments_membership, @config.logger)
|
68
|
-
|
64
|
+
|
69
65
|
if !@config.offline? && @config.send_events && !@config.diagnostic_opt_out?
|
70
66
|
diagnostic_accumulator = Impl::DiagnosticAccumulator.new(Impl::DiagnosticAccumulator.create_diagnostic_id(sdk_key))
|
71
67
|
else
|
@@ -178,7 +174,7 @@ module LaunchDarkly
|
|
178
174
|
# Other supported user attributes include IP address, country code, and an arbitrary hash of
|
179
175
|
# custom attributes. For more about the supported user properties and how they work in
|
180
176
|
# LaunchDarkly, see [Targeting users](https://docs.launchdarkly.com/home/flags/targeting-users).
|
181
|
-
#
|
177
|
+
#
|
182
178
|
# The optional `:privateAttributeNames` user property allows you to specify a list of
|
183
179
|
# attribute names that should not be sent back to LaunchDarkly.
|
184
180
|
# [Private attributes](https://docs.launchdarkly.com/home/users/attributes#creating-private-user-attributes)
|
@@ -202,7 +198,7 @@ module LaunchDarkly
|
|
202
198
|
# @return the variation to show the user, or the default value if there's an an error
|
203
199
|
#
|
204
200
|
def variation(key, user, default)
|
205
|
-
evaluate_internal(key, user, default,
|
201
|
+
evaluate_internal(key, user, default, false).value
|
206
202
|
end
|
207
203
|
|
208
204
|
#
|
@@ -229,7 +225,7 @@ module LaunchDarkly
|
|
229
225
|
# @return [EvaluationDetail] an object describing the result
|
230
226
|
#
|
231
227
|
def variation_detail(key, user, default)
|
232
|
-
evaluate_internal(key, user, default,
|
228
|
+
evaluate_internal(key, user, default, true)
|
233
229
|
end
|
234
230
|
|
235
231
|
#
|
@@ -248,12 +244,12 @@ module LaunchDarkly
|
|
248
244
|
# @return [void]
|
249
245
|
#
|
250
246
|
def identify(user)
|
251
|
-
if !user || user[:key].nil?
|
252
|
-
@config.logger.warn("Identify called with nil user or
|
247
|
+
if !user || user[:key].nil? || user[:key].empty?
|
248
|
+
@config.logger.warn("Identify called with nil user or empty user key!")
|
253
249
|
return
|
254
250
|
end
|
255
251
|
sanitize_user(user)
|
256
|
-
@event_processor.
|
252
|
+
@event_processor.record_identify_event(user)
|
257
253
|
end
|
258
254
|
|
259
255
|
#
|
@@ -284,7 +280,7 @@ module LaunchDarkly
|
|
284
280
|
return
|
285
281
|
end
|
286
282
|
sanitize_user(user)
|
287
|
-
@event_processor.
|
283
|
+
@event_processor.record_custom_event(user, event_name, data, metric_value)
|
288
284
|
end
|
289
285
|
|
290
286
|
#
|
@@ -301,7 +297,7 @@ module LaunchDarkly
|
|
301
297
|
end
|
302
298
|
sanitize_user(current_context)
|
303
299
|
sanitize_user(previous_context)
|
304
|
-
@event_processor.
|
300
|
+
@event_processor.record_alias_event(current_context, previous_context)
|
305
301
|
end
|
306
302
|
|
307
303
|
#
|
@@ -338,6 +334,15 @@ module LaunchDarkly
|
|
338
334
|
def all_flags_state(user, options={})
|
339
335
|
return FeatureFlagsState.new(false) if @config.offline?
|
340
336
|
|
337
|
+
if !initialized?
|
338
|
+
if @store.initialized?
|
339
|
+
@config.logger.warn { "Called all_flags_state before client initialization; using last known values from data store" }
|
340
|
+
else
|
341
|
+
@config.logger.warn { "Called all_flags_state before client initialization. Data store not available; returning empty state" }
|
342
|
+
return FeatureFlagsState.new(false)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
341
346
|
unless user && !user[:key].nil?
|
342
347
|
@config.logger.error { "[LDClient] User and user key must be specified in all_flags_state" }
|
343
348
|
return FeatureFlagsState.new(false)
|
@@ -359,14 +364,25 @@ module LaunchDarkly
|
|
359
364
|
next
|
360
365
|
end
|
361
366
|
begin
|
362
|
-
|
363
|
-
state.add_flag(f, result.detail.value, result.detail.variation_index, with_reasons ? result.detail.reason : nil,
|
364
|
-
details_only_if_tracked)
|
367
|
+
detail = @evaluator.evaluate(f, user).detail
|
365
368
|
rescue => exn
|
369
|
+
detail = EvaluationDetail.new(nil, nil, EvaluationReason::error(EvaluationReason::ERROR_EXCEPTION))
|
366
370
|
Util.log_exception(@config.logger, "Error evaluating flag \"#{k}\" in all_flags_state", exn)
|
367
|
-
state.add_flag(f, nil, nil, with_reasons ? EvaluationReason::error(EvaluationReason::ERROR_EXCEPTION) : nil,
|
368
|
-
details_only_if_tracked)
|
369
371
|
end
|
372
|
+
|
373
|
+
requires_experiment_data = is_experiment(f, detail.reason)
|
374
|
+
flag_state = {
|
375
|
+
key: f[:key],
|
376
|
+
value: detail.value,
|
377
|
+
variation: detail.variation_index,
|
378
|
+
reason: detail.reason,
|
379
|
+
version: f[:version],
|
380
|
+
trackEvents: f[:trackEvents] || requires_experiment_data,
|
381
|
+
trackReason: requires_experiment_data,
|
382
|
+
debugEventsUntilDate: f[:debugEventsUntilDate],
|
383
|
+
}
|
384
|
+
|
385
|
+
state.add_flag(flag_state, with_reasons, details_only_if_tracked)
|
370
386
|
end
|
371
387
|
|
372
388
|
state
|
@@ -410,7 +426,7 @@ module LaunchDarkly
|
|
410
426
|
end
|
411
427
|
|
412
428
|
# @return [EvaluationDetail]
|
413
|
-
def evaluate_internal(key, user, default,
|
429
|
+
def evaluate_internal(key, user, default, with_reasons)
|
414
430
|
if @config.offline?
|
415
431
|
return Evaluator.error_result(EvaluationReason::ERROR_CLIENT_NOT_READY, default)
|
416
432
|
end
|
@@ -433,7 +449,7 @@ module LaunchDarkly
|
|
433
449
|
else
|
434
450
|
@config.logger.error { "[LDClient] Client has not finished initializing; feature store unavailable, returning default value" }
|
435
451
|
detail = Evaluator.error_result(EvaluationReason::ERROR_CLIENT_NOT_READY, default)
|
436
|
-
|
452
|
+
record_unknown_flag_eval(key, user, default, detail.reason, with_reasons)
|
437
453
|
return detail
|
438
454
|
end
|
439
455
|
end
|
@@ -443,32 +459,94 @@ module LaunchDarkly
|
|
443
459
|
if feature.nil?
|
444
460
|
@config.logger.info { "[LDClient] Unknown feature flag \"#{key}\". Returning default value" }
|
445
461
|
detail = Evaluator.error_result(EvaluationReason::ERROR_FLAG_NOT_FOUND, default)
|
446
|
-
|
462
|
+
record_unknown_flag_eval(key, user, default, detail.reason, with_reasons)
|
447
463
|
return detail
|
448
464
|
end
|
449
465
|
|
450
466
|
begin
|
451
|
-
res = @evaluator.evaluate(feature, user
|
452
|
-
if !res.
|
453
|
-
res.
|
454
|
-
|
467
|
+
res = @evaluator.evaluate(feature, user)
|
468
|
+
if !res.prereq_evals.nil?
|
469
|
+
res.prereq_evals.each do |prereq_eval|
|
470
|
+
record_prereq_flag_eval(prereq_eval.prereq_flag, prereq_eval.prereq_of_flag, user, prereq_eval.detail, with_reasons)
|
455
471
|
end
|
456
472
|
end
|
457
473
|
detail = res.detail
|
458
474
|
if detail.default_value?
|
459
475
|
detail = EvaluationDetail.new(default, nil, detail.reason)
|
460
476
|
end
|
461
|
-
|
477
|
+
record_flag_eval(feature, user, detail, default, with_reasons)
|
462
478
|
return detail
|
463
479
|
rescue => exn
|
464
480
|
Util.log_exception(@config.logger, "Error evaluating feature flag \"#{key}\"", exn)
|
465
481
|
detail = Evaluator.error_result(EvaluationReason::ERROR_EXCEPTION, default)
|
466
|
-
|
482
|
+
record_flag_eval_error(feature, user, default, detail.reason, with_reasons)
|
467
483
|
return detail
|
468
484
|
end
|
469
485
|
end
|
470
486
|
|
471
|
-
def
|
487
|
+
private def record_flag_eval(flag, user, detail, default, with_reasons)
|
488
|
+
add_experiment_data = is_experiment(flag, detail.reason)
|
489
|
+
@event_processor.record_eval_event(
|
490
|
+
user,
|
491
|
+
flag[:key],
|
492
|
+
flag[:version],
|
493
|
+
detail.variation_index,
|
494
|
+
detail.value,
|
495
|
+
(add_experiment_data || with_reasons) ? detail.reason : nil,
|
496
|
+
default,
|
497
|
+
add_experiment_data || flag[:trackEvents] || false,
|
498
|
+
flag[:debugEventsUntilDate],
|
499
|
+
nil
|
500
|
+
)
|
501
|
+
end
|
502
|
+
|
503
|
+
private def record_prereq_flag_eval(prereq_flag, prereq_of_flag, user, detail, with_reasons)
|
504
|
+
add_experiment_data = is_experiment(prereq_flag, detail.reason)
|
505
|
+
@event_processor.record_eval_event(
|
506
|
+
user,
|
507
|
+
prereq_flag[:key],
|
508
|
+
prereq_flag[:version],
|
509
|
+
detail.variation_index,
|
510
|
+
detail.value,
|
511
|
+
(add_experiment_data || with_reasons) ? detail.reason : nil,
|
512
|
+
nil,
|
513
|
+
add_experiment_data || prereq_flag[:trackEvents] || false,
|
514
|
+
prereq_flag[:debugEventsUntilDate],
|
515
|
+
prereq_of_flag[:key]
|
516
|
+
)
|
517
|
+
end
|
518
|
+
|
519
|
+
private def record_flag_eval_error(flag, user, default, reason, with_reasons)
|
520
|
+
@event_processor.record_eval_event(user, flag[:key], flag[:version], nil, default, with_reasons ? reason : nil, default,
|
521
|
+
flag[:trackEvents], flag[:debugEventsUntilDate], nil)
|
522
|
+
end
|
523
|
+
|
524
|
+
private def record_unknown_flag_eval(flag_key, user, default, reason, with_reasons)
|
525
|
+
@event_processor.record_eval_event(user, flag_key, nil, nil, default, with_reasons ? reason : nil, default,
|
526
|
+
false, nil, nil)
|
527
|
+
end
|
528
|
+
|
529
|
+
private def is_experiment(flag, reason)
|
530
|
+
return false if !reason
|
531
|
+
|
532
|
+
if reason.in_experiment
|
533
|
+
return true
|
534
|
+
end
|
535
|
+
|
536
|
+
case reason[:kind]
|
537
|
+
when 'RULE_MATCH'
|
538
|
+
index = reason[:ruleIndex]
|
539
|
+
if !index.nil?
|
540
|
+
rules = flag[:rules] || []
|
541
|
+
return index >= 0 && index < rules.length && rules[index][:trackEvents]
|
542
|
+
end
|
543
|
+
when 'FALLTHROUGH'
|
544
|
+
return !!flag[:trackEventsFallthrough]
|
545
|
+
end
|
546
|
+
false
|
547
|
+
end
|
548
|
+
|
549
|
+
private def sanitize_user(user)
|
472
550
|
if user[:key]
|
473
551
|
user[:key] = user[:key].to_s
|
474
552
|
end
|
data/lib/ldclient-rb/stream.rb
CHANGED
@@ -47,7 +47,8 @@ module LaunchDarkly
|
|
47
47
|
headers: headers,
|
48
48
|
read_timeout: READ_TIMEOUT_SECONDS,
|
49
49
|
logger: @config.logger,
|
50
|
-
socket_factory: @config.socket_factory
|
50
|
+
socket_factory: @config.socket_factory,
|
51
|
+
reconnect_time: @config.initial_reconnect_delay
|
51
52
|
}
|
52
53
|
log_connection_started
|
53
54
|
@es = SSE::Client.new(@config.stream_uri + "/all", **opts) do |conn|
|
data/lib/ldclient-rb/util.rb
CHANGED
@@ -24,6 +24,15 @@ module LaunchDarkly
|
|
24
24
|
if config.socket_factory
|
25
25
|
http_client_options["socket_class"] = config.socket_factory
|
26
26
|
end
|
27
|
+
proxy = URI.parse(uri_s).find_proxy
|
28
|
+
if !proxy.nil?
|
29
|
+
http_client_options["proxy"] = {
|
30
|
+
proxy_address: proxy.host,
|
31
|
+
proxy_port: proxy.port,
|
32
|
+
proxy_username: proxy.user,
|
33
|
+
proxy_password: proxy.password
|
34
|
+
}
|
35
|
+
end
|
27
36
|
return HTTP::Client.new(http_client_options)
|
28
37
|
.timeout({
|
29
38
|
read: config.read_timeout,
|
data/lib/ldclient-rb/version.rb
CHANGED
data/lib/ldclient-rb.rb
CHANGED
@@ -21,7 +21,6 @@ require "ldclient-rb/polling"
|
|
21
21
|
require "ldclient-rb/user_filter"
|
22
22
|
require "ldclient-rb/simple_lru_cache"
|
23
23
|
require "ldclient-rb/non_blocking_thread_pool"
|
24
|
-
require "ldclient-rb/event_summarizer"
|
25
24
|
require "ldclient-rb/events"
|
26
25
|
require "ldclient-rb/requestor"
|
27
26
|
require "ldclient-rb/file_data_source"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: launchdarkly-server-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.3.
|
4
|
+
version: 6.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- LaunchDarkly
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-dynamodb
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.2.
|
33
|
+
version: 2.2.33
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 2.2.
|
40
|
+
version: 2.2.33
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -198,14 +198,14 @@ dependencies:
|
|
198
198
|
requirements:
|
199
199
|
- - '='
|
200
200
|
- !ruby/object:Gem::Version
|
201
|
-
version: 2.2.
|
201
|
+
version: 2.2.1
|
202
202
|
type: :runtime
|
203
203
|
prerelease: false
|
204
204
|
version_requirements: !ruby/object:Gem::Requirement
|
205
205
|
requirements:
|
206
206
|
- - '='
|
207
207
|
- !ruby/object:Gem::Version
|
208
|
-
version: 2.2.
|
208
|
+
version: 2.2.1
|
209
209
|
- !ruby/object:Gem::Dependency
|
210
210
|
name: json
|
211
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,7 +254,6 @@ files:
|
|
254
254
|
- lib/ldclient-rb/cache_store.rb
|
255
255
|
- lib/ldclient-rb/config.rb
|
256
256
|
- lib/ldclient-rb/evaluation_detail.rb
|
257
|
-
- lib/ldclient-rb/event_summarizer.rb
|
258
257
|
- lib/ldclient-rb/events.rb
|
259
258
|
- lib/ldclient-rb/expiring_cache.rb
|
260
259
|
- lib/ldclient-rb/file_data_source.rb
|
@@ -265,8 +264,9 @@ files:
|
|
265
264
|
- lib/ldclient-rb/impl/evaluator.rb
|
266
265
|
- lib/ldclient-rb/impl/evaluator_bucketing.rb
|
267
266
|
- lib/ldclient-rb/impl/evaluator_operators.rb
|
268
|
-
- lib/ldclient-rb/impl/event_factory.rb
|
269
267
|
- lib/ldclient-rb/impl/event_sender.rb
|
268
|
+
- lib/ldclient-rb/impl/event_summarizer.rb
|
269
|
+
- lib/ldclient-rb/impl/event_types.rb
|
270
270
|
- lib/ldclient-rb/impl/integrations/consul_impl.rb
|
271
271
|
- lib/ldclient-rb/impl/integrations/dynamodb_impl.rb
|
272
272
|
- lib/ldclient-rb/impl/integrations/file_data_source.rb
|
@@ -319,7 +319,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
319
319
|
- !ruby/object:Gem::Version
|
320
320
|
version: '0'
|
321
321
|
requirements: []
|
322
|
-
rubygems_version: 3.3.
|
322
|
+
rubygems_version: 3.3.17
|
323
323
|
signing_key:
|
324
324
|
specification_version: 4
|
325
325
|
summary: LaunchDarkly SDK for Ruby
|
@@ -1,55 +0,0 @@
|
|
1
|
-
|
2
|
-
module LaunchDarkly
|
3
|
-
# @private
|
4
|
-
EventSummary = Struct.new(:start_date, :end_date, :counters)
|
5
|
-
|
6
|
-
# Manages the state of summarizable information for the EventProcessor, including the
|
7
|
-
# event counters and user deduplication. Note that the methods of this class are
|
8
|
-
# deliberately not thread-safe; the EventProcessor is responsible for enforcing
|
9
|
-
# synchronization across both the summarizer and the event queue.
|
10
|
-
#
|
11
|
-
# @private
|
12
|
-
class EventSummarizer
|
13
|
-
def initialize
|
14
|
-
clear
|
15
|
-
end
|
16
|
-
|
17
|
-
# Adds this event to our counters, if it is a type of event we need to count.
|
18
|
-
def summarize_event(event)
|
19
|
-
if event[:kind] == "feature"
|
20
|
-
counter_key = {
|
21
|
-
key: event[:key],
|
22
|
-
version: event[:version],
|
23
|
-
variation: event[:variation]
|
24
|
-
}
|
25
|
-
c = @counters[counter_key]
|
26
|
-
if c.nil?
|
27
|
-
@counters[counter_key] = {
|
28
|
-
value: event[:value],
|
29
|
-
default: event[:default],
|
30
|
-
count: 1
|
31
|
-
}
|
32
|
-
else
|
33
|
-
c[:count] = c[:count] + 1
|
34
|
-
end
|
35
|
-
time = event[:creationDate]
|
36
|
-
if !time.nil?
|
37
|
-
@start_date = time if @start_date == 0 || time < @start_date
|
38
|
-
@end_date = time if time > @end_date
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# Returns a snapshot of the current summarized event data, and resets this state.
|
44
|
-
def snapshot
|
45
|
-
ret = EventSummary.new(@start_date, @end_date, @counters)
|
46
|
-
ret
|
47
|
-
end
|
48
|
-
|
49
|
-
def clear
|
50
|
-
@start_date = 0
|
51
|
-
@end_date = 0
|
52
|
-
@counters = {}
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|