Skip to content
Open
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
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,24 @@ attributes = {
context = EvaluationContext(**attributes)
```

### Flag Metadata

Evaluations include flag metadata for the LaunchDarkly specific parts of the evaluation result which have no OpenFeature equivalent. Each entry is absent when it does not apply to the evaluation.

| Key | Type | Description |
|---------------------|---------|--------------------------------------------------------------------|
| `variationIndex` | integer | The index of the returned variation. Absent for default values. |
| `inExperiment` | boolean | Present, and `true`, when the evaluation was part of an experiment. |
| `ruleIndex` | integer | The index of the rule that matched. |
| `ruleId` | string | The identifier of the rule that matched. |
| `prerequisiteKey` | string | The key of the prerequisite flag that failed. |
| `bigSegmentsStatus` | string | The status of the Big Segments query made during the evaluation. |

```ruby
details = client.fetch_boolean_details(flag_key: "my-flag", default_value: false)
in_experiment = details.flag_metadata.fetch("inExperiment", false)
```

## Learn more

Check out our [documentation](http://docs.launchdarkly.com) for in-depth instructions on configuring and using LaunchDarkly. You can also head straight to the [complete reference guide for this SDK](https://docs.launchdarkly.com/sdk/server-side/ruby).
Expand Down
32 changes: 31 additions & 1 deletion lib/ldclient-openfeature/impl/details_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ module LaunchDarkly
module OpenFeature
module Impl
class ResolutionDetailsConverter
VARIATION_INDEX_KEY = 'variationIndex'
IN_EXPERIMENT_KEY = 'inExperiment'
RULE_INDEX_KEY = 'ruleIndex'
RULE_ID_KEY = 'ruleId'
PREREQUISITE_KEY_KEY = 'prerequisiteKey'
BIG_SEGMENTS_STATUS_KEY = 'bigSegmentsStatus'

private_constant :VARIATION_INDEX_KEY, :IN_EXPERIMENT_KEY, :RULE_INDEX_KEY, :RULE_ID_KEY,
:PREREQUISITE_KEY_KEY, :BIG_SEGMENTS_STATUS_KEY

#
# @param detail [LaunchDarkly::EvaluationDetail]
#
Expand Down Expand Up @@ -35,10 +45,30 @@ def to_resolution_details(detail)
error_code: openfeature_error_code,
error_message: nil,
reason: openfeature_reason,
variant: openfeature_variant
variant: openfeature_variant,
flag_metadata: flag_metadata(reason, is_default ? nil : variation_index)
)
end

#
# @param reason [LaunchDarkly::EvaluationReason]
# @param variation_index [Integer, nil]
#
# @return [Hash]
#
private def flag_metadata(reason, variation_index)
metadata = {}

metadata[VARIATION_INDEX_KEY] = variation_index unless variation_index.nil?
metadata[IN_EXPERIMENT_KEY] = true if reason.in_experiment
metadata[RULE_INDEX_KEY] = reason.rule_index unless reason.rule_index.nil?
metadata[RULE_ID_KEY] = reason.rule_id unless reason.rule_id.nil?
metadata[PREREQUISITE_KEY_KEY] = reason.prerequisite_key unless reason.prerequisite_key.nil?
metadata[BIG_SEGMENTS_STATUS_KEY] = reason.big_segments_status.to_s unless reason.big_segments_status.nil?

metadata
end

#
# @param kind [Symbol]
#
Expand Down
50 changes: 50 additions & 0 deletions spec/impl/details_converter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,54 @@
expect(resolution_details.error_code).to eq(of_error_code)
end
end

it "includes the variation index in the flag metadata" do
detail = LaunchDarkly::EvaluationDetail.new(true, 1, LaunchDarkly::EvaluationReason::fallthrough)
resolution_details = details_converter.to_resolution_details(detail)

expect(resolution_details.flag_metadata).to eq({'variationIndex' => 1})
end

it "omits the variation index from the flag metadata for default values" do
detail = LaunchDarkly::EvaluationDetail.new(true, nil, LaunchDarkly::EvaluationReason::error(LaunchDarkly::EvaluationReason::ERROR_FLAG_NOT_FOUND))
resolution_details = details_converter.to_resolution_details(detail)

expect(resolution_details.flag_metadata).to eq({})
end

it "includes in experiment in the flag metadata for experiment evaluations" do
detail = LaunchDarkly::EvaluationDetail.new(true, 1, LaunchDarkly::EvaluationReason::fallthrough(true))
resolution_details = details_converter.to_resolution_details(detail)

expect(resolution_details.flag_metadata).to eq({'variationIndex' => 1, 'inExperiment' => true})
end

it "omits in experiment from the flag metadata for non-experiment evaluations" do
detail = LaunchDarkly::EvaluationDetail.new(true, 1, LaunchDarkly::EvaluationReason::fallthrough(false))
resolution_details = details_converter.to_resolution_details(detail)

expect(resolution_details.flag_metadata).not_to have_key('inExperiment')
end

it "includes the rule in the flag metadata for rule matches" do
detail = LaunchDarkly::EvaluationDetail.new(true, 1, LaunchDarkly::EvaluationReason::rule_match(2, 'the-rule-id', false))
resolution_details = details_converter.to_resolution_details(detail)

expect(resolution_details.flag_metadata).to eq({'variationIndex' => 1, 'ruleIndex' => 2, 'ruleId' => 'the-rule-id'})
end

it "includes the prerequisite key in the flag metadata for failed prerequisites" do
detail = LaunchDarkly::EvaluationDetail.new(true, 1, LaunchDarkly::EvaluationReason::prerequisite_failed('the-prerequisite-key'))
resolution_details = details_converter.to_resolution_details(detail)

expect(resolution_details.flag_metadata).to eq({'variationIndex' => 1, 'prerequisiteKey' => 'the-prerequisite-key'})
end

it "includes the big segments status in the flag metadata" do
reason = LaunchDarkly::EvaluationReason::fallthrough.with_big_segments_status(LaunchDarkly::BigSegmentsStatus::STALE)
detail = LaunchDarkly::EvaluationDetail.new(true, 1, reason)
resolution_details = details_converter.to_resolution_details(detail)

expect(resolution_details.flag_metadata).to eq({'variationIndex' => 1, 'bigSegmentsStatus' => 'STALE'})
end
end
Loading