1+ require "ldclient-rb/impl/event_factory"
12require "ldclient-rb/impl/store_client_wrapper"
23require "concurrent/atomics"
34require "digest/sha1"
@@ -13,6 +14,7 @@ module LaunchDarkly
1314 #
1415 class LDClient
1516 include Evaluation
17+ include Impl
1618 #
1719 # Creates a new client instance that connects to LaunchDarkly. A custom
1820 # configuration parameter can also supplied to specify advanced options,
@@ -32,6 +34,9 @@ class LDClient
3234 def initialize ( sdk_key , config = Config . default , wait_for_sec = 5 )
3335 @sdk_key = sdk_key
3436
37+ @event_factory_default = EventFactory . new ( false )
38+ @event_factory_with_reasons = EventFactory . new ( true )
39+
3540 # We need to wrap the feature store object with a FeatureStoreClientWrapper in order to add
3641 # some necessary logic around updates. Unfortunately, we have code elsewhere that accesses
3742 # the feature store through the Config object, so we need to make a new Config that uses
@@ -165,7 +170,7 @@ def initialized?
165170 # @return the variation to show the user, or the default value if there's an an error
166171 #
167172 def variation ( key , user , default )
168- evaluate_internal ( key , user , default , false ) . value
173+ evaluate_internal ( key , user , default , @event_factory_default ) . value
169174 end
170175
171176 #
@@ -192,7 +197,7 @@ def variation(key, user, default)
192197 # @return [EvaluationDetail] an object describing the result
193198 #
194199 def variation_detail ( key , user , default )
195- evaluate_internal ( key , user , default , true )
200+ evaluate_internal ( key , user , default , @event_factory_with_reasons )
196201 end
197202
198203 #
@@ -215,7 +220,8 @@ def identify(user)
215220 @config . logger . warn ( "Identify called with nil user or nil user key!" )
216221 return
217222 end
218- @event_processor . add_event ( kind : "identify" , key : user [ :key ] , user : user )
223+ sanitize_user ( user )
224+ @event_processor . add_event ( @event_factory_default . new_identify_event ( user ) )
219225 end
220226
221227 #
@@ -225,18 +231,28 @@ def identify(user)
225231 # Note that event delivery is asynchronous, so the event may not actually be sent
226232 # until later; see {#flush}.
227233 #
234+ # As of this version’s release date, the LaunchDarkly service does not support the `metricValue`
235+ # parameter. As a result, specifying `metricValue` will not yet produce any different behavior
236+ # from omitting it. Refer to the [SDK reference guide](https://docs.launchdarkly.com/docs/ruby-sdk-reference#section-track)
237+ # for the latest status.
238+ #
228239 # @param event_name [String] The name of the event
229240 # @param user [Hash] The user to register; this can have all the same user properties
230241 # described in {#variation}
231- # @param data [Hash] A hash containing any additional data associated with the event
242+ # @param data [Hash] An optional hash containing any additional data associated with the event
243+ # @param metric_value [Number] A numeric value used by the LaunchDarkly experimentation
244+ # feature in numeric custom metrics. Can be omitted if this event is used by only
245+ # non-numeric metrics. This field will also be returned as part of the custom event
246+ # for Data Export.
232247 # @return [void]
233248 #
234- def track ( event_name , user , data )
249+ def track ( event_name , user , data = nil , metric_value = nil )
235250 if !user || user [ :key ] . nil?
236251 @config . logger . warn ( "Track called with nil user or nil user key!" )
237252 return
238253 end
239- @event_processor . add_event ( kind : "custom" , key : event_name , user : user , data : data )
254+ sanitize_user ( user )
255+ @event_processor . add_event ( @event_factory_default . new_custom_event ( event_name , user , data , metric_value ) )
240256 end
241257
242258 #
@@ -294,7 +310,7 @@ def all_flags_state(user, options={})
294310 next
295311 end
296312 begin
297- result = evaluate ( f , user , @store , @config . logger )
313+ result = evaluate ( f , user , @store , @config . logger , @event_factory_default )
298314 state . add_flag ( f , result . detail . value , result . detail . variation_index , with_reasons ? result . detail . reason : nil ,
299315 details_only_if_tracked )
300316 rescue => exn
@@ -334,7 +350,7 @@ def create_default_data_source(sdk_key, config)
334350 end
335351
336352 # @return [EvaluationDetail]
337- def evaluate_internal ( key , user , default , include_reasons_in_events )
353+ def evaluate_internal ( key , user , default , event_factory )
338354 if @config . offline?
339355 return error_result ( 'CLIENT_NOT_READY' , default )
340356 end
@@ -344,8 +360,9 @@ def evaluate_internal(key, user, default, include_reasons_in_events)
344360 @config . logger . warn { "[LDClient] Client has not finished initializing; using last known values from feature store" }
345361 else
346362 @config . logger . error { "[LDClient] Client has not finished initializing; feature store unavailable, returning default value" }
347- @event_processor . add_event ( kind : "feature" , key : key , value : default , default : default , user : user )
348- return error_result ( 'CLIENT_NOT_READY' , default )
363+ detail = error_result ( 'CLIENT_NOT_READY' , default )
364+ @event_processor . add_event ( event_factory . new_unknown_flag_event ( key , user , default , detail . reason ) )
365+ return detail
349366 end
350367 end
351368
@@ -354,20 +371,19 @@ def evaluate_internal(key, user, default, include_reasons_in_events)
354371 if feature . nil?
355372 @config . logger . info { "[LDClient] Unknown feature flag \" #{ key } \" . Returning default value" }
356373 detail = error_result ( 'FLAG_NOT_FOUND' , default )
357- @event_processor . add_event ( kind : "feature" , key : key , value : default , default : default , user : user ,
358- reason : include_reasons_in_events ? detail . reason : nil )
374+ @event_processor . add_event ( event_factory . new_unknown_flag_event ( key , user , default , detail . reason ) )
359375 return detail
360376 end
361377
362378 unless user
363379 @config . logger . error { "[LDClient] Must specify user" }
364380 detail = error_result ( 'USER_NOT_SPECIFIED' , default )
365- @event_processor . add_event ( make_feature_event ( feature , nil , detail , default , include_reasons_in_events ) )
381+ @event_processor . add_event ( event_factory . new_default_event ( feature , user , default , detail . reason ) )
366382 return detail
367383 end
368384
369385 begin
370- res = evaluate ( feature , user , @store , @config . logger ) # note, evaluate will do its own sanitization
386+ res = evaluate ( feature , user , @store , @config . logger , event_factory )
371387 if !res . events . nil?
372388 res . events . each do |event |
373389 @event_processor . add_event ( event )
@@ -377,29 +393,20 @@ def evaluate_internal(key, user, default, include_reasons_in_events)
377393 if detail . default_value?
378394 detail = EvaluationDetail . new ( default , nil , detail . reason )
379395 end
380- @event_processor . add_event ( make_feature_event ( feature , user , detail , default , include_reasons_in_events ) )
396+ @event_processor . add_event ( event_factory . new_eval_event ( feature , user , detail , default ) )
381397 return detail
382398 rescue => exn
383399 Util . log_exception ( @config . logger , "Error evaluating feature flag \" #{ key } \" " , exn )
384400 detail = error_result ( 'EXCEPTION' , default )
385- @event_processor . add_event ( make_feature_event ( feature , user , detail , default , include_reasons_in_events ) )
401+ @event_processor . add_event ( event_factory . new_default_event ( feature , user , default , detail . reason ) )
386402 return detail
387403 end
388404 end
389405
390- def make_feature_event ( flag , user , detail , default , with_reasons )
391- {
392- kind : "feature" ,
393- key : flag [ :key ] ,
394- user : user ,
395- variation : detail . variation_index ,
396- value : detail . value ,
397- default : default ,
398- version : flag [ :version ] ,
399- trackEvents : flag [ :trackEvents ] ,
400- debugEventsUntilDate : flag [ :debugEventsUntilDate ] ,
401- reason : with_reasons ? detail . reason : nil
402- }
406+ def sanitize_user ( user )
407+ if user [ :key ]
408+ user [ :key ] = user [ :key ] . to_s
409+ end
403410 end
404411 end
405412
0 commit comments