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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50934709e1ee8c075c56c149f75753f87498eb9e1f06e39597d2cd4514ea7196
|
4
|
+
data.tar.gz: e7f153366b7b50c3951f844bf9ce1a0b81093fc733818dbb02e8f0a888d9ac26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2469e536ca482489eb46f3ff650aeb573eb691ab6c6c2b8ed669b7f8ba799bf65d68d40f6cabc51ec4b051dd56e309430f94e5dc4fbbd70193efa5156d1d1082
|
7
|
+
data.tar.gz: 454219746c7b296fd8c92ee5e266f96765f72527706b7d6f7360445eb1d245e2acb37e4cb722ed48bf73dce8e307d2121771270ea9bedb71e91d67f9a79b8ea0
|
data/README.md
CHANGED
@@ -3,8 +3,7 @@ LaunchDarkly Server-side SDK for Ruby
|
|
3
3
|
|
4
4
|
[](http://badge.fury.io/rb/launchdarkly-server-sdk)
|
5
5
|
|
6
|
-
[](https://hakiri.io/github/launchdarkly/ruby-server-sdk/master)
|
6
|
+
[](https://circleci.com/gh/launchdarkly/ruby-server-sdk/tree/main)
|
8
7
|
[](https://www.rubydoc.info/gems/launchdarkly-server-sdk)
|
9
8
|
[](https://launchdarkly.github.io/ruby-server-sdk)
|
10
9
|
|
data/lib/ldclient-rb/config.rb
CHANGED
@@ -21,6 +21,7 @@ module LaunchDarkly
|
|
21
21
|
# @option opts [Integer] :capacity (10000) See {#capacity}.
|
22
22
|
# @option opts [Float] :flush_interval (30) See {#flush_interval}.
|
23
23
|
# @option opts [Float] :read_timeout (10) See {#read_timeout}.
|
24
|
+
# @option opts [Float] :initial_reconnect_delay (1) See {#initial_reconnect_delay}.
|
24
25
|
# @option opts [Float] :connect_timeout (2) See {#connect_timeout}.
|
25
26
|
# @option opts [Object] :cache_store See {#cache_store}.
|
26
27
|
# @option opts [Object] :feature_store See {#feature_store}.
|
@@ -54,6 +55,7 @@ module LaunchDarkly
|
|
54
55
|
@flush_interval = opts[:flush_interval] || Config.default_flush_interval
|
55
56
|
@connect_timeout = opts[:connect_timeout] || Config.default_connect_timeout
|
56
57
|
@read_timeout = opts[:read_timeout] || Config.default_read_timeout
|
58
|
+
@initial_reconnect_delay = opts[:initial_reconnect_delay] || Config.default_initial_reconnect_delay
|
57
59
|
@feature_store = opts[:feature_store] || Config.default_feature_store
|
58
60
|
@stream = opts.has_key?(:stream) ? opts[:stream] : Config.default_stream
|
59
61
|
@use_ldd = opts.has_key?(:use_ldd) ? opts[:use_ldd] : Config.default_use_ldd
|
@@ -180,6 +182,13 @@ module LaunchDarkly
|
|
180
182
|
#
|
181
183
|
attr_reader :read_timeout
|
182
184
|
|
185
|
+
#
|
186
|
+
# The initial delay before reconnecting after an error in the SSE client.
|
187
|
+
# This only applies to the streaming connection.
|
188
|
+
# @return [Float]
|
189
|
+
#
|
190
|
+
attr_reader :initial_reconnect_delay
|
191
|
+
|
183
192
|
#
|
184
193
|
# The connect timeout for network connections in seconds.
|
185
194
|
# @return [Float]
|
@@ -395,6 +404,14 @@ module LaunchDarkly
|
|
395
404
|
10
|
396
405
|
end
|
397
406
|
|
407
|
+
#
|
408
|
+
# The default value for {#initial_reconnect_delay}.
|
409
|
+
# @return [Float] 1
|
410
|
+
#
|
411
|
+
def self.default_initial_reconnect_delay
|
412
|
+
1
|
413
|
+
end
|
414
|
+
|
398
415
|
#
|
399
416
|
# The default value for {#connect_timeout}.
|
400
417
|
# @return [Float] 10
|
data/lib/ldclient-rb/events.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require "ldclient-rb/impl/diagnostic_events"
|
2
2
|
require "ldclient-rb/impl/event_sender"
|
3
|
+
require "ldclient-rb/impl/event_summarizer"
|
4
|
+
require "ldclient-rb/impl/event_types"
|
3
5
|
require "ldclient-rb/impl/util"
|
4
6
|
|
5
7
|
require "concurrent"
|
@@ -26,16 +28,33 @@ require "time"
|
|
26
28
|
#
|
27
29
|
|
28
30
|
module LaunchDarkly
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
module EventProcessorMethods
|
32
|
+
def record_eval_event(
|
33
|
+
user,
|
34
|
+
key,
|
35
|
+
version = nil,
|
36
|
+
variation = nil,
|
37
|
+
value = nil,
|
38
|
+
reason = nil,
|
39
|
+
default = nil,
|
40
|
+
track_events = false,
|
41
|
+
debug_until = nil,
|
42
|
+
prereq_of = nil
|
43
|
+
)
|
44
|
+
end
|
32
45
|
|
33
|
-
|
34
|
-
|
46
|
+
def record_identify_event(user)
|
47
|
+
end
|
35
48
|
|
36
|
-
|
37
|
-
|
38
|
-
|
49
|
+
def record_custom_event(
|
50
|
+
user,
|
51
|
+
key,
|
52
|
+
data = nil,
|
53
|
+
metric_value = nil
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def record_alias_event(user, previous_user)
|
39
58
|
end
|
40
59
|
|
41
60
|
def flush
|
@@ -45,12 +64,16 @@ module LaunchDarkly
|
|
45
64
|
end
|
46
65
|
end
|
47
66
|
|
67
|
+
MAX_FLUSH_WORKERS = 5
|
68
|
+
USER_ATTRS_TO_STRINGIFY_FOR_EVENTS = [ :key, :secondary, :ip, :country, :email, :firstName, :lastName,
|
69
|
+
:avatar, :name ]
|
70
|
+
|
71
|
+
private_constant :MAX_FLUSH_WORKERS
|
72
|
+
private_constant :USER_ATTRS_TO_STRINGIFY_FOR_EVENTS
|
73
|
+
|
48
74
|
# @private
|
49
|
-
class
|
50
|
-
|
51
|
-
@event = event
|
52
|
-
end
|
53
|
-
attr_reader :event
|
75
|
+
class NullEventProcessor
|
76
|
+
include EventProcessorMethods
|
54
77
|
end
|
55
78
|
|
56
79
|
# @private
|
@@ -90,6 +113,8 @@ module LaunchDarkly
|
|
90
113
|
|
91
114
|
# @private
|
92
115
|
class EventProcessor
|
116
|
+
include EventProcessorMethods
|
117
|
+
|
93
118
|
def initialize(sdk_key, config, client = nil, diagnostic_accumulator = nil, test_properties = nil)
|
94
119
|
raise ArgumentError, "sdk_key must not be nil" if sdk_key.nil? # see LDClient constructor comment on sdk_key
|
95
120
|
@logger = config.logger
|
@@ -116,16 +141,46 @@ module LaunchDarkly
|
|
116
141
|
@stopped = Concurrent::AtomicBoolean.new(false)
|
117
142
|
@inbox_full = Concurrent::AtomicBoolean.new(false)
|
118
143
|
|
119
|
-
event_sender = test_properties
|
120
|
-
test_properties[:event_sender] :
|
144
|
+
event_sender = (test_properties || {})[:event_sender] ||
|
121
145
|
Impl::EventSender.new(sdk_key, config, client ? client : Util.new_http_client(config.events_uri, config))
|
122
146
|
|
147
|
+
@timestamp_fn = (test_properties || {})[:timestamp_fn] || proc { Impl::Util.current_time_millis }
|
148
|
+
|
123
149
|
EventDispatcher.new(@inbox, sdk_key, config, diagnostic_accumulator, event_sender)
|
124
150
|
end
|
125
151
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
152
|
+
def record_eval_event(
|
153
|
+
user,
|
154
|
+
key,
|
155
|
+
version = nil,
|
156
|
+
variation = nil,
|
157
|
+
value = nil,
|
158
|
+
reason = nil,
|
159
|
+
default = nil,
|
160
|
+
track_events = false,
|
161
|
+
debug_until = nil,
|
162
|
+
prereq_of = nil
|
163
|
+
)
|
164
|
+
post_to_inbox(LaunchDarkly::Impl::EvalEvent.new(timestamp, user, key, version, variation, value, reason,
|
165
|
+
default, track_events, debug_until, prereq_of))
|
166
|
+
end
|
167
|
+
|
168
|
+
def record_identify_event(user)
|
169
|
+
post_to_inbox(LaunchDarkly::Impl::IdentifyEvent.new(timestamp, user))
|
170
|
+
end
|
171
|
+
|
172
|
+
def record_custom_event(user, key, data = nil, metric_value = nil)
|
173
|
+
post_to_inbox(LaunchDarkly::Impl::CustomEvent.new(timestamp, user, key, data, metric_value))
|
174
|
+
end
|
175
|
+
|
176
|
+
def record_alias_event(user, previous_user)
|
177
|
+
post_to_inbox(LaunchDarkly::Impl::AliasEvent.new(
|
178
|
+
timestamp,
|
179
|
+
user.nil? ? nil : user[:key],
|
180
|
+
user_to_context_kind(user),
|
181
|
+
previous_user.nil? ? nil : previous_user[:key],
|
182
|
+
user_to_context_kind(previous_user)
|
183
|
+
))
|
129
184
|
end
|
130
185
|
|
131
186
|
def flush
|
@@ -155,9 +210,11 @@ module LaunchDarkly
|
|
155
210
|
sync_msg.wait_for_completion
|
156
211
|
end
|
157
212
|
|
158
|
-
private
|
213
|
+
private def timestamp
|
214
|
+
@timestamp_fn.call()
|
215
|
+
end
|
159
216
|
|
160
|
-
def post_to_inbox(message)
|
217
|
+
private def post_to_inbox(message)
|
161
218
|
begin
|
162
219
|
@inbox.push(message, non_block=true)
|
163
220
|
rescue ThreadError
|
@@ -170,6 +227,10 @@ module LaunchDarkly
|
|
170
227
|
end
|
171
228
|
end
|
172
229
|
end
|
230
|
+
|
231
|
+
private def user_to_context_kind(user)
|
232
|
+
(user.nil? || !user[:anonymous]) ? 'user' : 'anonymousUser'
|
233
|
+
end
|
173
234
|
end
|
174
235
|
|
175
236
|
# @private
|
@@ -209,8 +270,6 @@ module LaunchDarkly
|
|
209
270
|
begin
|
210
271
|
message = inbox.pop
|
211
272
|
case message
|
212
|
-
when EventMessage
|
213
|
-
dispatch_event(message.event, outbox)
|
214
273
|
when FlushMessage
|
215
274
|
trigger_flush(outbox, flush_workers)
|
216
275
|
when FlushUsersMessage
|
@@ -224,6 +283,8 @@ module LaunchDarkly
|
|
224
283
|
do_shutdown(flush_workers, diagnostic_event_workers)
|
225
284
|
running = false
|
226
285
|
message.completed
|
286
|
+
else
|
287
|
+
dispatch_event(message, outbox)
|
227
288
|
end
|
228
289
|
rescue => e
|
229
290
|
Util.log_exception(@config.logger, "Unexpected error in event processor", e)
|
@@ -257,11 +318,10 @@ module LaunchDarkly
|
|
257
318
|
# the event (if tracked) and once for debugging.
|
258
319
|
will_add_full_event = false
|
259
320
|
debug_event = nil
|
260
|
-
if event
|
261
|
-
will_add_full_event = event
|
321
|
+
if event.is_a?(LaunchDarkly::Impl::EvalEvent)
|
322
|
+
will_add_full_event = event.track_events
|
262
323
|
if should_debug_event(event)
|
263
|
-
debug_event = event
|
264
|
-
debug_event[:debug] = true
|
324
|
+
debug_event = LaunchDarkly::Impl::DebugEvent.new(event)
|
265
325
|
end
|
266
326
|
else
|
267
327
|
will_add_full_event = true
|
@@ -270,12 +330,8 @@ module LaunchDarkly
|
|
270
330
|
# For each user we haven't seen before, we add an index event - unless this is already
|
271
331
|
# an identify event for that user.
|
272
332
|
if !(will_add_full_event && @config.inline_users_in_events)
|
273
|
-
if event.
|
274
|
-
outbox.add_event(
|
275
|
-
kind: "index",
|
276
|
-
creationDate: event[:creationDate],
|
277
|
-
user: event[:user]
|
278
|
-
})
|
333
|
+
if !event.user.nil? && !notice_user(event.user) && !event.is_a?(LaunchDarkly::Impl::IdentifyEvent)
|
334
|
+
outbox.add_event(LaunchDarkly::Impl::IndexEvent.new(event.timestamp, event.user))
|
279
335
|
end
|
280
336
|
end
|
281
337
|
|
@@ -295,7 +351,7 @@ module LaunchDarkly
|
|
295
351
|
end
|
296
352
|
|
297
353
|
def should_debug_event(event)
|
298
|
-
debug_until = event
|
354
|
+
debug_until = event.debug_until
|
299
355
|
if !debug_until.nil?
|
300
356
|
last_past = @last_known_past_time.value
|
301
357
|
debug_until > last_past && debug_until > Impl::Util.current_time_millis
|
@@ -365,12 +421,11 @@ module LaunchDarkly
|
|
365
421
|
@capacity_exceeded = false
|
366
422
|
@dropped_events = 0
|
367
423
|
@events = []
|
368
|
-
@summarizer = EventSummarizer.new
|
424
|
+
@summarizer = LaunchDarkly::Impl::EventSummarizer.new
|
369
425
|
end
|
370
426
|
|
371
427
|
def add_event(event)
|
372
428
|
if @events.length < @capacity
|
373
|
-
@logger.debug { "[LDClient] Enqueueing event: #{event.to_json}" }
|
374
429
|
@events.push(event)
|
375
430
|
@capacity_exceeded = false
|
376
431
|
else
|
@@ -404,6 +459,15 @@ module LaunchDarkly
|
|
404
459
|
|
405
460
|
# @private
|
406
461
|
class EventOutputFormatter
|
462
|
+
FEATURE_KIND = 'feature'
|
463
|
+
IDENTIFY_KIND = 'identify'
|
464
|
+
CUSTOM_KIND = 'custom'
|
465
|
+
ALIAS_KIND = 'alias'
|
466
|
+
INDEX_KIND = 'index'
|
467
|
+
DEBUG_KIND = 'debug'
|
468
|
+
SUMMARY_KIND = 'summary'
|
469
|
+
ANONYMOUS_USER_CONTEXT_KIND = 'anonymousUser'
|
470
|
+
|
407
471
|
def initialize(config)
|
408
472
|
@inline_users = config.inline_users_in_events
|
409
473
|
@user_filter = UserFilter.new(config)
|
@@ -418,100 +482,130 @@ module LaunchDarkly
|
|
418
482
|
events_out
|
419
483
|
end
|
420
484
|
|
421
|
-
private
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
Util.stringify_attrs(filtered, USER_ATTRS_TO_STRINGIFY_FOR_EVENTS)
|
426
|
-
end
|
427
|
-
|
428
|
-
def make_output_event(event)
|
429
|
-
case event[:kind]
|
430
|
-
when "feature"
|
431
|
-
is_debug = event[:debug]
|
485
|
+
private def make_output_event(event)
|
486
|
+
case event
|
487
|
+
|
488
|
+
when LaunchDarkly::Impl::EvalEvent
|
432
489
|
out = {
|
433
|
-
kind:
|
434
|
-
creationDate: event
|
435
|
-
key: event
|
436
|
-
value: event
|
490
|
+
kind: FEATURE_KIND,
|
491
|
+
creationDate: event.timestamp,
|
492
|
+
key: event.key,
|
493
|
+
value: event.value
|
437
494
|
}
|
438
|
-
out[:default] = event
|
439
|
-
out[:variation] = event
|
440
|
-
out[:version] = event
|
441
|
-
out[:prereqOf] = event
|
442
|
-
out
|
443
|
-
|
444
|
-
|
445
|
-
else
|
446
|
-
out[:userKey] = event[:user][:key]
|
447
|
-
end
|
448
|
-
out[:reason] = event[:reason] if !event[:reason].nil?
|
495
|
+
out[:default] = event.default if !event.default.nil?
|
496
|
+
out[:variation] = event.variation if !event.variation.nil?
|
497
|
+
out[:version] = event.version if !event.version.nil?
|
498
|
+
out[:prereqOf] = event.prereq_of if !event.prereq_of.nil?
|
499
|
+
set_opt_context_kind(out, event.user)
|
500
|
+
set_user_or_user_key(out, event.user)
|
501
|
+
out[:reason] = event.reason if !event.reason.nil?
|
449
502
|
out
|
450
|
-
|
503
|
+
|
504
|
+
when LaunchDarkly::Impl::IdentifyEvent
|
451
505
|
{
|
452
|
-
kind:
|
453
|
-
creationDate: event
|
454
|
-
key: event
|
455
|
-
user: process_user(event)
|
506
|
+
kind: IDENTIFY_KIND,
|
507
|
+
creationDate: event.timestamp,
|
508
|
+
key: event.user[:key].to_s,
|
509
|
+
user: process_user(event.user)
|
456
510
|
}
|
457
|
-
|
511
|
+
|
512
|
+
when LaunchDarkly::Impl::CustomEvent
|
458
513
|
out = {
|
459
|
-
kind:
|
460
|
-
creationDate: event
|
461
|
-
key: event
|
514
|
+
kind: CUSTOM_KIND,
|
515
|
+
creationDate: event.timestamp,
|
516
|
+
key: event.key
|
462
517
|
}
|
463
|
-
out[:data] = event
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
out[:userKey] = event[:user][:key]
|
468
|
-
end
|
469
|
-
out[:metricValue] = event[:metricValue] if event.has_key?(:metricValue)
|
470
|
-
out[:contextKind] = event[:contextKind] if event.has_key?(:contextKind)
|
518
|
+
out[:data] = event.data if !event.data.nil?
|
519
|
+
set_user_or_user_key(out, event.user)
|
520
|
+
out[:metricValue] = event.metric_value if !event.metric_value.nil?
|
521
|
+
set_opt_context_kind(out, event.user)
|
471
522
|
out
|
472
|
-
|
523
|
+
|
524
|
+
when LaunchDarkly::Impl::AliasEvent
|
525
|
+
{
|
526
|
+
kind: ALIAS_KIND,
|
527
|
+
creationDate: event.timestamp,
|
528
|
+
key: event.key,
|
529
|
+
contextKind: event.context_kind,
|
530
|
+
previousKey: event.previous_key,
|
531
|
+
previousContextKind: event.previous_context_kind
|
532
|
+
}
|
533
|
+
|
534
|
+
when LaunchDarkly::Impl::IndexEvent
|
473
535
|
{
|
474
|
-
kind:
|
475
|
-
creationDate: event
|
476
|
-
user: process_user(event)
|
536
|
+
kind: INDEX_KIND,
|
537
|
+
creationDate: event.timestamp,
|
538
|
+
user: process_user(event.user)
|
477
539
|
}
|
540
|
+
|
541
|
+
when LaunchDarkly::Impl::DebugEvent
|
542
|
+
original = event.eval_event
|
543
|
+
out = {
|
544
|
+
kind: DEBUG_KIND,
|
545
|
+
creationDate: original.timestamp,
|
546
|
+
key: original.key,
|
547
|
+
user: process_user(original.user),
|
548
|
+
value: original.value
|
549
|
+
}
|
550
|
+
out[:default] = original.default if !original.default.nil?
|
551
|
+
out[:variation] = original.variation if !original.variation.nil?
|
552
|
+
out[:version] = original.version if !original.version.nil?
|
553
|
+
out[:prereqOf] = original.prereq_of if !original.prereq_of.nil?
|
554
|
+
set_opt_context_kind(out, original.user)
|
555
|
+
out[:reason] = original.reason if !original.reason.nil?
|
556
|
+
out
|
557
|
+
|
478
558
|
else
|
479
|
-
|
559
|
+
nil
|
480
560
|
end
|
481
561
|
end
|
482
562
|
|
483
563
|
# Transforms the summary data into the format used for event sending.
|
484
|
-
def make_summary_event(summary)
|
564
|
+
private def make_summary_event(summary)
|
485
565
|
flags = {}
|
486
|
-
summary
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
if ckey[:version].nil?
|
503
|
-
c[:unknown] = true
|
504
|
-
else
|
505
|
-
c[:version] = ckey[:version]
|
566
|
+
summary.counters.each do |flagKey, flagInfo|
|
567
|
+
counters = []
|
568
|
+
flagInfo.versions.each do |version, variations|
|
569
|
+
variations.each do |variation, counter|
|
570
|
+
c = {
|
571
|
+
value: counter.value,
|
572
|
+
count: counter.count
|
573
|
+
}
|
574
|
+
c[:variation] = variation if !variation.nil?
|
575
|
+
if version.nil?
|
576
|
+
c[:unknown] = true
|
577
|
+
else
|
578
|
+
c[:version] = version
|
579
|
+
end
|
580
|
+
counters.push(c)
|
581
|
+
end
|
506
582
|
end
|
507
|
-
|
508
|
-
|
583
|
+
flags[flagKey] = { default: flagInfo.default, counters: counters }
|
584
|
+
end
|
509
585
|
{
|
510
|
-
kind:
|
586
|
+
kind: SUMMARY_KIND,
|
511
587
|
startDate: summary[:start_date],
|
512
588
|
endDate: summary[:end_date],
|
513
589
|
features: flags
|
514
590
|
}
|
515
591
|
end
|
592
|
+
|
593
|
+
private def set_opt_context_kind(out, user)
|
594
|
+
out[:contextKind] = ANONYMOUS_USER_CONTEXT_KIND if !user.nil? && user[:anonymous]
|
595
|
+
end
|
596
|
+
|
597
|
+
private def set_user_or_user_key(out, user)
|
598
|
+
if @inline_users
|
599
|
+
out[:user] = process_user(user)
|
600
|
+
else
|
601
|
+
key = user[:key]
|
602
|
+
out[:userKey] = key.is_a?(String) ? key : key.to_s
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
private def process_user(user)
|
607
|
+
filtered = @user_filter.transform_user_props(user)
|
608
|
+
Util.stringify_attrs(filtered, USER_ATTRS_TO_STRINGIFY_FOR_EVENTS)
|
609
|
+
end
|
516
610
|
end
|
517
611
|
end
|
@@ -16,21 +16,32 @@ module LaunchDarkly
|
|
16
16
|
|
17
17
|
# Used internally to build the state map.
|
18
18
|
# @private
|
19
|
-
def add_flag(
|
20
|
-
key =
|
21
|
-
@flag_values[key] = value
|
19
|
+
def add_flag(flag_state, with_reasons, details_only_if_tracked)
|
20
|
+
key = flag_state[:key]
|
21
|
+
@flag_values[key] = flag_state[:value]
|
22
22
|
meta = {}
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
|
24
|
+
omit_details = false
|
25
|
+
if details_only_if_tracked
|
26
|
+
if !flag_state[:trackEvents] && !flag_state[:trackReason] && !(flag_state[:debugEventsUntilDate] && flag_state[:debugEventsUntilDate] > Impl::Util::current_time_millis)
|
27
|
+
omit_details = true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
reason = (!with_reasons and !flag_state[:trackReason]) ? nil : flag_state[:reason]
|
32
|
+
|
33
|
+
if !reason.nil? && !omit_details
|
34
|
+
meta[:reason] = reason
|
26
35
|
end
|
27
|
-
|
28
|
-
|
29
|
-
meta[:
|
36
|
+
|
37
|
+
if !omit_details
|
38
|
+
meta[:version] = flag_state[:version]
|
30
39
|
end
|
31
|
-
|
32
|
-
meta[:
|
33
|
-
meta[:
|
40
|
+
|
41
|
+
meta[:variation] = flag_state[:variation] if !flag_state[:variation].nil?
|
42
|
+
meta[:trackEvents] = true if flag_state[:trackEvents]
|
43
|
+
meta[:trackReason] = true if flag_state[:trackReason]
|
44
|
+
meta[:debugEventsUntilDate] = flag_state[:debugEventsUntilDate] if flag_state[:debugEventsUntilDate]
|
34
45
|
@flag_metadata[key] = meta
|
35
46
|
end
|
36
47
|
|
@@ -4,6 +4,13 @@ require "ldclient-rb/impl/evaluator_operators"
|
|
4
4
|
|
5
5
|
module LaunchDarkly
|
6
6
|
module Impl
|
7
|
+
# Used internally to record that we evaluated a prerequisite flag.
|
8
|
+
PrerequisiteEvalRecord = Struct.new(
|
9
|
+
:prereq_flag, # the prerequisite flag that we evaluated
|
10
|
+
:prereq_of_flag, # the flag that it was a prerequisite of
|
11
|
+
:detail # the EvaluationDetail representing the evaluation result
|
12
|
+
)
|
13
|
+
|
7
14
|
# Encapsulates the feature flag evaluation logic. The Evaluator has no knowledge of the rest of the SDK environment;
|
8
15
|
# if it needs to retrieve flags or segments that are referenced by a flag, it does so through a simple function that
|
9
16
|
# is provided in the constructor. It also produces feature requests as appropriate for any referenced prerequisite
|
@@ -22,7 +29,7 @@ module LaunchDarkly
|
|
22
29
|
@get_big_segments_membership = get_big_segments_membership
|
23
30
|
@logger = logger
|
24
31
|
end
|
25
|
-
|
32
|
+
|
26
33
|
# Used internally to hold an evaluation result and additional state that may be accumulated during an
|
27
34
|
# evaluation. It's simpler and a bit more efficient to represent these as mutable properties rather than
|
28
35
|
# trying to use a pure functional approach, and since we're not exposing this object to any application code
|
@@ -34,7 +41,7 @@ module LaunchDarkly
|
|
34
41
|
# evaluation.
|
35
42
|
EvalResult = Struct.new(
|
36
43
|
:detail, # the EvaluationDetail representing the evaluation result
|
37
|
-
:
|
44
|
+
:prereq_evals, # an array of PrerequisiteEvalRecord instances, or nil
|
38
45
|
:big_segments_status,
|
39
46
|
:big_segments_membership
|
40
47
|
)
|
@@ -50,17 +57,15 @@ module LaunchDarkly
|
|
50
57
|
#
|
51
58
|
# @param flag [Object] the flag
|
52
59
|
# @param user [Object] the user properties
|
53
|
-
# @param event_factory [EventFactory] called to construct a feature request event when a prerequisite flag is
|
54
|
-
# evaluated; the caller is responsible for constructing the feature event for the top-level evaluation
|
55
60
|
# @return [EvalResult] the evaluation result
|
56
|
-
def evaluate(flag, user
|
61
|
+
def evaluate(flag, user)
|
57
62
|
result = EvalResult.new
|
58
63
|
if user.nil? || user[:key].nil?
|
59
64
|
result.detail = Evaluator.error_result(EvaluationReason::ERROR_USER_NOT_SPECIFIED)
|
60
65
|
return result
|
61
66
|
end
|
62
67
|
|
63
|
-
detail = eval_internal(flag, user, result
|
68
|
+
detail = eval_internal(flag, user, result)
|
64
69
|
if !result.big_segments_status.nil?
|
65
70
|
# If big_segments_status is non-nil at the end of the evaluation, it means a query was done at
|
66
71
|
# some point and we will want to include the status in the evaluation reason.
|
@@ -80,12 +85,12 @@ module LaunchDarkly
|
|
80
85
|
|
81
86
|
private
|
82
87
|
|
83
|
-
def eval_internal(flag, user, state
|
88
|
+
def eval_internal(flag, user, state)
|
84
89
|
if !flag[:on]
|
85
90
|
return get_off_value(flag, EvaluationReason::off)
|
86
91
|
end
|
87
92
|
|
88
|
-
prereq_failure_reason = check_prerequisites(flag, user, state
|
93
|
+
prereq_failure_reason = check_prerequisites(flag, user, state)
|
89
94
|
if !prereq_failure_reason.nil?
|
90
95
|
return get_off_value(flag, prereq_failure_reason)
|
91
96
|
end
|
@@ -118,7 +123,7 @@ module LaunchDarkly
|
|
118
123
|
return EvaluationDetail.new(nil, nil, EvaluationReason::fallthrough)
|
119
124
|
end
|
120
125
|
|
121
|
-
def check_prerequisites(flag, user, state
|
126
|
+
def check_prerequisites(flag, user, state)
|
122
127
|
(flag[:prerequisites] || []).each do |prerequisite|
|
123
128
|
prereq_ok = true
|
124
129
|
prereq_key = prerequisite[:key]
|
@@ -129,15 +134,15 @@ module LaunchDarkly
|
|
129
134
|
prereq_ok = false
|
130
135
|
else
|
131
136
|
begin
|
132
|
-
prereq_res = eval_internal(prereq_flag, user, state
|
137
|
+
prereq_res = eval_internal(prereq_flag, user, state)
|
133
138
|
# Note that if the prerequisite flag is off, we don't consider it a match no matter what its
|
134
139
|
# off variation was. But we still need to evaluate it in order to generate an event.
|
135
140
|
if !prereq_flag[:on] || prereq_res.variation_index != prerequisite[:variation]
|
136
141
|
prereq_ok = false
|
137
142
|
end
|
138
|
-
|
139
|
-
state.
|
140
|
-
state.
|
143
|
+
prereq_eval = PrerequisiteEvalRecord.new(prereq_flag, flag, prereq_res)
|
144
|
+
state.prereq_evals = [] if state.prereq_evals.nil?
|
145
|
+
state.prereq_evals.push(prereq_eval)
|
141
146
|
rescue => exn
|
142
147
|
Util.log_exception(@logger, "Error evaluating prerequisite flag \"#{prereq_key}\" for flag \"#{flag[:key]}\"", exn)
|
143
148
|
prereq_ok = false
|
@@ -89,7 +89,7 @@ module LaunchDarkly
|
|
89
89
|
|
90
90
|
private
|
91
91
|
|
92
|
-
BUILTINS = Set[:key, :ip, :country, :email, :firstName, :lastName, :avatar, :name, :anonymous]
|
92
|
+
BUILTINS = Set[:key, :secondary, :ip, :country, :email, :firstName, :lastName, :avatar, :name, :anonymous]
|
93
93
|
NUMERIC_VERSION_COMPONENTS_REGEX = Regexp.new("^[0-9.]*")
|
94
94
|
|
95
95
|
private_constant :BUILTINS
|