- Notifications
You must be signed in to change notification settings - Fork 28
feat(Audience Evaluation): Audience Logging #152
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
Conversation
1 similar comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall.
Missing attribute value Log Level was decided to be changed from WARNING to DEBUG.
| | ||
| if user_provided_value.nil? && condition_match != EXISTS_MATCH_TYPE | ||
| @logger.log( | ||
| Logger::WARN, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logger::DEBUG?
| unless value_valid_for_exact_conditions?(user_provided_value) | ||
| @logger.log( | ||
| Logger::WARN, | ||
| "Audience condition '#{condition}' evaluated as UNKNOWN because the value for user " \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This log is being used at multiple places. Can we make this a const? Or move all of the logs into a separate file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be done for logger improvement at SDK level.
However i have moved log messages to constants file for now.
spec/audience_spec.rb Outdated
| @config_body_json = OptimizelySpec::VALID_CONFIG_BODY_JSON | ||
| @config_typed_audience_json = JSON.dump(OptimizelySpec::CONFIG_DICT_WITH_TYPED_AUDIENCES) | ||
| end | ||
| let(:config_body) { OptimizelySpec::VALID_CONFIG_BODY } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. unused
| "Audience '3468206646' evaluated as 'true'." | ||
| ) | ||
| | ||
| expect(spy_logger).to have_received(:log).once.with( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we assert that these logs have been called in the given sequence? OR assert the total number of calls to ensure nothing else is being logged?
| condition = {'match' => 'exact', 'name' => 'weird_condition', 'type' => 'weird', 'value' => 'hi'} | ||
| condition_evaluator = Optimizely::CustomAttributeConditionEvaluator.new({'weird_condition' => 'bye'}, spy_logger) | ||
| expect(condition_evaluator.evaluate(condition)).to eq(nil) | ||
| expect(spy_logger).to have_received(:log).once.with( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. Can we use a construct that ensures that :log is called once and only with this message?
| ) | ||
| end | ||
| | ||
| it 'should log and return nil if there user-provided value is of a unexpected type' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. 'there'
…uby-sdk into rashid/logging-for-audience
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good! Thanks for updating this in line with the other SDKs; I think I only found nits. 👏
| Helpers::Validator.finite_number?(condition_value) && | ||
| Helpers::Validator.finite_number?(user_provided_value) | ||
| | ||
| return true if user_provided_value == condition_value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to do some kind of special comparison instead of user_provided_value == condition_value in order to account for cases in which user_provided_value and condition_value are of different numeric types?
If not, I think it'd be cleaner to rely on the equality check that already occurs at the end of this function. At the very least, this would be consistent with most of our other SDKs. In exchange, we'd have to modify Helpers::Validator.same_types? to return true in the case of different numeric types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. It will be much cleaner that way.
| format(Helpers::Constants::AUDIENCE_EVALUATION_LOGS['UNKNOWN_CONDITION_VALUE'], condition) | ||
| ) | ||
| return nil | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: would be slightly better (and certainly more consistent with other SDKs) to reorder the above two blocks. If the condition_value isn't a string, that'd be indicative of a broader problem that might be resolved in a future SDK, where it might actually be legitimate for the user_provided_value to be a non-string.
(I know we check for non-nil user_provided_value before we get to either of these blocks, but at least that helps us increase code re-use...)
spec/audience_spec.rb Outdated
| user_attributes)).to be false | ||
| expect(spy_logger).to have_received(:log).once.with( | ||
| Logger::DEBUG, | ||
| "Evaluating audiences for experiment 'test_experiment_with_audience': #{experiment['audienceIds']}." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid string interpolation in these tests? It'd be helpful to show what the final strings look like, especially since we're relying on Ruby's string representation of the underlying hash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great. Thanks again!
| # false otherwise. | ||
| # Numeric values are considered as same type. | ||
| | ||
| return true if value_1.is_a?(Numeric) && value_2.is_a?(Numeric) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it's okay to do the numeric check before the boolean check, in Ruby. I've confirmed that true and false are not Numerics.
| return true if value_1.is_a?(Numeric) && value_2.is_a?(Numeric) | ||
| | ||
| return true if boolean?(value_1) && boolean?(value_2) | ||
| return true if value_1.is_a?(Integer) && value_2.is_a?(Integer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for changing this! I just did some final QA for the 3.0 release, and I'm sure this would have been a problem if we hadn't changed it. We do expect numbers and floats to be interchangeable for the purposes of audience targeting. 👌
Summary
This adds logging to audience evaluation.
Test plan
Unit tests written in
Issues