Skip to content
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
* Added `eval_jexl_debug()` method to `NimbusTargetingHelper` interface for CLI testing and debugging. Evaluates JEXL expressions and returns debug results as JSON. Consumers implementing this interface must add the new method.
([#7156](https://github.com/mozilla/application-services/pull/7156))
([#31607](https://github.com/mozilla-mobile/firefox-ios/pull/31607))
* Update Cirrus metrics handler interface for recording enrollment status to specify nimbus user id as separate metric and change method name from `record_enrollment_statuses` to `record_enrollment_statuses_v2`. Consumers implementing this interface must add the new method.
* Update Cirrus `MetricsHandler` interface for recording enrollment status to specify nimbus user id as separate metric and change method name from `record_enrollment_statuses` to `record_enrollment_statuses_v2`. Consumers implementing this interface must add the new method.
([#14280](https://github.com/mozilla/experimenter/pull/14280))
* Move `nimbus_events.enrollment_status` to new `nimbus-targeting-context` ping, and add Nimbus `MetricsHandler` interface method `submit_targeting_context` to submit the ping. Consumers implementing this interface must add the new method. ([#14542](https://github.com/mozilla/experimenter/issues/14542))
* Enable using `PreviousGeckoPrefState` to revert Gecko pref experiments when applicable ([#7157](https://github.com/mozilla/application-services/pull/7157))

### Error support
Expand Down
1 change: 1 addition & 0 deletions automation/build_ios_artifacts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export PROJECT=MozillaRustComponentsWrapper
-o ./megazords/ios-rust/Sources/MozillaRustComponentsWrapper/Generated/Glean \
"${SOURCE_ROOT}"/components/ads-client/metrics.yaml \
"${SOURCE_ROOT}"/components/nimbus/metrics.yaml \
"${SOURCE_ROOT}"/components/nimbus/pings.yaml \
"${SOURCE_ROOT}"/components/logins/metrics.yaml \
"${SOURCE_ROOT}"/components/sync_manager/metrics.yaml \
"${SOURCE_ROOT}"/components/sync_manager/pings.yaml
Expand Down
2 changes: 1 addition & 1 deletion components/nimbus/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ apply from: "$appServicesRootDir/publish.gradle"

ext {
gleanNamespace = "mozilla.telemetry.glean"
gleanYamlFiles = ["${project.projectDir}/../metrics.yaml"]
gleanYamlFiles = ["${project.projectDir}/../metrics.yaml", "${project.projectDir}/../pings.yaml"]
if (gradle.hasProperty("mozconfig")) {
gleanPythonEnvDir = gradle.mozconfig.substs.GRADLE_GLEAN_PARSER_VENV
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import mozilla.telemetry.glean.Glean
import org.json.JSONObject
import org.mozilla.experiments.nimbus.GleanMetrics.NimbusEvents
import org.mozilla.experiments.nimbus.GleanMetrics.NimbusHealth
import org.mozilla.experiments.nimbus.GleanMetrics.Pings
import org.mozilla.experiments.nimbus.internal.AppContext
import org.mozilla.experiments.nimbus.internal.AvailableExperiment
import org.mozilla.experiments.nimbus.internal.EnrolledExperiment
Expand Down Expand Up @@ -137,6 +138,10 @@ open class Nimbus(
),
)
}

override fun submitTargetingContext() {
Pings.nimbusTargetingContext.submit()
}
}

private val nimbusClient: NimbusClientInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import mozilla.telemetry.glean.Glean
import mozilla.telemetry.glean.config.Configuration
import mozilla.telemetry.glean.net.HttpStatus
import mozilla.telemetry.glean.net.PingUploader
import mozilla.telemetry.glean.private.RecordedEvent
import mozilla.telemetry.glean.testing.GleanTestRule
import org.json.JSONObject
import org.junit.Assert.assertEquals
Expand All @@ -36,6 +37,7 @@ import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mozilla.experiments.nimbus.GleanMetrics.NimbusEvents
import org.mozilla.experiments.nimbus.GleanMetrics.NimbusHealth
import org.mozilla.experiments.nimbus.GleanMetrics.Pings
import org.mozilla.experiments.nimbus.internal.EnrollmentChangeEvent
import org.mozilla.experiments.nimbus.internal.EnrollmentChangeEventType
import org.mozilla.experiments.nimbus.internal.GeckoPref
Expand Down Expand Up @@ -723,17 +725,21 @@ class NimbusTests {
return testExperimentsJsonString(appInfo, packageName)
}

var enrollmentStatusEvents: List<RecordedEvent>? = null
val gleanJob = Pings.nimbusTargetingContext.testBeforeNextSubmit {
enrollmentStatusEvents = NimbusEvents.enrollmentStatus.testGetValue()
}

val job = nimbus.applyLocalExperiments(::getString)
runBlocking {
job.join()
gleanJob.join()
}

assertEquals(1, nimbus.getAvailableExperiments().size)
assertNotNull("Event must have a value", NimbusEvents.enrollmentStatus.testGetValue())
val enrollmentStatusEvents = NimbusEvents.enrollmentStatus.testGetValue()!!
assertEquals("Event count must match", enrollmentStatusEvents.count(), 1)
assertEquals("Event count must match", 1, enrollmentStatusEvents?.size)

val enrolledExtra = enrollmentStatusEvents[0].extra!!
val enrolledExtra = enrollmentStatusEvents!!.single().extra!!
assertEquals("branch must match", "test-branch", enrolledExtra["branch"])
assertEquals("slug must match", "test-experiment", enrolledExtra["slug"])
assertEquals("status must match", "Enrolled", enrolledExtra["status"])
Expand Down
3 changes: 3 additions & 0 deletions components/nimbus/metrics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ nimbus_events:
bugs:
- https://mozilla-hub.atlassian.net/browse/EXP-3827
- https://bugzilla.mozilla.org/show_bug.cgi?id=1996105
- https://bugzilla.mozilla.org/show_bug.cgi?id=1996120
data_reviews:
- https://github.com/mozilla/application-services/pull/5857#issuecomment-1749722071
data_sensitivity:
Expand All @@ -258,6 +259,8 @@ nimbus_events:
- project-nimbus@mozilla.com
expires: never
disabled: true
send_in_pings:
- nimbus-targeting-context
is_ready:
type: event
description: >
Expand Down
20 changes: 20 additions & 0 deletions components/nimbus/pings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

---
$schema: moz://mozilla.org/schemas/glean/pings/2-0-0

nimbus-targeting-context:
description: |
This ping is submitted by Nimbus each time the enrollment workflow has completed.
include_client_id: true
send_if_empty: true
bugs:
- https://mozilla-hub.atlassian.net/browse/EXP-6084
data_reviews:
- https://github.com/mozilla/application-services/pull/7225
notification_emails:
- beth@mozilla.com
- dthorn@mozilla.com
- project-nimbus@mozilla.com
3 changes: 3 additions & 0 deletions components/nimbus/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ pub trait MetricsHandler: Send + Sync {

#[cfg(feature = "stateful")]
fn record_malformed_feature_config(&self, event: MalformedFeatureConfigExtraDef);

#[cfg(feature = "stateful")]
fn submit_targeting_context(&self);
}

#[derive(Serialize, Deserialize, Clone)]
Expand Down
2 changes: 2 additions & 0 deletions components/nimbus/src/nimbus.udl
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ callback interface MetricsHandler {
void record_feature_exposure(FeatureExposureExtraDef event);

void record_malformed_feature_config(MalformedFeatureConfigExtraDef event);

void submit_targeting_context();
};

dictionary EnrollmentStatusExtraDef {
Expand Down
17 changes: 13 additions & 4 deletions components/nimbus/src/stateful/nimbus_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@ impl NimbusClient {
&coenrolling_ids,
self.gecko_prefs.clone(),
)?;
self.record_enrollment_status_telemetry(state)?;
Ok(())
}

Expand Down Expand Up @@ -288,7 +287,9 @@ impl NimbusClient {
let existing_experiments: Vec<Experiment> =
db.get_store(StoreId::Experiments).collect_all(&writer)?;
let events = self.evolve_experiments(db, &mut writer, &mut state, &existing_experiments)?;
self.end_initialize(db, writer, &mut state)?;
let res = self.end_initialize(db, writer, &mut state);
self.record_enrollment_status_telemetry(&mut state)?;
res?;
Ok(events)
}

Expand All @@ -304,7 +305,9 @@ impl NimbusClient {
let existing_experiments: Vec<Experiment> =
db.get_store(StoreId::Experiments).collect_all(&writer)?;
let events = self.evolve_experiments(db, &mut writer, &mut state, &existing_experiments)?;
self.end_initialize(db, writer, &mut state)?;
let res = self.end_initialize(db, writer, &mut state);
self.record_enrollment_status_telemetry(&mut state)?;
res?;
Ok(events)
}

Expand Down Expand Up @@ -475,6 +478,7 @@ impl NimbusClient {
let mut state = self.mutable_state.lock().unwrap();
self.begin_initialize(db, &mut writer, &mut state)?;

let should_record_enrollment_status = pending_updates.is_some();
let res = match pending_updates {
Some(new_experiments) => {
self.update_ta_active_experiments(db, &writer, &mut state)?;
Expand All @@ -485,7 +489,11 @@ impl NimbusClient {
};

// Finish up any cleanup, e.g. copying from database in to memory.
self.end_initialize(db, writer, &mut state)?;
let end_init_res = self.end_initialize(db, writer, &mut state);
if should_record_enrollment_status {
self.record_enrollment_status_telemetry(&mut state)?;
}
end_init_res?;
Ok(res)
}

Expand Down Expand Up @@ -1013,6 +1021,7 @@ impl NimbusClient {
})
.collect(),
);
self.metrics_handler.submit_targeting_context();
Ok(())
}
}
Expand Down
12 changes: 12 additions & 0 deletions components/nimbus/src/tests/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ struct MetricState {
exposures: Vec<FeatureExposureExtraDef>,
#[cfg(feature = "stateful")]
malformeds: Vec<MalformedFeatureConfigExtraDef>,
#[cfg(feature = "stateful")]
submit_targeting_context_calls: u64,
#[cfg(not(feature = "stateful"))]
nimbus_user_id: Option<String>,
}
Expand Down Expand Up @@ -202,6 +204,10 @@ impl TestMetrics {
pub fn get_malformeds(&self) -> Vec<MalformedFeatureConfigExtraDef> {
self.state.lock().unwrap().malformeds.clone()
}

pub fn get_submit_targeting_context_calls(&self) -> u64 {
self.state.lock().unwrap().submit_targeting_context_calls
}
}

impl MetricsHandler for TestMetrics {
Expand Down Expand Up @@ -239,6 +245,12 @@ impl MetricsHandler for TestMetrics {
let mut state = self.state.lock().unwrap();
state.malformeds.push(event);
}

#[cfg(feature = "stateful")]
fn submit_targeting_context(&self) {
let mut state = self.state.lock().unwrap();
state.submit_targeting_context_calls += 1;
}
}

#[cfg(feature = "stateful")]
Expand Down
32 changes: 32 additions & 0 deletions components/nimbus/src/tests/stateful/test_nimbus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,13 @@ fn test_enrollment_status_metrics_recorded() -> Result<()> {

client.apply_pending_experiments()?;

assert_eq!(
client
.get_metrics_handler()
.get_submit_targeting_context_calls(),
1u64
);

let metric_records = client.get_metrics_handler().get_enrollment_statuses();
assert_eq!(metric_records.len(), 3);

Expand Down Expand Up @@ -1325,6 +1332,13 @@ fn test_enrollment_status_metrics_recorded() -> Result<()> {
])?)?;
client.apply_pending_experiments()?;

assert_eq!(
client
.get_metrics_handler()
.get_submit_targeting_context_calls(),
2u64
);

let metric_records = client.get_metrics_handler().get_enrollment_statuses();
assert_eq!(metric_records.len(), 6);

Expand Down Expand Up @@ -1386,6 +1400,12 @@ fn test_enrollment_status_metrics_not_recorded_app_name_mismatch() -> Result<()>

client.apply_pending_experiments()?;

assert_eq!(
client
.get_metrics_handler()
.get_submit_targeting_context_calls(),
1u64
);
let metric_records = client.get_metrics_handler().get_enrollment_statuses();
assert_eq!(metric_records.len(), 0);

Expand Down Expand Up @@ -1429,6 +1449,12 @@ fn test_enrollment_status_metrics_not_recorded_channel_mismatch() -> Result<()>

client.apply_pending_experiments()?;

assert_eq!(
client
.get_metrics_handler()
.get_submit_targeting_context_calls(),
1u64
);
let metric_records = client.get_metrics_handler().get_enrollment_statuses();
assert_eq!(metric_records.len(), 0);
Ok(())
Expand Down Expand Up @@ -1723,6 +1749,12 @@ fn test_recorded_context_recorded() -> Result<()> {
let active_experiments = client.get_active_experiments()?;
assert_eq!(active_experiments.len(), 1);
assert_eq!(client.get_recorded_context().get_record_calls(), 1u64);
assert_eq!(
client
.get_metrics_handler()
.get_submit_targeting_context_calls(),
1u64
);

Ok(())
}
Expand Down
5 changes: 5 additions & 0 deletions components/nimbus/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ impl MetricsHandler for NoopMetricsHandler {
fn record_malformed_feature_config(&self, _event: MalformedFeatureConfigExtraDef) {
// do nothing
}

#[cfg(feature = "stateful")]
fn submit_targeting_context(&self) {
// do nothing
}
}

#[allow(dead_code)] // work around https://github.com/rust-lang/rust/issues/46379
Expand Down
4 changes: 4 additions & 0 deletions examples/nimbus/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ fn main() -> Result<()> {
fn record_malformed_feature_config(&self, _event: MalformedFeatureConfigExtraDef) {
// do nothing
}

fn submit_targeting_context(&self) {
// do nothing
}
}

// We set the logging level to be `warn` here, meaning that only
Expand Down
9 changes: 8 additions & 1 deletion taskcluster/scripts/build-and-test-swift.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,19 @@ def generate_glean_metrics(args):
)
out_dir = args.out_dir / "all" / "Generated" / "Metrics"
focus_out_dir = args.out_dir / "focus" / "Generated" / "Metrics"
focus_glean_files = map(str, [ROOT_DIR / "components/nimbus/metrics.yaml"])
focus_glean_files = map(
str,
[
ROOT_DIR / "components/nimbus/metrics.yaml",
ROOT_DIR / "components/nimbus/pings.yaml",
]
)
firefox_glean_files = map(
str,
[
ROOT_DIR / "components/ads-client/metrics.yaml",
ROOT_DIR / "components/nimbus/metrics.yaml",
ROOT_DIR / "components/nimbus/pings.yaml",
ROOT_DIR / "components/logins/metrics.yaml",
ROOT_DIR / "components/sync_manager/metrics.yaml",
ROOT_DIR / "components/sync_manager/pings.yaml",
Expand Down