Skip to content

fix(logs): Fixing log messages for Targeted Rollouts and feature variable evaluation. #337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Sources/Data Model/Group.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/****************************************************************************
* Copyright 2019, Optimizely, Inc. and contributors *
* Copyright 2019-2020, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
Expand Down Expand Up @@ -32,7 +32,7 @@ struct Group: Codable, Equatable {

extension Group {

func getExperiemnt(id: String) -> Experiment? {
func getExperiment(id: String) -> Experiment? {
return experiments.filter { $0.id == id }.first
}

Expand Down
10 changes: 4 additions & 6 deletions Sources/Implementation/DefaultBucketer.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/****************************************************************************
* Copyright 2019, Optimizely, Inc. and contributors *
* Copyright 2019-2020, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
Expand Down Expand Up @@ -33,7 +33,7 @@ class DefaultBucketer: OPTBucketer {

// check for mutex

let group = config.project.groups.filter { $0.getExperiemnt(id: experiment.id) != nil }.first
let group = config.project.groups.filter { $0.getExperiment(id: experiment.id) != nil }.first

if let group = group {
switch group.policy {
Expand Down Expand Up @@ -61,18 +61,16 @@ class DefaultBucketer: OPTBucketer {
// bucket to variation only if experiment passes Mutex check

if let variation = bucketToVariation(experiment: experiment, bucketingId: bucketingId) {
logger.i(.userBucketedIntoVariationInExperiment(bucketingId, experiment.key, variation.key))
return variation
} else {
logger.i(.userNotBucketedIntoVariationInExperiment(bucketingId, experiment.key))
return nil
}
}

func bucketToExperiment(config: ProjectConfig, group: Group, bucketingId: String) -> Experiment? {
let hashId = makeHashIdFromBucketingId(bucketingId: bucketingId, entityId: group.id)
let bucketValue = self.generateBucketValue(bucketingId: hashId)
logger.d(.userAssignedToExperimentBucketValue(bucketValue, bucketingId))
logger.d(.userAssignedToBucketValue(bucketValue, bucketingId))

if group.trafficAllocation.count == 0 {
logger.e(.groupHasNoTrafficAllocation(group.id))
Expand All @@ -97,7 +95,7 @@ class DefaultBucketer: OPTBucketer {
func bucketToVariation(experiment: Experiment, bucketingId: String) -> Variation? {
let hashId = makeHashIdFromBucketingId(bucketingId: bucketingId, entityId: experiment.id)
let bucketValue = generateBucketValue(bucketingId: hashId)
logger.d(.userAssignedToVariationBucketValue(bucketValue, bucketingId))
logger.d(.userAssignedToBucketValue(bucketValue, bucketingId))

if experiment.trafficAllocation.count == 0 {
logger.e(.experimentHasNoTrafficAllocation(experiment.key))
Expand Down
24 changes: 11 additions & 13 deletions Sources/Implementation/DefaultDecisionService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,20 @@ class DefaultDecisionService: OPTDecisionService {
return nil
}

// ---- check for whitelisted variation registered at runtime ----
// ---- check if the user is forced into a variation ----
if let variationId = config.getForcedVariation(experimentKey: experiment.key, userId: userId)?.id,
let variation = experiment.getVariation(id: variationId) {
return variation
}

// ---- check if the experiment has forced variation ----
// ---- check to see if user is white-listed for a certain variation ----
if let variationKey = experiment.forcedVariations[userId] {
if let variation = experiment.getVariation(key: variationKey) {
logger.i(.forcedVariationFound(variationKey, userId))
return variation
}

// mapped to invalid variation - ignore and continue for other deciesions
// mapped to invalid variation - ignore and continue for other decisions
logger.e(.forcedVariationFoundButInvalid(variationKey, userId))
}

Expand All @@ -65,22 +65,26 @@ class DefaultDecisionService: OPTDecisionService {

var bucketedVariation: Variation?
// ---- check if the user passes audience targeting before bucketing ----
if isInExperiment(config: config, experiment: experiment, userId: userId, attributes: attributes) {
if doesMeetAudienceConditions(config: config, experiment: experiment, userId: userId, attributes: attributes) {
// bucket user into a variation
bucketedVariation = bucketer.bucketExperiment(config: config, experiment: experiment, bucketingId: bucketingId)

if let bucketedVariation = bucketedVariation {
logger.i(.userBucketedIntoVariationInExperiment(userId, experiment.key, bucketedVariation.key))
// save to user profile
self.saveProfile(userId: userId, experimentId: experimentId, variationId: bucketedVariation.id)
} else {
logger.i(.userNotBucketedIntoVariation(userId))
}

} else {
logger.i(.userNotInExperiment(userId, experiment.key))
}

return bucketedVariation
}

func isInExperiment(config: ProjectConfig, experiment: Experiment, userId: String, attributes: OptimizelyAttributes, logType: Constants.EvaluationLogType = .experiment, loggingKey: String? = nil) -> Bool {
func doesMeetAudienceConditions(config: ProjectConfig, experiment: Experiment, userId: String, attributes: OptimizelyAttributes, logType: Constants.EvaluationLogType = .experiment, loggingKey: String? = nil) -> Bool {

var result = true // success as default (no condition, etc)
let evType = logType.rawValue
Expand Down Expand Up @@ -133,19 +137,13 @@ class DefaultDecisionService: OPTDecisionService {
//1. Attempt to bucket user into experiment using feature flag.
// Check if the feature flag is under an experiment and the the user is bucketed into one of these experiments
if let pair = getVariationForFeatureExperiment(config: config, featureFlag: featureFlag, userId: userId, attributes: attributes) {
logger.d(.userInFeatureExperiment(userId, pair.variation?.key ?? "unknown", pair.experiment?.key ?? "unknown", featureFlag.key))
return pair
} else {
logger.d(.userNotInFeatureExperiment(userId, featureFlag.key))
}

//2. Attempt to bucket user into rollout using the feature flag.
// Check if the feature flag has rollout and the user is bucketed into one of it's rules
if let variation = getVariationForFeatureRollout(config: config, featureFlag: featureFlag, userId: userId, attributes: attributes) {
logger.d(.userInRollout(userId, featureFlag.key))
return (nil, variation)
} else {
logger.d(.userNotInRollout(userId, featureFlag.key))
}

return nil
Expand Down Expand Up @@ -202,7 +200,7 @@ class DefaultDecisionService: OPTDecisionService {
for index in 0..<rolloutRules.count.advanced(by: -1) {
let loggingKey = index + 1
let experiment = rolloutRules[index]
if isInExperiment(config: config, experiment: experiment, userId: userId, attributes: attributes, logType: .rolloutRule, loggingKey: "\(loggingKey)") {
if doesMeetAudienceConditions(config: config, experiment: experiment, userId: userId, attributes: attributes, logType: .rolloutRule, loggingKey: "\(loggingKey)") {
logger.d(.userMeetsConditionsForTargetingRule(userId, loggingKey))
if let variation = bucketer.bucketExperiment(config: config, experiment: experiment, bucketingId: bucketingId) {
logger.d(.userBucketedIntoTargetingRule(userId, loggingKey))
Expand All @@ -217,7 +215,7 @@ class DefaultDecisionService: OPTDecisionService {
// Evaluate fall back rule / last rule now
let experiment = rolloutRules[rolloutRules.count - 1]

if isInExperiment(config: config, experiment: experiment, userId: userId, attributes: attributes, logType: .rolloutRule, loggingKey: "Everyone Else") {
if doesMeetAudienceConditions(config: config, experiment: experiment, userId: userId, attributes: attributes, logType: .rolloutRule, loggingKey: "Everyone Else") {
if let variation = bucketer.bucketExperiment(config: config, experiment: experiment, bucketingId: bucketingId) {
logger.d(.userBucketedIntoEveryoneTargetingRule(userId))

Expand Down
12 changes: 8 additions & 4 deletions Sources/Optimizely/OptimizelyClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -535,13 +535,10 @@ open class OptimizelyClient: NSObject {
if let featureVariable = decision.variation?.variables?.filter({$0.id == variable.id}).first {
if let featureEnabled = decision.variation?.featureEnabled, featureEnabled {
featureValue = featureVariable.value

logger.i(.userReceivedVariableValue(userId, featureKey, variableKey, featureValue))
logger.i(.userReceivedVariableValue(featureValue, variableKey, featureKey))
} else {
logger.i(.featureNotEnabledReturnDefaultVariableValue(userId, featureKey, variableKey))
}
} else {
logger.i(.variableNotUsedReturnDefaultVariableValue(variableKey))
}
} else {
logger.i(.userReceivedDefaultVariableValue(userId, featureKey, variableKey))
Expand Down Expand Up @@ -627,6 +624,13 @@ open class OptimizelyClient: NSObject {
attributes: attributes ?? OptimizelyAttributes())
if let featureEnabled = decision?.variation?.featureEnabled {
enabled = featureEnabled
if featureEnabled {
logger.i(.featureEnabledForUser(featureKey, userId))
} else {
logger.i(.featureNotEnabledForUser(featureKey, userId))
}
} else {
logger.i(.userReceivedAllDefaultVariableValues(userId, featureKey))
}

for (_, v) in featureFlag.variablesMap {
Expand Down
4 changes: 2 additions & 2 deletions Sources/Protocols/OPTBucketer.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/****************************************************************************
* Copyright 2019, Optimizely, Inc. and contributors *
* Copyright 2019-2020, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
Expand Down Expand Up @@ -27,7 +27,7 @@ protocol OPTBucketer {

/**
Bucket a bucketingId into an experiment.
- Parameter experiment: The experiment in which to bucket the bucketingId.
- Parameter experiment: The experiment or rollout rule in which to bucket the bucketingId.
- Parameter bucketingId: The ID to bucket. This must be a non-null, non-empty string.
- Returns: The variation the bucketingId was bucketed into.
*/
Expand Down
Loading