@@ -27,6 +27,7 @@ var ERROR_MESSAGES = enums.ERROR_MESSAGES;
27
27
var LOG_LEVEL = enums . LOG_LEVEL ;
28
28
var LOG_MESSAGES = enums . LOG_MESSAGES ;
29
29
var DECISION_SOURCES = enums . DECISION_SOURCES ;
30
+ var AUDIENCE_EVALUATION_TYPES = enums . AUDIENCE_EVALUATION_TYPES ;
30
31
31
32
/**
32
33
* Optimizely's decision service that determines which variation of an experiment the user will be allocated to.
@@ -90,17 +91,39 @@ DecisionService.prototype.getVariation = function(configObj, experimentKey, user
90
91
}
91
92
92
93
// Perform regular targeting and bucketing
93
- if ( ! this . __checkIfUserIsInAudience ( configObj , experimentKey , userId , attributes ) ) {
94
+ if ( ! this . __checkIfUserIsInAudience ( configObj , experimentKey , AUDIENCE_EVALUATION_TYPES . EXPERIMENT , userId , attributes , '' ) ) {
95
+ var userDoesNotMeetConditionsLogMessage = sprintf (
96
+ LOG_MESSAGES . USER_NOT_IN_EXPERIMENT ,
97
+ MODULE_NAME ,
98
+ userId ,
99
+ experimentKey
100
+ ) ;
101
+ this . logger . log ( LOG_LEVEL . INFO , userDoesNotMeetConditionsLogMessage ) ;
94
102
return null ;
95
103
}
96
104
97
105
var bucketerParams = this . __buildBucketerParams ( configObj , experimentKey , bucketingId , userId ) ;
98
106
var variationId = bucketer . bucket ( bucketerParams ) ;
99
107
variation = configObj . variationIdMap [ variationId ] ;
100
108
if ( ! variation ) {
109
+ var userHasNoVariationLogMessage = sprintf (
110
+ LOG_MESSAGES . USER_HAS_NO_VARIATION ,
111
+ MODULE_NAME ,
112
+ userId ,
113
+ experimentKey
114
+ ) ;
115
+ this . logger . log ( LOG_LEVEL . DEBUG , userHasNoVariationLogMessage ) ;
101
116
return null ;
102
117
}
103
118
119
+ var userInVariationLogMessage = sprintf (
120
+ LOG_MESSAGES . USER_HAS_VARIATION ,
121
+ MODULE_NAME ,
122
+ userId ,
123
+ variation . key ,
124
+ experimentKey
125
+ ) ;
126
+ this . logger . log ( LOG_LEVEL . INFO , userInVariationLogMessage ) ;
104
127
// persist bucketing
105
128
this . __saveUserProfile ( experiment , variation , userId , experimentBucketMap ) ;
106
129
@@ -171,21 +194,24 @@ DecisionService.prototype.__getWhitelistedVariation = function(experiment, userI
171
194
172
195
/**
173
196
* Checks whether the user is included in experiment audience
174
- * @param {Object } configObj The parsed project configuration object
175
- * @param {string } experimentKey Key of experiment being validated
176
- * @param {string } userId ID of user
177
- * @param {Object } attributes Optional parameter for user's attributes
197
+ * @param {Object } configObj The parsed project configuration object
198
+ * @param {string } experimentKey Key of experiment being validated
199
+ * @param {string } evaluationAttribute String representing experiment key or rule
200
+ * @param {string } userId ID of user
201
+ * @param {Object } attributes Optional parameter for user's attributes
202
+ * @param {string } loggingKey String representing experiment key or rollout rule. To be used in log messages only.
178
203
* @return {boolean } True if user meets audience conditions
179
204
*/
180
- DecisionService . prototype . __checkIfUserIsInAudience = function ( configObj , experimentKey , userId , attributes ) {
205
+ DecisionService . prototype . __checkIfUserIsInAudience = function ( configObj , experimentKey , evaluationAttribute , userId , attributes , loggingKey ) {
181
206
var experimentAudienceConditions = projectConfig . getExperimentAudienceConditions ( configObj , experimentKey ) ;
182
207
var audiencesById = projectConfig . getAudiencesById ( configObj ) ;
183
208
this . logger . log (
184
209
LOG_LEVEL . DEBUG ,
185
210
sprintf (
186
211
LOG_MESSAGES . EVALUATING_AUDIENCES_COMBINED ,
187
212
MODULE_NAME ,
188
- experimentKey ,
213
+ evaluationAttribute ,
214
+ loggingKey || experimentKey ,
189
215
JSON . stringify ( experimentAudienceConditions )
190
216
)
191
217
) ;
@@ -195,23 +221,13 @@ DecisionService.prototype.__checkIfUserIsInAudience = function(configObj, experi
195
221
sprintf (
196
222
LOG_MESSAGES . AUDIENCE_EVALUATION_RESULT_COMBINED ,
197
223
MODULE_NAME ,
198
- experimentKey ,
224
+ evaluationAttribute ,
225
+ loggingKey || experimentKey ,
199
226
result . toString ( ) . toUpperCase ( )
200
227
)
201
228
) ;
202
229
203
- if ( ! result ) {
204
- var userDoesNotMeetConditionsLogMessage = sprintf (
205
- LOG_MESSAGES . USER_NOT_IN_EXPERIMENT ,
206
- MODULE_NAME ,
207
- userId ,
208
- experimentKey
209
- ) ;
210
- this . logger . log ( LOG_LEVEL . INFO , userDoesNotMeetConditionsLogMessage ) ;
211
- return false ;
212
- }
213
-
214
- return true ;
230
+ return result ;
215
231
} ;
216
232
217
233
/**
@@ -335,25 +351,9 @@ DecisionService.prototype.__saveUserProfile = function(experiment, variation, us
335
351
DecisionService . prototype . getVariationForFeature = function ( configObj , feature , userId , attributes ) {
336
352
var experimentDecision = this . _getVariationForFeatureExperiment ( configObj , feature , userId , attributes ) ;
337
353
if ( experimentDecision . variation !== null ) {
338
- this . logger . log (
339
- LOG_LEVEL . DEBUG ,
340
- sprintf (
341
- LOG_MESSAGES . USER_IN_FEATURE_EXPERIMENT ,
342
- MODULE_NAME ,
343
- userId ,
344
- experimentDecision . variation . key ,
345
- experimentDecision . experiment . key ,
346
- feature . key
347
- )
348
- ) ;
349
354
return experimentDecision ;
350
355
}
351
356
352
- this . logger . log (
353
- LOG_LEVEL . DEBUG ,
354
- sprintf ( LOG_MESSAGES . USER_NOT_IN_FEATURE_EXPERIMENT , MODULE_NAME , userId , feature . key )
355
- ) ;
356
-
357
357
var rolloutDecision = this . _getVariationForRollout ( configObj , feature , userId , attributes ) ;
358
358
if ( rolloutDecision . variation !== null ) {
359
359
this . logger . log ( LOG_LEVEL . DEBUG , sprintf ( LOG_MESSAGES . USER_IN_ROLLOUT , MODULE_NAME , userId , feature . key ) ) ;
@@ -456,50 +456,56 @@ DecisionService.prototype._getVariationForRollout = function(configObj, feature,
456
456
// "everyone else", which will be evaluated separately outside this loop
457
457
var endIndex = rollout . experiments . length - 1 ;
458
458
var index ;
459
- var experiment ;
459
+ var rolloutRule ;
460
460
var bucketerParams ;
461
461
var variationId ;
462
462
var variation ;
463
+ var loggingKey ;
463
464
for ( index = 0 ; index < endIndex ; index ++ ) {
464
- experiment = configObj . experimentKeyMap [ rollout . experiments [ index ] . key ] ;
465
+ rolloutRule = configObj . experimentKeyMap [ rollout . experiments [ index ] . key ] ;
466
+ loggingKey = index + 1 ;
465
467
466
- if ( ! this . __checkIfUserIsInAudience ( configObj , experiment . key , userId , attributes ) ) {
468
+ if ( ! this . __checkIfUserIsInAudience ( configObj , rolloutRule . key , AUDIENCE_EVALUATION_TYPES . RULE , userId , attributes , loggingKey ) ) {
467
469
this . logger . log (
468
470
LOG_LEVEL . DEBUG ,
469
- sprintf ( LOG_MESSAGES . USER_DOESNT_MEET_CONDITIONS_FOR_TARGETING_RULE , MODULE_NAME , userId , index + 1 )
471
+ sprintf ( LOG_MESSAGES . USER_DOESNT_MEET_CONDITIONS_FOR_TARGETING_RULE , MODULE_NAME , userId , loggingKey )
470
472
) ;
471
473
continue ;
472
474
}
473
475
474
476
this . logger . log (
475
477
LOG_LEVEL . DEBUG ,
476
- sprintf ( LOG_MESSAGES . USER_MEETS_CONDITIONS_FOR_TARGETING_RULE , MODULE_NAME , userId , index + 1 )
478
+ sprintf ( LOG_MESSAGES . USER_MEETS_CONDITIONS_FOR_TARGETING_RULE , MODULE_NAME , userId , loggingKey )
477
479
) ;
478
- bucketerParams = this . __buildBucketerParams ( configObj , experiment . key , bucketingId , userId ) ;
480
+ bucketerParams = this . __buildBucketerParams ( configObj , rolloutRule . key , bucketingId , userId ) ;
479
481
variationId = bucketer . bucket ( bucketerParams ) ;
480
482
variation = configObj . variationIdMap [ variationId ] ;
481
483
if ( variation ) {
482
484
this . logger . log (
483
485
LOG_LEVEL . DEBUG ,
484
- sprintf ( LOG_MESSAGES . USER_BUCKETED_INTO_TARGETING_RULE , MODULE_NAME , userId , index + 1 )
486
+ sprintf ( LOG_MESSAGES . USER_BUCKETED_INTO_TARGETING_RULE , MODULE_NAME , userId , loggingKey )
485
487
) ;
486
488
return {
487
- experiment : experiment ,
489
+ experiment : rolloutRule ,
488
490
variation : variation ,
489
491
decisionSource : DECISION_SOURCES . ROLLOUT ,
490
492
} ;
491
493
} else {
492
494
this . logger . log (
493
495
LOG_LEVEL . DEBUG ,
494
- sprintf ( LOG_MESSAGES . USER_NOT_BUCKETED_INTO_TARGETING_RULE , MODULE_NAME , userId , index + 1 )
496
+ sprintf ( LOG_MESSAGES . USER_NOT_BUCKETED_INTO_TARGETING_RULE , MODULE_NAME , userId , loggingKey )
495
497
) ;
496
498
break ;
497
499
}
498
500
}
499
501
500
- var everyoneElseExperiment = configObj . experimentKeyMap [ rollout . experiments [ endIndex ] . key ] ;
501
- if ( this . __checkIfUserIsInAudience ( configObj , everyoneElseExperiment . key , userId , attributes ) ) {
502
- bucketerParams = this . __buildBucketerParams ( configObj , everyoneElseExperiment . key , bucketingId , userId ) ;
502
+ var everyoneElseRule = configObj . experimentKeyMap [ rollout . experiments [ endIndex ] . key ] ;
503
+ if ( this . __checkIfUserIsInAudience ( configObj , everyoneElseRule . key , AUDIENCE_EVALUATION_TYPES . RULE , userId , attributes , 'Everyone Else' ) ) {
504
+ this . logger . log (
505
+ LOG_LEVEL . DEBUG ,
506
+ sprintf ( LOG_MESSAGES . USER_MEETS_CONDITIONS_FOR_TARGETING_RULE , MODULE_NAME , userId , 'Everyone Else' )
507
+ ) ;
508
+ bucketerParams = this . __buildBucketerParams ( configObj , everyoneElseRule . key , bucketingId , userId ) ;
503
509
variationId = bucketer . bucket ( bucketerParams ) ;
504
510
variation = configObj . variationIdMap [ variationId ] ;
505
511
if ( variation ) {
@@ -508,7 +514,7 @@ DecisionService.prototype._getVariationForRollout = function(configObj, feature,
508
514
sprintf ( LOG_MESSAGES . USER_BUCKETED_INTO_EVERYONE_TARGETING_RULE , MODULE_NAME , userId )
509
515
) ;
510
516
return {
511
- experiment : everyoneElseExperiment ,
517
+ experiment : everyoneElseRule ,
512
518
variation : variation ,
513
519
decisionSource : DECISION_SOURCES . ROLLOUT ,
514
520
} ;
0 commit comments