Pings

Glean-owned pings are submitted automatically

Products do not need to submit Glean built-in pings, as their scheduling is managed internally. The APIs on this page are only relevant for products defining custom pings.

Submission API

submit

Collect and queue a custom ping for eventual uploading.

By default, if the ping doesn't currently have any events or metrics set, submit will do nothing. However, if the send_if_empty flag is set to true in the ping definition, it will always be submitted.

It is not necessary for the caller to check if Glean is disabled before calling submit. If Glean is disabled submit is a no-op.

For example, to submit the custom ping defined in Adding new custom pings:

import org.mozilla.yourApplication.GleanMetrics.Pings
Pings.search.submit(
    Pings.searchReasonCodes.performed
)
import org.mozilla.yourApplication.GleanMetrics.Pings

Pings.INSTANCE.search.submit(
    Pings.INSTANCE.searchReasonCodes.performed
);
import Glean

GleanMetrics.Pings.shared.search.submit(
    reason: .performed
)
from glean import load_pings

pings = load_pings("pings.yaml")

pings.search.submit(pings.search_reason_codes.PERFORMED)
use glean::Pings;

pings::search.submit(pings::SearchReasonCodes::Performed);
import * as pings from "./path/to/generated/files/pings.js";

pings.search.submit(pings.searchReasonCodes.Performed);

C++

mozilla::glean_pings::Search.Submit("performed"_ns);

JavaScript

GleanPings.search.submit("performed");

Testing API

testBeforeNextSubmit

Runs a validation function before the ping is collected.

import org.mozilla.yourApplication.GleanMetrics.Search
import org.mozilla.yourApplication.GleanMetrics.Pings

// Record some data.
Search.defaultEngine.add(5);

// Instruct the ping API to validate the ping data.
var validatorRun = false
Pings.search.testBeforeNextSubmit { reason ->
    assertEquals(Pings.searchReasonCodes.performed, reason)
    assertEquals(5, Search.defaultEngine.testGetValue())
    validatorRun = true
}

// Submit the ping.
Pings.search.submit(
    Pings.searchReasonCodes.performed
)

// Verify that the validator run.
assertTrue(validatorRun)
import org.mozilla.yourApplication.GleanMetrics.Search
import org.mozilla.yourApplication.GleanMetrics.Pings

// Record some data.
Search.INSTANCE.defaultEngine.add(5);

// Instruct the ping API to validate the ping data.
boolean validatorRun = false;
Pings.INSTANCE.search.testBeforeNextSubmit((reason) -> {
    assertEquals(Pings.searchReasonCodes.performed, reason);
    assertEquals(5, Search.INSTANCE.defaultEngine.testGetValue());
    validatorRun = true;
});

// Submit the ping.
Pings.INSTANCE.search.submit(
    Pings.INSTANCE.searchReasonCodes.performed
);

// Verify that the validator run.
assertTrue(validatorRun);
// Record some data.
Search.defaultEngine.add(5)

// Instruct the ping API to validate the ping data.
var validatorRun = false
GleanMetrics.pings.shared.search.testBeforeNextSubmit { reason in
    XCTAssertEqual(.performed, reason, "Unexpected reason for search ping submitted")
    XCTAssertEqual(5, try Search.defaultEngine.testGetValue(), "Unexpected value for default engine in search ping")
    validatorRun = true
}

// Submit the ping.
GleanMetrics.Pings.shared.search.submit(
    reason: .performed
)

// Verify that the validator run.
XCTAssert(validatorRun, "Expected validator to be called by now.")
from glean import load_metrics, load_pings

pings = load_pings("pings.yaml")
metrics = load_metrics("metrics.yaml")

# Record some data.
metrics.search.default_engine.add(5)

# Need a mutable object and plain booleans are not.
callback_was_called = [False]

def check_custom_ping(reason):
    assert reason == pings.search_reason_codes.PERFORMED
    assert 5 == metrics.search.default_engine.test_get_value()
    callback_was_called[0] = True

# Instruct the ping API to validate the ping data.
pings.search.test_before_next_submit(check_custom_ping)

# Submit the ping.
pings.search.submit(pings.search_reason_codes.PERFORMED)

# Verify that the validator run.
assert callback_was_called[0]
use glean_metrics::{search, pings};

// Record some data.
search::default_engine.add(5);

// Instruct the ping API to validate the ping data.
pings::search.test_before_next_submit(move |reason| {
    assert_eq!(pings::SearchReasonCodes::Performed, reason);
    assert_eq!(5, search::default_engine.test_get_value(None).unwrap());
});

// When the `submit` API is not directly called by the
// test code, it may be worth checking that the validator
// function run by using a canary boolean in the closure
// used in `test_before_next_submit` and asserting on its
// value after submission.

// Submit the ping.
pings::search.submit(pings::SearchReasonCodes::Performed);
import * as search from "./path/to/generated/files/search.js";
import * as pings from "./path/to/generated/files/pings.js";

// Record some data.
search.defaultEngine.add(5);

// Instruct the ping API to validate the ping data.
let validatorRun = false;
const p = pings.search.testBeforeNextSubmit(async reason => {
  assert.strictEqual(reason, "performed");
  assert.strictEqual(await search.defaultEngine.testGetValue(), 5);
  validatorRun = true;
});

// Submit the ping.
pings.search.submit("performed");
// Wait for the validation to finish.
assert.doesNotThrow(async () => await p);

// Verify that the validator run.
assert.ok(validatorRun);

JavaScript:

Glean.search.defaultEngine.add(5);
let submitted = false;
GleanPings.search.testBeforeNextSubmit(reason => {
  submitted = true;
  Assert.equal(5, Glean.search.defaultEngine.testGetValue());
});
GleanPings.search.submit();
Assert.ok(submitted);

C++:

mozilla::glean::search::default_engine.Add(5);
bool submitted = false;
mozilla::glean_pings::Search.TestBeforeNextSubmit([&submitted](const nsACString& aReason) {
  submitted = true;
  ASSERT_EQ(false, mozilla::glean::search::default_engine.TestGetValue().unwrap().ref());
});
mozilla::glean_pings::Search.Submit();
ASSERT_TRUE(submitted);