@@ -6,28 +6,198 @@ module Optimizely
66 class Event
77 # Representation of an event which can be sent to the Optimizely logging endpoint.
88
9- # Event API format
10- OFFLINE_API_PATH = 'https://%{project_id}.log.optimizely.com/event'
9+ attr_reader :http_verb
10+ attr_reader :params
11+ attr_reader :url
12+ attr_reader :headers
13+
14+ def initialize ( http_verb , url , params , headers )
15+ @http_verb = http_verb
16+ @url = url
17+ @params = params
18+ @headers = headers
19+ end
20+
21+ # Override equality operator to make two events with the same contents equal for testing purposes
22+ def ==( event )
23+ @http_verb == event . http_verb && @url == event . url && @params == event . params && @headers == event . headers
24+ end
25+ end
1126
12- # Gets/Sets event params.
27+ class BaseEventBuilder
28+ attr_reader :config
29+ attr_reader :bucketer
1330 attr_accessor :params
1431
15- def initialize ( params )
16- @params = params
32+ def initialize ( config , bucketer )
33+ @config = config
34+ @bucketer = bucketer
35+ @params = { }
1736 end
1837
19- def url
20- # URL for sending impression/conversion event.
38+ private
39+
40+ def add_common_params ( user_id , attributes )
41+ # Add params which are used in both conversion and impression events.
2142 #
22- # project_id - ID for the project.
43+ # user_id - ID for user.
44+ # attributes - Hash representing user attributes and values which need to be recorded.
45+
46+ add_project_id
47+ add_account_id
48+ add_user_id ( user_id )
49+ add_attributes ( attributes )
50+ add_source
51+ add_time
52+ end
53+ end
54+
55+ class EventBuilderV2 < BaseEventBuilder
56+ CONVERSION_EVENT_ENDPOINT = 'https://p13nlog.dz.optimizely.com/log/event'
57+ IMPRESSION_EVENT_ENDPOINT = 'https://p13nlog.dz.optimizely.com/log/decision'
58+ POST_HEADERS = { 'Content-Type' => 'application/json' }
59+
60+ def create_impression_event ( experiment_key , variation_id , user_id , attributes )
61+ # Create conversion Event to be sent to the logging endpoint.
62+ #
63+ # experiment_key - Experiment for which impression needs to be recorded.
64+ # variation_id - ID for variation which would be presented to user.
65+ # user_id - ID for user.
66+ # attributes - Hash representing user attributes and values which need to be recorded.
67+ #
68+ # Returns event hash encapsulating the impression event.
69+
70+ @params = { }
71+ add_common_params ( user_id , attributes )
72+ add_decision ( experiment_key , variation_id )
73+ add_attributes ( attributes )
74+ Event . new ( :post , IMPRESSION_EVENT_ENDPOINT , @params , POST_HEADERS )
75+ end
76+
77+ def create_conversion_event ( event_key , user_id , attributes , event_value , experiment_keys )
78+ # Create conversion Event to be sent to the logging endpoint.
79+ #
80+ # event_key - Event key representing the event which needs to be recorded.
81+ # user_id - ID for user.
82+ # attributes - Hash representing user attributes and values which need to be recorded.
83+ # event_value - Value associated with the event. Can be used to represent revenue in cents.
84+ # experiment_keys - Array of valid experiment keys for the event
85+ #
86+ # Returns event hash encapsulating the conversion event.
87+
88+ @params = { }
89+ add_common_params ( user_id , attributes )
90+ add_conversion_event ( event_key , event_value )
91+ add_layer_states ( user_id , experiment_keys )
92+ Event . new ( :post , CONVERSION_EVENT_ENDPOINT , @params , POST_HEADERS )
93+ end
94+
95+ private
96+
97+ def add_common_params ( user_id , attributes )
98+ super
99+ @params [ 'isGlobalHoldback' ] = false
100+ end
101+
102+ def add_project_id
103+ @params [ 'projectId' ] = @config . project_id
104+ end
105+
106+ def add_account_id
107+ @params [ 'accountId' ] = @config . account_id
108+ end
109+
110+ def add_user_id ( user_id )
111+ @params [ 'visitorId' ] = user_id
112+ end
113+
114+ def add_attributes ( attributes )
115+ @params [ 'userFeatures' ] = [ ]
116+
117+ return if attributes . nil?
118+
119+ attributes . keys . each do |attribute_key |
120+ # Omit falsy attribute values
121+ attribute_value = attributes [ attribute_key ]
122+ next unless attribute_value
123+
124+ # Skip attributes not in the datafile
125+ attribute_id = @config . get_attribute_id ( attribute_key )
126+ next unless attribute_id
127+
128+ feature = {
129+ 'id' => attribute_id ,
130+ 'name' => attribute_key ,
131+ 'type' => 'custom' ,
132+ 'value' => attribute_value ,
133+ 'shouldIndex' => true ,
134+ }
135+ @params [ 'userFeatures' ] . push ( feature )
136+ end
137+ end
138+
139+ def add_decision ( experiment_key , variation_id )
140+ experiment_id = @config . get_experiment_id ( experiment_key )
141+ @params [ 'layerId' ] = @config . experiment_key_map [ experiment_key ] [ 'layerId' ]
142+ @params [ 'decision' ] = {
143+ 'variationId' => variation_id ,
144+ 'experimentId' => experiment_id ,
145+ 'isLayerHoldback' => false ,
146+ }
147+ end
148+
149+ def add_conversion_event ( event_key , event_value )
150+ # Add conversion event information to the event.
23151 #
24- # Returns URL for event API.
152+ # event_key - Event key representing the event which needs to be recorded.
153+ # event_value - Value associated with the event. Can be used to represent revenue in cents.
154+
155+ event_id = @config . event_key_map [ event_key ] [ 'id' ]
156+ event_name = @config . event_key_map [ event_key ] [ 'key' ]
157+
158+ @params [ 'eventEntityId' ] = event_id
159+ @params [ 'eventFeatures' ] = [ ]
160+ @params [ 'eventName' ] = event_name
161+ @params [ 'eventMetrics' ] = [ ]
25162
26- sprintf ( OFFLINE_API_PATH , project_id : @params [ Params ::PROJECT_ID ] )
163+ if event_value
164+ @params [ 'eventMetrics' ] . push ( {
165+ 'name' => 'revenue' ,
166+ 'value' => event_value ,
167+ } )
168+ end
169+ end
170+
171+ def add_layer_states ( user_id , experiment_keys )
172+ @params [ 'layerStates' ] = [ ]
173+
174+ experiment_keys . each do |experiment_key |
175+ variation_id = @bucketer . bucket ( experiment_key , user_id )
176+ experiment_id = @config . experiment_key_map [ experiment_key ] [ 'id' ]
177+ layer_state = {
178+ 'layerId' => @config . experiment_key_map [ experiment_key ] [ 'layerId' ] ,
179+ 'decision' => {
180+ 'variationId' => variation_id ,
181+ 'experimentId' => experiment_id ,
182+ 'isLayerHoldback' => false ,
183+ } ,
184+ 'actionTriggered' => true ,
185+ }
186+ @params [ 'layerStates' ] . push ( layer_state )
187+ end
188+ end
189+
190+ def add_source
191+ @params [ 'clientEngine' ] = 'ruby-sdk'
192+ @params [ 'clientVersion' ] = VERSION
193+ end
194+
195+ def add_time
196+ @params [ 'timestamp' ] = ( Time . now . to_f * 1000 ) . to_i
27197 end
28198 end
29199
30- class EventBuilder
200+ class EventBuilderV1 < BaseEventBuilder
31201 # Class which encapsulates methods to build events for tracking impressions and conversions.
32202
33203 # Attribute mapping format
@@ -36,15 +206,8 @@ class EventBuilder
36206 # Experiment mapping format
37207 EXPERIMENT_PARAM_FORMAT = '%{experiment_prefix}%{experiment_id}'
38208
39- attr_accessor :config
40- attr_accessor :bucketer
41- attr_accessor :params
42-
43- def initialize ( config , bucketer )
44- @config = config
45- @bucketer = bucketer
46- @params = { }
47- end
209+ # Event endpoint path
210+ OFFLINE_API_PATH = 'https://%{project_id}.log.optimizely.com/event'
48211
49212 def create_impression_event ( experiment_key , variation_id , user_id , attributes )
50213 # Create conversion Event to be sent to the logging endpoint.
@@ -60,7 +223,7 @@ def create_impression_event(experiment_key, variation_id, user_id, attributes)
60223 add_common_params ( user_id , attributes )
61224 add_impression_goal ( experiment_key )
62225 add_experiment ( experiment_key , variation_id )
63- Event . new ( @params )
226+ Event . new ( :get , sprintf ( OFFLINE_API_PATH , project_id : @params [ Params :: PROJECT_ID ] ) , @params , { } )
64227 end
65228
66229 def create_conversion_event ( event_key , user_id , attributes , event_value , experiment_keys )
@@ -71,12 +234,14 @@ def create_conversion_event(event_key, user_id, attributes, event_value, experim
71234 # attributes - Hash representing user attributes and values which need to be recorded.
72235 # event_value - Value associated with the event. Can be used to represent revenue in cents.
73236 # experiment_keys - Array of valid experiment keys for the goal
237+ #
238+ # Returns event hash encapsulating the conversion event.
74239
75240 @params = { }
76241 add_common_params ( user_id , attributes )
77242 add_conversion_goal ( event_key , event_value )
78243 add_experiment_variation_params ( user_id , experiment_keys )
79- Event . new ( @params )
244+ Event . new ( :get , sprintf ( OFFLINE_API_PATH , project_id : @params [ Params :: PROJECT_ID ] ) , @params , { } )
80245 end
81246
82247 private
@@ -128,20 +293,6 @@ def add_time
128293 @params [ Params ::TIME ] = Time . now . strftime ( '%s' ) . to_i
129294 end
130295
131- def add_common_params ( user_id , attributes )
132- # Add params which are used same in both conversion and impression events.
133- #
134- # user_id - ID for user.
135- # attributes - Hash representing user attributes and values which need to be recorded.
136-
137- add_project_id
138- add_account_id
139- add_user_id ( user_id )
140- add_attributes ( attributes )
141- add_source
142- add_time
143- end
144-
145296 def add_impression_goal ( experiment_key )
146297 # Add impression goal information to the event.
147298 #
0 commit comments