Skip to content

Commit 0acbb00

Browse files
Vignesh Rajathomaszurkan-optimizely
authored andcommitted
Add support for numeric metrics (#129)
1 parent e265374 commit 0acbb00

File tree

5 files changed

+58
-27
lines changed

5 files changed

+58
-27
lines changed

core-api/src/main/java/com/optimizely/ab/event/internal/EventBuilderV2.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,16 @@ public LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig,
112112

113113
List<LayerState> layerStates = createLayerStates(projectConfig, experimentVariationMap);
114114

115-
Long eventValue = EventTagUtils.getRevenueValue(eventTags);
116-
List<EventMetric> eventMetrics = Collections.emptyList();
117-
if (eventValue != null) {
118-
eventMetrics = Collections.singletonList(new EventMetric(EventMetric.REVENUE_METRIC_TYPE, eventValue));
115+
List<EventMetric> eventMetrics = new ArrayList<EventMetric>();
116+
117+
Long revenueValue = EventTagUtils.getRevenueValue(eventTags);
118+
if (revenueValue != null) {
119+
eventMetrics.add(new EventMetric(EventMetric.REVENUE_METRIC_TYPE, revenueValue));
120+
}
121+
122+
Double numericMetricValue = EventTagUtils.getNumericValue(eventTags);
123+
if (numericMetricValue != null) {
124+
eventMetrics.add(new EventMetric(EventMetric.NUMERIC_METRIC_TYPE, numericMetricValue));
119125
}
120126

121127
Conversion conversionPayload = new Conversion();

core-api/src/main/java/com/optimizely/ab/event/internal/payload/EventMetric.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
public class EventMetric {
2020

2121
public static final String REVENUE_METRIC_TYPE = "revenue";
22+
public static final String NUMERIC_METRIC_TYPE = "value";
2223

2324
private String name;
24-
private long value;
25+
private Number value;
2526

2627
public EventMetric() { }
2728

28-
public EventMetric(String name, long value) {
29+
public EventMetric(String name, Number value) {
2930
this.name = name;
3031
this.value = value;
3132
}
@@ -38,30 +39,29 @@ public void setName(String name) {
3839
this.name = name;
3940
}
4041

41-
public long getValue() {
42+
public Number getValue() {
4243
return value;
4344
}
4445

45-
public void setValue(long value) {
46+
public void setValue(Number value) {
4647
this.value = value;
4748
}
4849

49-
5050
@Override
51-
public boolean equals(Object other) {
52-
if (!(other instanceof EventMetric))
53-
return false;
51+
public boolean equals(Object obj) {
52+
if (this == obj) return true;
53+
if (obj == null || getClass() != obj.getClass()) return false;
5454

55-
EventMetric otherEventMetric = (EventMetric)other;
55+
EventMetric that = (EventMetric) obj;
5656

57-
return name.equals(otherEventMetric.getName()) && value == otherEventMetric.getValue();
57+
if (!name.equals(that.name)) return false;
58+
return value.equals(that.value);
5859
}
5960

60-
6161
@Override
6262
public int hashCode() {
63-
int result = name != null ? name.hashCode() : 0;
64-
result = 31 * result + (int) (value ^ (value >>> 32));
63+
int result = name.hashCode();
64+
result = 31 * result + value.hashCode();
6565
return result;
6666
}
6767

core-api/src/main/java/com/optimizely/ab/internal/EventTagUtils.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,22 @@ public static Long getRevenueValue(@Nonnull Map<String, ?> eventTags) {
4747
}
4848
return eventValue;
4949
}
50+
51+
/**
52+
* Fetch the numeric metric value from event tags. "value" is a reserved keyword.
53+
*/
54+
public static Double getNumericValue(@Nonnull Map<String, ?> eventTags) {
55+
Double eventValue = null;
56+
if (eventTags.containsKey(ReservedEventKey.VALUE.toString())) {
57+
Object rawValue = eventTags.get(ReservedEventKey.VALUE.toString());
58+
if (rawValue instanceof Number) {
59+
eventValue = ((Number) rawValue).doubleValue();
60+
logger.info("Parsed numeric metric value \"{}\" from event tags.", eventValue);
61+
} else {
62+
logger.warn("Failed to parse numeric metric value \"{}\" from event tags.", rawValue);
63+
}
64+
}
65+
66+
return eventValue;
67+
}
5068
}

core-api/src/main/java/com/optimizely/ab/internal/ReservedEventKey.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
package com.optimizely.ab.internal;
1818

1919
public enum ReservedEventKey {
20-
REVENUE("revenue");
20+
REVENUE("revenue"),
21+
VALUE("value");
2122

2223
private final String key;
2324

core-api/src/test/java/com/optimizely/ab/event/internal/EventBuilderV2Test.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.optimizely.ab.event.internal;
1818

1919
import com.google.gson.Gson;
20+
import com.google.gson.internal.LazilyParsedNumber;
2021
import com.optimizely.ab.bucketing.Bucketer;
2122
import com.optimizely.ab.config.Attribute;
2223
import com.optimizely.ab.config.EventType;
@@ -43,12 +44,12 @@
4344
import java.util.HashMap;
4445
import java.util.List;
4546
import java.util.Map;
47+
import java.util.Arrays;
4648

4749
import static com.optimizely.ab.config.ProjectConfigTestUtils.validProjectConfigV2;
4850
import static org.hamcrest.CoreMatchers.is;
4951
import static org.hamcrest.Matchers.closeTo;
5052
import static org.junit.Assert.assertFalse;
51-
import static org.junit.Assert.assertNotEquals;
5253
import static org.junit.Assert.assertNull;
5354
import static org.junit.Assert.assertThat;
5455
import static org.junit.Assert.assertTrue;
@@ -132,8 +133,8 @@ public void createImpressionEventIgnoresUnknownAttributes() throws Exception {
132133

133134
// verify that no Feature is created for "unknownAtrribute" -> "blahValue"
134135
for (Feature feature : impression.getUserFeatures()) {
135-
assertNotEquals(feature.getName(), "unknownAttribute");
136-
assertNotEquals(feature.getValue(), "blahValue");
136+
assertFalse(feature.getName() == "unknownAttribute");
137+
assertFalse(feature.getValue() == "blahValue");
137138
}
138139
}
139140

@@ -269,11 +270,13 @@ public void createConversionEvent() throws Exception {
269270
}
270271

271272
/**
272-
* Verify that eventValue is properly recorded in a conversion request as an {@link EventMetric}
273+
* Verify that "revenue" and "value" are properly recorded in a conversion request as {@link EventMetric} objects.
274+
* "revenue" is fixed-point and "value" is floating-point.
273275
*/
274276
@Test
275-
public void createConversionParamsWithRevenue() throws Exception {
276-
long revenue = 1234L;
277+
public void createConversionParamsWithEventMetrics() throws Exception {
278+
Long revenue = 1234L;
279+
Double value = 13.37;
277280

278281
// use the "valid" project config and its associated experiment, variation, and attributes
279282
Attribute attribute = validProjectConfig.getAttributes().get(0);
@@ -290,6 +293,7 @@ public void createConversionParamsWithRevenue() throws Exception {
290293
Map<String, String> attributeMap = Collections.singletonMap(attribute.getKey(), "value");
291294
Map<String, Object> eventTagMap = new HashMap<String, Object>();
292295
eventTagMap.put(ReservedEventKey.REVENUE.toString(), revenue);
296+
eventTagMap.put(ReservedEventKey.VALUE.toString(), value);
293297
Map<Experiment, Variation> experimentVariationMap = createExperimentVariationMap(
294298
validProjectConfig,
295299
mockBucketAlgorithm,
@@ -302,9 +306,11 @@ public void createConversionParamsWithRevenue() throws Exception {
302306

303307
Conversion conversion = gson.fromJson(conversionEvent.getBody(), Conversion.class);
304308

305-
// we're not going to verify everything, only revenue
306-
assertThat(conversion.getEventMetrics(),
307-
is(Collections.singletonList(new EventMetric(EventMetric.REVENUE_METRIC_TYPE, revenue))));
309+
List<EventMetric> eventMetrics = Arrays.asList(
310+
new EventMetric(EventMetric.REVENUE_METRIC_TYPE, new LazilyParsedNumber(revenue.toString())),
311+
new EventMetric(EventMetric.NUMERIC_METRIC_TYPE, new LazilyParsedNumber(value.toString())));
312+
// we're not going to verify everything, only the event metrics
313+
assertThat(conversion.getEventMetrics(), is(eventMetrics));
308314
}
309315

310316
/**

0 commit comments

Comments
 (0)