Assignments
Assignments are the mechanism through which a given Subject is assigned to a variation for a feature flag or experiment.
Currently, the Eppo SDK supports the following assignment types:
- String
- Boolean
- JSON
- Numeric (Integer and Float)
String Assignments
String assignments return a string value that is set as the variation for the experiment. String flags are the most common type of flags. They are useful for both A/B/n tests and advanced targeting use cases.
use std::collections::HashMap;
let flag_key = "flag-key-123";
let subject_key = "user-123";
let default_assignment = "version-a";
let mut subject_attributes = HashMap::new();
subject_attributes.insert("country".into(), "US".into());
subject_attributes.insert("age".into(), 30.into());
subject_attributes.insert("isReturningUser".into(), true.into());
let variant = client
.get_string_assignment(
flag_key,
subject_key,
subject_attributes,
)
.inspect_err(|err| eprintln!("error assigning a flag: {:?}", err))
.unwrap_or_default()
.unwrap_or(default_assignment.into());
// Use the variant value to determine which path to take
if variant == "version-a" {
handle_version_a();
} else if variant == "version-b" {
handle_version_b();
}
Boolean Assignments
Boolean flags support simple on/off toggles. They're useful for simple, binary feature switches like blue/green deployments or enabling/disabling a new feature.
use std::collections::HashMap;
let flag_key = "flag-key-123";
let subject_key = "user-123";
let default_assignment = false;
let mut subject_attributes = HashMap::new();
subject_attributes.insert("country".into(), "US".into());
subject_attributes.insert("age".into(), 30.into());
subject_attributes.insert("isReturningUser".into(), true.into());
let variant = client
.get_boolean_assignment(
flag_key,
subject_key,
subject_attributes,
)
.inspect_err(|err| eprintln!("error assigning a flag: {:?}", err))
.unwrap_or_default()
.unwrap_or(default_assignment);
if variant {
handle_feature_enabled();
} else {
handle_feature_disabled();
}
JSON Assignments
JSON flags work best for advanced configuration use cases. The JSON flag can include structured information such as:
- The text of marketing copy for a promotional campaign
- The address of a different hero image
Using this pattern, a team can make minor changes to the copy and design of a website without having to go through an entire code release process.
use std::collections::HashMap;
use serde_json::Value;
let flag_key = "flag-key-123";
let subject_key = "user-123";
let default_assignment = serde_json::json!({
"hero": false,
"heroImage": "placeholder.png",
"heroTitle": "Placeholder Hero Title",
"heroDescription": "Placeholder Hero Description"
});
let mut subject_attributes = HashMap::new();
subject_attributes.insert("country".into(), "US".into());
subject_attributes.insert("age".into(), 30.into());
subject_attributes.insert("isReturningUser".into(), true.into());
let campaign_json = client
.get_json_assignment(
flag_key,
subject_key,
subject_attributes,
)
.inspect_err(|err| eprintln!("error assigning a flag: {:?}", err))
.unwrap_or_default()
.unwrap_or(default_assignment);
if let Some(campaign) = campaign_json.as_object() {
let hero_image = campaign.get("heroImage").and_then(Value::as_str).unwrap_or("default.png");
let hero_title = campaign.get("heroTitle").and_then(Value::as_str).unwrap_or("");
let hero_description = campaign.get("heroDescription").and_then(Value::as_str).unwrap_or("");
render_hero(hero_image, hero_title, hero_description);
}
Integer and Numeric Assignments
Integer and numeric assignments work the same way but return either an integer or a floating point number. These assignments are useful where you want to use a numeric value to drive business logic such as pricing on an item or a number of items to display in a list.
use std::collections::HashMap;
let flag_key = "flag-key-123";
let subject_key = "user-123";
let default_integer = 0;
let default_numeric = 0.0;
let mut subject_attributes = HashMap::new();
subject_attributes.insert("country".into(), "US".into());
subject_attributes.insert("age".into(), 30.into());
subject_attributes.insert("isReturningUser".into(), true.into());
// Example of getting an integer assignment
let number_of_items = client
.get_integer_assignment(
flag_key,
subject_key,
subject_attributes.clone(),
)
.inspect_err(|err| eprintln!("error assigning a flag: {:?}", err))
.unwrap_or_default()
.unwrap_or(default_integer);
// Example of getting a numeric assignment
let price = client
.get_numeric_assignment(
flag_key,
subject_key,
subject_attributes,
)
.inspect_err(|err| eprintln!("error assigning a flag: {:?}", err))
.unwrap_or_default()
.unwrap_or(default_numeric);
// Use the assignments to drive business logic
display_items(number_of_items);
set_item_price(price);
Assignment Logger Schema
The SDK will invoke the log_assignment
function with an AssignmentEvent
struct that contains the following fields:
timestamp
StringDefault: undefined
The time when the subject was assigned to the variation. Example: "2021-06-22T17:35:12.000Z"
feature_flag
StringDefault: undefined
An Eppo feature flag key. Example: "recommendation-algo"
allocation
StringDefault: undefined
An Eppo allocation key. Example: "allocation-17"
experiment
StringDefault: undefined
An Eppo experiment key. Example: "recommendation-algo-allocation-17"
subject
StringDefault: undefined
An identifier of the subject or user assigned to the experiment variation. Example: UUID
subject_attributes
HashMap<String, Value>Default: HashMap::new()
A free-form map of metadata about the subject. These attributes are only logged if passed to the SDK assignment function. Example: { "country": "US" }
variation
StringDefault: undefined
The experiment variation the subject was assigned to. Example: "control"
meta_data
HashMap<String, String>Default: HashMap::new()
Metadata around the assignment, such as the version of the SDK. Example: { "sdkLanguage": "rust", "sdkLibVersion": "0.1.0" }
Logging data to your data warehouse
Eppo's unique architecture makes it so Eppo never has access to your data. This means that you can use the assignment logging functions to send data to any data warehouse or logging system you want.
All you need to do is implement the AssignmentLogger
trait:
- Console
- Custom Implementation
use eppo::AssignmentLogger;
struct MyAssignmentLogger;
impl AssignmentLogger for MyAssignmentLogger {
fn log_assignment(&self, assignment: AssignmentEvent) {
println!("{:?}", assignment);
}
}
This example writes to your local machine and is useful for development in your local environment. In production, these logs will need to get written to a table in your data warehouse.
use eppo::AssignmentLogger;
struct MyCustomLogger;
impl AssignmentLogger for MyCustomLogger {
fn log_assignment(&self, assignment: AssignmentEvent) {
// Implement your custom logging logic here
// For example, sending to your data warehouse
send_to_data_warehouse(assignment);
}
}
fn send_to_data_warehouse(assignment: AssignmentEvent) {
// Your implementation here
}
The Rust SDK currently has fewer built-in integrations compared to other SDKs. You'll need to implement custom logging logic for specific data warehouses or analytics platforms.