launchdarkly-server-sdk 7.2.0 → 8.0.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/README.md +2 -2
- data/lib/ldclient-rb/config.rb +4 -69
- data/lib/ldclient-rb/context.rb +2 -45
- data/lib/ldclient-rb/evaluation_detail.rb +5 -1
- data/lib/ldclient-rb/events.rb +78 -7
- data/lib/ldclient-rb/impl/big_segments.rb +1 -1
- data/lib/ldclient-rb/impl/context.rb +3 -3
- data/lib/ldclient-rb/impl/event_sender.rb +1 -0
- data/lib/ldclient-rb/impl/event_types.rb +61 -3
- data/lib/ldclient-rb/impl/integrations/file_data_source.rb +1 -0
- data/lib/ldclient-rb/impl/integrations/redis_impl.rb +2 -1
- data/lib/ldclient-rb/impl/migrations/migrator.rb +287 -0
- data/lib/ldclient-rb/impl/migrations/tracker.rb +136 -0
- data/lib/ldclient-rb/impl/model/feature_flag.rb +23 -0
- data/lib/ldclient-rb/impl/sampler.rb +25 -0
- data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +84 -15
- data/lib/ldclient-rb/integrations/test_data.rb +3 -3
- data/lib/ldclient-rb/interfaces.rb +97 -0
- data/lib/ldclient-rb/ldclient.rb +106 -16
- data/lib/ldclient-rb/migrations.rb +230 -0
- data/lib/ldclient-rb/util.rb +63 -0
- data/lib/ldclient-rb/version.rb +1 -1
- data/lib/ldclient-rb.rb +1 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdb1eeb75ade6b2f82e1271c763f74ae577da09510e585b7cc1076ae9ff594d7
|
4
|
+
data.tar.gz: 8f794b216dff21125547319781efc2d77ce1632af6faccd8fa3c7fd96e2c8216
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ad1349bf430c6bb3a821d033f11106883c25d68aadc10bd622809b4c6dfe04e55ada3b9a49b8c92588389a4b3fb2112b1fd4fb63cdedf264cd3a0cc0bc0ac26
|
7
|
+
data.tar.gz: 6a605bd4f7ea9c7af3454e9a70bf5b3db1057456e5fc96249c807a706b0ca2fa8f0d3bd1238dae7e2fa5778ffe5d3b8728c9085499df0d952f76b3e41dcfa7a7
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ LaunchDarkly Server-side SDK for Ruby
|
|
9
9
|
|
10
10
|
LaunchDarkly overview
|
11
11
|
-------------------------
|
12
|
-
[LaunchDarkly](https://www.launchdarkly.com) is a feature management platform that serves
|
12
|
+
[LaunchDarkly](https://www.launchdarkly.com) is a feature management platform that serves trillions of feature flags daily to help teams build better software, faster. [Get started](https://docs.launchdarkly.com/home/getting-started) using LaunchDarkly today!
|
13
13
|
|
14
14
|
[](https://twitter.com/intent/follow?screen_name=launchdarkly)
|
15
15
|
|
@@ -26,7 +26,7 @@ Refer to the [SDK documentation](https://docs.launchdarkly.com/sdk/server-side/r
|
|
26
26
|
Learn more
|
27
27
|
-----------
|
28
28
|
|
29
|
-
|
29
|
+
Read our [documentation](http://docs.launchdarkly.com) for in-depth instructions on configuring and using LaunchDarkly. You can also head straight to the [reference guide for this SDK](http://docs.launchdarkly.com/docs/ruby-sdk-reference).
|
30
30
|
|
31
31
|
Generated API documentation for all versions of the SDK is on [RubyDoc.info](https://www.rubydoc.info/gems/launchdarkly-server-sdk). The API documentation for the latest version is also on [GitHub Pages](https://launchdarkly.github.io/ruby-server-sdk).
|
32
32
|
|
data/lib/ldclient-rb/config.rb
CHANGED
@@ -13,18 +13,6 @@ module LaunchDarkly
|
|
13
13
|
#
|
14
14
|
# Constructor for creating custom LaunchDarkly configurations.
|
15
15
|
#
|
16
|
-
# `user_keys_capacity` and `user_keys_flush_interval` are deprecated
|
17
|
-
# configuration options. They exist to maintain backwards compatibility
|
18
|
-
# with previous configurations. Newer code should prefer their replacement
|
19
|
-
# options -- `context_keys_capacity` and `context_keys_flush_interval`.
|
20
|
-
#
|
21
|
-
# In the event both the user and context variations are provided, the
|
22
|
-
# context specific configuration option will take precedence.
|
23
|
-
#
|
24
|
-
# Similarly, `private_attribute_names` is deprecated. Newer code should
|
25
|
-
# prefer `private_attributes`. If both are provided, `private_attributes`
|
26
|
-
# will take precedence.
|
27
|
-
#
|
28
16
|
# @param opts [Hash] the configuration options
|
29
17
|
# @option opts [Logger] :logger See {#logger}.
|
30
18
|
# @option opts [String] :base_uri ("https://sdk.launchdarkly.com") See {#base_uri}.
|
@@ -42,12 +30,9 @@ module LaunchDarkly
|
|
42
30
|
# @option opts [Float] :poll_interval (30) See {#poll_interval}.
|
43
31
|
# @option opts [Boolean] :stream (true) See {#stream?}.
|
44
32
|
# @option opts [Boolean] all_attributes_private (false) See {#all_attributes_private}.
|
45
|
-
# @option opts [Array] :private_attribute_names See {#private_attribute_names}.
|
46
33
|
# @option opts [Array] :private_attributes See {#private_attributes}.
|
47
34
|
# @option opts [Boolean] :send_events (true) See {#send_events}.
|
48
|
-
# @option opts [Integer] :user_keys_capacity (1000) See {#user_keys_capacity}.
|
49
35
|
# @option opts [Integer] :context_keys_capacity (1000) See {#context_keys_capacity}.
|
50
|
-
# @option opts [Float] :user_keys_flush_interval (300) See {#user_keys_flush_interval}.
|
51
36
|
# @option opts [Float] :context_keys_flush_interval (300) See {#context_keys_flush_interval}.
|
52
37
|
# @option opts [Object] :data_source See {#data_source}.
|
53
38
|
# @option opts [Boolean] :diagnostic_opt_out (false) See {#diagnostic_opt_out?}.
|
@@ -76,10 +61,10 @@ module LaunchDarkly
|
|
76
61
|
@offline = opts.has_key?(:offline) ? opts[:offline] : Config.default_offline
|
77
62
|
@poll_interval = opts.has_key?(:poll_interval) && opts[:poll_interval] > Config.default_poll_interval ? opts[:poll_interval] : Config.default_poll_interval
|
78
63
|
@all_attributes_private = opts[:all_attributes_private] || false
|
79
|
-
@private_attributes = opts[:private_attributes] ||
|
64
|
+
@private_attributes = opts[:private_attributes] || []
|
80
65
|
@send_events = opts.has_key?(:send_events) ? opts[:send_events] : Config.default_send_events
|
81
|
-
@context_keys_capacity = opts[:context_keys_capacity] ||
|
82
|
-
@context_keys_flush_interval = opts[:context_keys_flush_interval] ||
|
66
|
+
@context_keys_capacity = opts[:context_keys_capacity] || Config.default_context_keys_capacity
|
67
|
+
@context_keys_flush_interval = opts[:context_keys_flush_interval] || Config.default_context_keys_flush_interval
|
83
68
|
@data_source = opts[:data_source]
|
84
69
|
@diagnostic_opt_out = opts.has_key?(:diagnostic_opt_out) && opts[:diagnostic_opt_out]
|
85
70
|
@diagnostic_recording_interval = opts.has_key?(:diagnostic_recording_interval) && opts[:diagnostic_recording_interval] > Config.minimum_diagnostic_recording_interval ?
|
@@ -258,14 +243,6 @@ module LaunchDarkly
|
|
258
243
|
#
|
259
244
|
attr_reader :private_attributes
|
260
245
|
|
261
|
-
#
|
262
|
-
# @deprecated Backwards compatibility alias for #private_attributes.
|
263
|
-
#
|
264
|
-
# @return [Integer]
|
265
|
-
# @see #private_attributes
|
266
|
-
#
|
267
|
-
alias :private_attribute_names :private_attributes
|
268
|
-
|
269
246
|
#
|
270
247
|
# Whether to send events back to LaunchDarkly. This differs from {#offline?} in that it affects
|
271
248
|
# only the sending of client-side events, not streaming or polling for events from the server.
|
@@ -281,14 +258,6 @@ module LaunchDarkly
|
|
281
258
|
#
|
282
259
|
attr_reader :context_keys_capacity
|
283
260
|
|
284
|
-
#
|
285
|
-
# @deprecated Backwards compatibility alias for #context_keys_capacity.
|
286
|
-
#
|
287
|
-
# @return [Integer]
|
288
|
-
# @see #context_keys_flush_interval
|
289
|
-
#
|
290
|
-
alias :user_keys_capacity :context_keys_capacity
|
291
|
-
|
292
261
|
#
|
293
262
|
# The interval in seconds at which the event processor will reset its set of known context keys.
|
294
263
|
# @return [Float]
|
@@ -296,14 +265,6 @@ module LaunchDarkly
|
|
296
265
|
#
|
297
266
|
attr_reader :context_keys_flush_interval
|
298
267
|
|
299
|
-
#
|
300
|
-
# @deprecated Backwards compatibility alias for #context_keys_flush_interval.
|
301
|
-
#
|
302
|
-
# @return [Integer]
|
303
|
-
# @see #context_keys_flush_interval
|
304
|
-
#
|
305
|
-
alias :user_keys_flush_interval :context_keys_flush_interval
|
306
|
-
|
307
268
|
#
|
308
269
|
# An object that is responsible for receiving feature flag data from LaunchDarkly. By default,
|
309
270
|
# the client uses its standard polling or streaming implementation; this is customizable for
|
@@ -486,7 +447,7 @@ module LaunchDarkly
|
|
486
447
|
|
487
448
|
#
|
488
449
|
# The default value for {#connect_timeout}.
|
489
|
-
# @return [Float]
|
450
|
+
# @return [Float] 2
|
490
451
|
#
|
491
452
|
def self.default_connect_timeout
|
492
453
|
2
|
@@ -570,18 +531,6 @@ module LaunchDarkly
|
|
570
531
|
300
|
571
532
|
end
|
572
533
|
|
573
|
-
class << self
|
574
|
-
#
|
575
|
-
# @deprecated Backwards compatibility alias for #default_context_keys_capacity
|
576
|
-
#
|
577
|
-
alias :default_user_keys_capacity :default_context_keys_capacity
|
578
|
-
|
579
|
-
#
|
580
|
-
# @deprecated Backwards compatibility alias for #default_context_keys_flush_interval
|
581
|
-
#
|
582
|
-
alias :default_user_keys_flush_interval :default_context_keys_flush_interval
|
583
|
-
end
|
584
|
-
|
585
534
|
#
|
586
535
|
# The default value for {#diagnostic_recording_interval}.
|
587
536
|
# @return [Float] 900
|
@@ -647,25 +596,11 @@ module LaunchDarkly
|
|
647
596
|
# @return [Integer]
|
648
597
|
attr_reader :context_cache_size
|
649
598
|
|
650
|
-
#
|
651
|
-
# @deprecated Backwards compatibility alias for #context_cache_size
|
652
|
-
#
|
653
|
-
# @return [Integer]
|
654
|
-
#
|
655
|
-
alias :user_cache_size :context_cache_size
|
656
|
-
|
657
599
|
# The maximum length of time (in seconds) that the Big Segment state for a context will be cached
|
658
600
|
# by the SDK.
|
659
601
|
# @return [Float]
|
660
602
|
attr_reader :context_cache_time
|
661
603
|
|
662
|
-
#
|
663
|
-
# @deprecated Backwards compatibility alias for #context_cache_time
|
664
|
-
#
|
665
|
-
# @return [Float]
|
666
|
-
#
|
667
|
-
alias :user_cache_time :context_cache_time
|
668
|
-
|
669
604
|
# The interval (in seconds) at which the SDK will poll the Big Segment store to make sure it is
|
670
605
|
# available and to determine how long ago it was updated.
|
671
606
|
# @return [Float]
|
data/lib/ldclient-rb/context.rb
CHANGED
@@ -317,12 +317,13 @@ module LaunchDarkly
|
|
317
317
|
# {https://docs.launchdarkly.com/sdk/features/user-config SDK
|
318
318
|
# documentation}.
|
319
319
|
#
|
320
|
+
# @deprecated The old user format will be removed in 8.0.0. Please use the new context specific format.
|
321
|
+
#
|
320
322
|
# @param data [Hash]
|
321
323
|
# @return [LDContext]
|
322
324
|
#
|
323
325
|
def self.create(data)
|
324
326
|
return create_invalid_context(ERR_NOT_HASH) unless data.is_a?(Hash)
|
325
|
-
return create_legacy_context(data) unless data.has_key?(:kind)
|
326
327
|
|
327
328
|
kind = data[:kind]
|
328
329
|
if kind == KIND_MULTI
|
@@ -392,50 +393,6 @@ module LaunchDarkly
|
|
392
393
|
new(nil, nil, nil, nil, false, nil, nil, error)
|
393
394
|
end
|
394
395
|
|
395
|
-
#
|
396
|
-
# @param data [Hash]
|
397
|
-
# @return [LDContext]
|
398
|
-
#
|
399
|
-
private_class_method def self.create_legacy_context(data)
|
400
|
-
key = data[:key]
|
401
|
-
|
402
|
-
# Legacy users are allowed to have "" as a key but they cannot have nil as a key.
|
403
|
-
return create_invalid_context(ERR_KEY_EMPTY) if key.nil?
|
404
|
-
|
405
|
-
name = data[:name]
|
406
|
-
name_error = LaunchDarkly::Impl::Context.validate_name(name)
|
407
|
-
return create_invalid_context(name_error) unless name_error.nil?
|
408
|
-
|
409
|
-
anonymous = data[:anonymous]
|
410
|
-
anonymous_error = LaunchDarkly::Impl::Context.validate_anonymous(anonymous, true)
|
411
|
-
return create_invalid_context(anonymous_error) unless anonymous_error.nil?
|
412
|
-
|
413
|
-
custom = data[:custom]
|
414
|
-
unless custom.nil? || custom.is_a?(Hash)
|
415
|
-
return create_invalid_context(ERR_CUSTOM_NON_HASH)
|
416
|
-
end
|
417
|
-
|
418
|
-
# We only need to create an attribute hash if one of these keys exist.
|
419
|
-
# Everything else is stored in dedicated instance variables.
|
420
|
-
attributes = custom.clone
|
421
|
-
data.each do |k, v|
|
422
|
-
case k
|
423
|
-
when :ip, :email, :avatar, :firstName, :lastName, :country
|
424
|
-
attributes ||= {}
|
425
|
-
attributes[k] = v.clone
|
426
|
-
else
|
427
|
-
next
|
428
|
-
end
|
429
|
-
end
|
430
|
-
|
431
|
-
private_attributes = data[:privateAttributeNames]
|
432
|
-
if private_attributes && !private_attributes.is_a?(Array)
|
433
|
-
return create_invalid_context(ERR_PRIVATE_NON_ARRAY)
|
434
|
-
end
|
435
|
-
|
436
|
-
new(key.to_s, key.to_s, KIND_DEFAULT, name, anonymous, attributes, private_attributes)
|
437
|
-
end
|
438
|
-
|
439
396
|
#
|
440
397
|
# @param data [Hash]
|
441
398
|
# @param kind [String]
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module LaunchDarkly
|
3
2
|
# An object returned by {LDClient#variation_detail}, combining the result of a flag evaluation with
|
4
3
|
# an explanation of how it was calculated.
|
@@ -13,6 +12,7 @@ module LaunchDarkly
|
|
13
12
|
def initialize(value, variation_index, reason)
|
14
13
|
raise ArgumentError.new("variation_index must be a number") if !variation_index.nil? && !(variation_index.is_a? Numeric)
|
15
14
|
raise ArgumentError.new("reason must be an EvaluationReason") unless reason.is_a? EvaluationReason
|
15
|
+
|
16
16
|
@value = value
|
17
17
|
@variation_index = variation_index
|
18
18
|
@reason = reason
|
@@ -100,6 +100,10 @@ module LaunchDarkly
|
|
100
100
|
# a rule specified a nonexistent variation. An error message will always be logged in this case.
|
101
101
|
ERROR_MALFORMED_FLAG = :MALFORMED_FLAG
|
102
102
|
|
103
|
+
# Value for {#error_kind} indicating that there was an inconsistency between the expected type of the flag, and the
|
104
|
+
# actual type of the variation evaluated.
|
105
|
+
ERROR_WRONG_TYPE = :WRONG_TYPE
|
106
|
+
|
103
107
|
# Value for {#error_kind} indicating that the caller passed `nil` for the context parameter, or the
|
104
108
|
# context was invalid.
|
105
109
|
ERROR_USER_NOT_SPECIFIED = :USER_NOT_SPECIFIED
|
data/lib/ldclient-rb/events.rb
CHANGED
@@ -40,7 +40,9 @@ module LaunchDarkly
|
|
40
40
|
default = nil,
|
41
41
|
track_events = false,
|
42
42
|
debug_until = nil,
|
43
|
-
prereq_of = nil
|
43
|
+
prereq_of = nil,
|
44
|
+
sampling_ratio = nil,
|
45
|
+
exclude_from_summaries = false
|
44
46
|
)
|
45
47
|
end
|
46
48
|
|
@@ -55,6 +57,9 @@ module LaunchDarkly
|
|
55
57
|
)
|
56
58
|
end
|
57
59
|
|
60
|
+
def record_migration_op_event(event)
|
61
|
+
end
|
62
|
+
|
58
63
|
def flush
|
59
64
|
end
|
60
65
|
|
@@ -153,10 +158,12 @@ module LaunchDarkly
|
|
153
158
|
default = nil,
|
154
159
|
track_events = false,
|
155
160
|
debug_until = nil,
|
156
|
-
prereq_of = nil
|
161
|
+
prereq_of = nil,
|
162
|
+
sampling_ratio = nil,
|
163
|
+
exclude_from_summaries = false
|
157
164
|
)
|
158
165
|
post_to_inbox(LaunchDarkly::Impl::EvalEvent.new(timestamp, context, key, version, variation, value, reason,
|
159
|
-
default, track_events, debug_until, prereq_of))
|
166
|
+
default, track_events, debug_until, prereq_of, sampling_ratio, exclude_from_summaries))
|
160
167
|
end
|
161
168
|
|
162
169
|
def record_identify_event(context)
|
@@ -167,6 +174,10 @@ module LaunchDarkly
|
|
167
174
|
post_to_inbox(LaunchDarkly::Impl::CustomEvent.new(timestamp, context, key, data, metric_value))
|
168
175
|
end
|
169
176
|
|
177
|
+
def record_migration_op_event(event)
|
178
|
+
post_to_inbox(event)
|
179
|
+
end
|
180
|
+
|
170
181
|
def flush
|
171
182
|
# flush is done asynchronously
|
172
183
|
post_to_inbox(FlushMessage.new)
|
@@ -220,6 +231,7 @@ module LaunchDarkly
|
|
220
231
|
@config = config
|
221
232
|
@diagnostic_accumulator = config.diagnostic_opt_out? ? nil : diagnostic_accumulator
|
222
233
|
@event_sender = event_sender
|
234
|
+
@sampler = LaunchDarkly::Impl::Sampler.new(Random.new)
|
223
235
|
|
224
236
|
@context_keys = SimpleLRUCacheSet.new(config.context_keys_capacity)
|
225
237
|
@formatter = EventOutputFormatter.new(config)
|
@@ -292,7 +304,7 @@ module LaunchDarkly
|
|
292
304
|
return if @disabled.value
|
293
305
|
|
294
306
|
# Always record the event in the summary.
|
295
|
-
outbox.add_to_summary(event)
|
307
|
+
outbox.add_to_summary(event) unless event.exclude_from_summaries
|
296
308
|
|
297
309
|
# Decide whether to add the event to the payload. Feature events may be added twice, once for
|
298
310
|
# the event (if tracked) and once for debugging.
|
@@ -309,12 +321,12 @@ module LaunchDarkly
|
|
309
321
|
|
310
322
|
# For each context we haven't seen before, we add an index event - unless this is already
|
311
323
|
# an identify event for that context.
|
312
|
-
if !event.context.nil? && !notice_context(event.context) && !event.is_a?(LaunchDarkly::Impl::IdentifyEvent)
|
324
|
+
if !event.context.nil? && !notice_context(event.context) && !event.is_a?(LaunchDarkly::Impl::IdentifyEvent) && !event.is_a?(LaunchDarkly::Impl::MigrationOpEvent)
|
313
325
|
outbox.add_event(LaunchDarkly::Impl::IndexEvent.new(event.timestamp, event.context))
|
314
326
|
end
|
315
327
|
|
316
|
-
outbox.add_event(event) if will_add_full_event
|
317
|
-
outbox.add_event(debug_event)
|
328
|
+
outbox.add_event(event) if will_add_full_event && @sampler.sample(event.sampling_ratio.nil? ? 1 : event.sampling_ratio)
|
329
|
+
outbox.add_event(debug_event) if !debug_event.nil? && @sampler.sample(event.sampling_ratio.nil? ? 1 : event.sampling_ratio)
|
318
330
|
end
|
319
331
|
|
320
332
|
#
|
@@ -443,6 +455,7 @@ module LaunchDarkly
|
|
443
455
|
CUSTOM_KIND = 'custom'
|
444
456
|
INDEX_KIND = 'index'
|
445
457
|
DEBUG_KIND = 'debug'
|
458
|
+
MIGRATION_OP_KIND = 'migration_op'
|
446
459
|
SUMMARY_KIND = 'summary'
|
447
460
|
|
448
461
|
def initialize(config)
|
@@ -476,6 +489,64 @@ module LaunchDarkly
|
|
476
489
|
out[:reason] = event.reason unless event.reason.nil?
|
477
490
|
out
|
478
491
|
|
492
|
+
when LaunchDarkly::Impl::MigrationOpEvent
|
493
|
+
out = {
|
494
|
+
kind: MIGRATION_OP_KIND,
|
495
|
+
creationDate: event.timestamp,
|
496
|
+
contextKeys: event.context.keys,
|
497
|
+
operation: event.operation.to_s,
|
498
|
+
evaluation: {
|
499
|
+
key: event.key,
|
500
|
+
value: event.evaluation.value,
|
501
|
+
},
|
502
|
+
}
|
503
|
+
|
504
|
+
out[:evaluation][:version] = event.version unless event.version.nil?
|
505
|
+
out[:evaluation][:default] = event.default unless event.default.nil?
|
506
|
+
out[:evaluation][:variation] = event.evaluation.variation_index unless event.evaluation.variation_index.nil?
|
507
|
+
out[:evaluation][:reason] = event.evaluation.reason unless event.evaluation.reason.nil?
|
508
|
+
out[:samplingRatio] = event.sampling_ratio unless event.sampling_ratio.nil? || event.sampling_ratio == 1
|
509
|
+
|
510
|
+
measurements = []
|
511
|
+
|
512
|
+
unless event.invoked.empty?
|
513
|
+
measurements << {
|
514
|
+
"key": "invoked",
|
515
|
+
"values": event.invoked.map { |origin| [origin, true] }.to_h,
|
516
|
+
}
|
517
|
+
end
|
518
|
+
|
519
|
+
unless event.consistency_check.nil?
|
520
|
+
measurement = {
|
521
|
+
"key": "consistent",
|
522
|
+
"value": event.consistency_check,
|
523
|
+
}
|
524
|
+
|
525
|
+
unless event.consistency_check_ratio.nil? || event.consistency_check_ratio == 1
|
526
|
+
measurement[:samplingRatio] = event.consistency_check_ratio
|
527
|
+
end
|
528
|
+
|
529
|
+
measurements << measurement
|
530
|
+
end
|
531
|
+
|
532
|
+
|
533
|
+
unless event.latencies.empty?
|
534
|
+
measurements << {
|
535
|
+
"key": "latency_ms",
|
536
|
+
"values": event.latencies,
|
537
|
+
}
|
538
|
+
end
|
539
|
+
|
540
|
+
unless event.errors.empty?
|
541
|
+
measurements << {
|
542
|
+
"key": "error",
|
543
|
+
"values": event.errors.map { |origin| [origin, true] }.to_h,
|
544
|
+
}
|
545
|
+
end
|
546
|
+
out[:measurements] = measurements unless measurements.empty?
|
547
|
+
|
548
|
+
out
|
549
|
+
|
479
550
|
when LaunchDarkly::Impl::IdentifyEvent
|
480
551
|
{
|
481
552
|
kind: IDENTIFY_KIND,
|
@@ -23,7 +23,7 @@ module LaunchDarkly
|
|
23
23
|
@last_status = nil
|
24
24
|
|
25
25
|
unless @store.nil?
|
26
|
-
@cache = ExpiringCache.new(big_segments_config.
|
26
|
+
@cache = ExpiringCache.new(big_segments_config.context_cache_size, big_segments_config.context_cache_time)
|
27
27
|
@poll_worker = RepeatingTask.new(big_segments_config.status_poll_interval, 0, -> { poll_store_and_update_status }, logger)
|
28
28
|
@poll_worker.start
|
29
29
|
end
|
@@ -40,7 +40,7 @@ module LaunchDarkly
|
|
40
40
|
return ERR_KIND_NON_STRING unless kind.is_a?(String)
|
41
41
|
return ERR_KIND_CANNOT_BE_KIND if kind == "kind"
|
42
42
|
return ERR_KIND_CANNOT_BE_MULTI if kind == "multi"
|
43
|
-
|
43
|
+
ERR_KIND_INVALID_CHARS unless kind.match?(/^[\w.-]+$/)
|
44
44
|
end
|
45
45
|
|
46
46
|
#
|
@@ -51,7 +51,7 @@ module LaunchDarkly
|
|
51
51
|
#
|
52
52
|
def self.validate_key(key)
|
53
53
|
return ERR_KEY_NON_STRING unless key.is_a?(String)
|
54
|
-
|
54
|
+
ERR_KEY_EMPTY if key == ""
|
55
55
|
end
|
56
56
|
|
57
57
|
#
|
@@ -61,7 +61,7 @@ module LaunchDarkly
|
|
61
61
|
# @return [String, nil]
|
62
62
|
#
|
63
63
|
def self.validate_name(name)
|
64
|
-
|
64
|
+
ERR_NAME_NON_STRING unless name.nil? || name.is_a?(String)
|
65
65
|
end
|
66
66
|
|
67
67
|
#
|
@@ -1,23 +1,33 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module LaunchDarkly
|
2
4
|
module Impl
|
3
5
|
class Event
|
4
6
|
# @param timestamp [Integer]
|
5
7
|
# @param context [LaunchDarkly::LDContext]
|
6
|
-
|
8
|
+
# @param sampling_ratio [Integer, nil]
|
9
|
+
# @param exclude_from_summaries [Boolean]
|
10
|
+
def initialize(timestamp, context, sampling_ratio = nil, exclude_from_summaries = false)
|
7
11
|
@timestamp = timestamp
|
8
12
|
@context = context
|
13
|
+
@sampling_ratio = sampling_ratio
|
14
|
+
@exclude_from_summaries = exclude_from_summaries
|
9
15
|
end
|
10
16
|
|
11
17
|
# @return [Integer]
|
12
18
|
attr_reader :timestamp
|
13
19
|
# @return [LaunchDarkly::LDContext]
|
14
20
|
attr_reader :context
|
21
|
+
# @return [Integer, nil]
|
22
|
+
attr_reader :sampling_ratio
|
23
|
+
# @return [Boolean]
|
24
|
+
attr_reader :exclude_from_summaries
|
15
25
|
end
|
16
26
|
|
17
27
|
class EvalEvent < Event
|
18
28
|
def initialize(timestamp, context, key, version = nil, variation = nil, value = nil, reason = nil, default = nil,
|
19
|
-
track_events = false, debug_until = nil, prereq_of = nil)
|
20
|
-
super(timestamp, context)
|
29
|
+
track_events = false, debug_until = nil, prereq_of = nil, sampling_ratio = nil, exclude_from_summaries = false)
|
30
|
+
super(timestamp, context, sampling_ratio, exclude_from_summaries)
|
21
31
|
@key = key
|
22
32
|
@version = version
|
23
33
|
@variation = variation
|
@@ -41,6 +51,54 @@ module LaunchDarkly
|
|
41
51
|
attr_reader :prereq_of
|
42
52
|
end
|
43
53
|
|
54
|
+
class MigrationOpEvent < Event
|
55
|
+
#
|
56
|
+
# A migration op event represents the results of a migration-assisted read or write operation.
|
57
|
+
#
|
58
|
+
# The event includes optional measurements reporting on consistency checks, error reporting, and operation latency
|
59
|
+
# values.
|
60
|
+
#
|
61
|
+
# @param timestamp [Integer]
|
62
|
+
# @param context [LaunchDarkly::LDContext]
|
63
|
+
# @param key [string]
|
64
|
+
# @param flag [LaunchDarkly::Impl::Model::FeatureFlag, nil]
|
65
|
+
# @param operation [Symbol]
|
66
|
+
# @param default_stage [Symbol]
|
67
|
+
# @param evaluation [LaunchDarkly::EvaluationDetail]
|
68
|
+
# @param invoked [Set]
|
69
|
+
# @param consistency_check [Boolean, nil]
|
70
|
+
# @param consistency_check_ratio [Integer, nil]
|
71
|
+
# @param errors [Set]
|
72
|
+
# @param latencies [Hash<Symbol, Float>]
|
73
|
+
#
|
74
|
+
def initialize(timestamp, context, key, flag, operation, default_stage, evaluation, invoked, consistency_check, consistency_check_ratio, errors, latencies)
|
75
|
+
super(timestamp, context)
|
76
|
+
@operation = operation
|
77
|
+
@key = key
|
78
|
+
@version = flag&.version
|
79
|
+
@sampling_ratio = flag&.sampling_ratio
|
80
|
+
@default = default_stage
|
81
|
+
@evaluation = evaluation
|
82
|
+
@consistency_check = consistency_check
|
83
|
+
@consistency_check_ratio = consistency_check.nil? ? nil : consistency_check_ratio
|
84
|
+
@invoked = invoked
|
85
|
+
@errors = errors
|
86
|
+
@latencies = latencies
|
87
|
+
end
|
88
|
+
|
89
|
+
attr_reader :operation
|
90
|
+
attr_reader :key
|
91
|
+
attr_reader :version
|
92
|
+
attr_reader :sampling_ratio
|
93
|
+
attr_reader :default
|
94
|
+
attr_reader :evaluation
|
95
|
+
attr_reader :consistency_check
|
96
|
+
attr_reader :consistency_check_ratio
|
97
|
+
attr_reader :invoked
|
98
|
+
attr_reader :errors
|
99
|
+
attr_reader :latencies
|
100
|
+
end
|
101
|
+
|
44
102
|
class IdentifyEvent < Event
|
45
103
|
def initialize(timestamp, context)
|
46
104
|
super(timestamp, context)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "ldclient-rb/interfaces"
|
1
2
|
require "concurrent/atomics"
|
2
3
|
require "json"
|
3
4
|
|
@@ -117,7 +118,7 @@ module LaunchDarkly
|
|
117
118
|
@logger = opts[:logger] || Config.default_logger
|
118
119
|
@test_hook = opts[:test_hook] # used for unit tests, deliberately undocumented
|
119
120
|
|
120
|
-
@stopped = Concurrent::AtomicBoolean.new
|
121
|
+
@stopped = Concurrent::AtomicBoolean.new
|
121
122
|
|
122
123
|
with_connection do |redis|
|
123
124
|
@logger.info("#{description}: using Redis instance at #{redis.connection[:host]}:#{redis.connection[:port]} and prefix: #{@prefix}")
|