Rate

Used to count how often something happens relative to how often something else happens. Like how many documents use a particular CSS Property, or how many HTTP connections had an error. You can think of it like a fraction, with a numerator and a denominator.

All rates start without a value. A rate with a numerator of 0 is valid and will be sent to ensure we capture the "no errors happened" or "no use counted" cases.

Let the Glean metric do the counting

When using a rate metric, it is important to let the Glean metric do the counting. Using your own variable for counting and setting the metric yourself could be problematic: ping scheduling will make it difficult to ensure the metric is at the correct value at the correct time. Instead, count to the numerator and denominator as you go.

Recording API

addToNumerator / addToDenominator

Numerators and denominators need to be counted individually.

import org.mozilla.yourApplication.GleanMetrics.Network

if (connectionHadError) {
    Network.httpConnectionError.addToNumerator(1)
}

Network.httpConnectionError.addToDenominator(1)

External Denominators

If the rate uses an external denominator, adding to the denominator must be done through the denominator's counter API:

import org.mozilla.yourApplication.GleanMetrics.Network

if (connectionHadError) {
    Network.httpConnectionError.addToNumerator(1)
}

Network.httpConnections.add(1)
import org.mozilla.yourApplication.GleanMetrics.Network;

if (connectionHadError) {
    Network.INSTANCE.httpConnectionError().addToNumerator(1);
}

Network.IMPORTANT.httpConnectionError().addToDenominator(1);

External Denominators

If the rate uses an external denominator, adding to the denominator must be done through the denominator's counter API:

import org.mozilla.yourApplication.GleanMetrics.Network;

if (connectionHadError) {
    Network.INSTANCE.httpConnectionError().addToNumerator(1);
}

Network.INSTANCE.httpConnections().add(1)
if (connectionHadError) {
    Network.httpConnectionError.addToNumerator(1)
}

Network.httpConnectionError.addToDenominator(1)

External Denominators

If the rate uses an external denominator, adding to the denominator must be done through the denominator's counter API:

if (connectionHadError) {
    Network.httpConnectionError.addToNumerator(1)
}

Network.httpConnections.add(1)
from glean import load_metrics
metrics = load_metrics("metrics.yaml")

if connection_had_error:
    metrics.network.http_connection_error.add_to_numerator(1)

metrics.network.http_connection_error.add_to_denominator(1)

External Denominators

If the rate uses an external denominator, adding to the denominator must be done through the denominator's counter API:

from glean import load_metrics
metrics = load_metrics("metrics.yaml")

if connection_had_error:
    metrics.network.http_connection_error.add_to_numerator(1)

metrics.network.http_connections.add(1)
use glean_metrics::network;

if connection_had_error {
    network::http_connection_error.add_to_numerator(1);
}

network::http_connection_error.add_to_denominator(1);

External Denominators

If the rate uses an external denominator, adding to the denominator must be done through the denominator's counter API:

use glean_metrics::network;

if connection_had_error {
    network::http_connection_error.add_to_numerator(1);
}

network::http_connections.add(1);
import * as network from "./path/to/generated/files/network.js";

if (connectionHadError) {
  network.httpConnectionError.addToNumerator(1);
}

network.httpConnectionError.addToDenominator(1);

C++

#include "mozilla/glean/GleanMetrics.h"

if (aHadError) {
mozilla::glean::network::http_connection_error.AddToNumerator(1);
}
mozilla::glean::network::http_connection_error.AddToDenominator(1);

JavaScript

if (aHadError) {
Glean.network.httpConnectionError.addToNumerator(1);
}
Glean.network.httpConnectionError.addToDenominator(1);

Recorded errors

  • invalid_value: If either numerator or denominator is incremented by a negative value.
  • invalid_type: If a floating point or non-number value is given.

Limits

  • Numerator and Denominator only increment.
  • Numerator and Denominator saturate at the largest value that can be represented as a 32-bit signed integer (2147483647).

Testing API

testGetValue

Gets the recorded value for a given rate metric.
Returns the numerator/denominator pair if data is stored.
Returns a language-specific empty/null value if no data is stored. Has an optional argument to specify the name of the ping you wish to retrieve data from, except in Rust where it's required. None or no argument will default to the first value found for send_in_pings.

import org.mozilla.yourApplication.GleanMetrics.Network

assertEquals(Rate(1, 1), Network.httpConnectionError.testGetValue())
import org.mozilla.yourApplication.GleanMetrics.Network;

assertEquals(Rate(1, 1), Network.INSTANCE.httpConnectionError().testGetValue());
XCTAssertEqual(
    Rate(numerator: 1, denominator: 1),
    Network.httpConnectionError.testGetValue()
)
from glean import load_metrics
metrics = load_metrics("metrics.yaml")

assert Rate(1, 1) == metrics.network.http_connection_error.test_get_value()
use glean_metrics::network;

let rate = network::http_connection_error.test_get_value(None).unwrap();
assert_eq!(1, rate.numerator);
assert_eq!(1, rate.denominator);
import * as network from "./path/to/generated/files/network.js";

const { numerator, denominator } = await network.httpConnectionError.testGetValue();
assert.strictEqual(numerator, 1);
assert.strictEqual(denominator, 1);

C++

#include "mozilla/glean/GleanMetrics.h"

auto pair = mozilla::glean::network::http_connection_error.TestGetValue().unwrap();
ASSERT_EQ(1, pair.first);
ASSERT_EQ(1, pair.second);

JavaScript

// testGetValue will throw NS_ERROR_LOSS_OF_SIGNIFICANT_DATA on error.
Assert.deepEqual(
{ numerator: 1, denominator: 1 },
Glean.network.httpConnectionError.testGetValue()
);

testGetNumRecordedErrors

import org.mozilla.yourApplication.GleanMetrics.Network

assertEquals(
    0,
    Network.httpConnectionError.testGetNumRecordedErrors(ErrorType.INVALID_VALUE)
)
import org.mozilla.yourApplication.GleanMetrics.Network;

assertEquals(
    0,
    Network.INSTANCE.httpConnectionError().testGetNumRecordedErrors(
        ErrorType.INVALID_VALUE
    )
);
XCTAssertEqual(
    0,
    Network.httpConnectionError.testGetNumRecordedErrors(.invalidValue)
)
from glean import load_metrics
metrics = load_metrics("metrics.yaml")

from glean.testing import ErrorType

assert 0 == metrics.network.http_connection_error.test_get_num_recorded_errors(
    ErrorType.INVALID_VALUE
)
use glean::ErrorType;
use glean_metrics::network;

assert_eq!(
    0,
    network::http_connection_error.test_get_num_recorded_errors(
        ErrorType::InvalidValue,
        None
    )
);
import * as network from "./path/to/generated/files/network.js";
import { ErrorType } from "@mozilla/glean/error";

assert.strictEqual(
  1,
  await network.httpConnectionError.testGetNumRecordedErrors(ErrorType.InvalidValue)
);

Metric parameters

Example rate metric definition:

network:
  http_connection_error:
    type: rate
    description: >
      How many HTTP connections error out out of the total connections made.
    bugs:
      - https://bugzilla.mozilla.org/000000
    data_reviews:
      - https://bugzilla.mozilla.org/show_bug.cgi?id=000000#c3
    notification_emails:
      - me@mozilla.com
    expires: 2020-10-01

For a full reference on metrics parameters common to all metric types, refer to the metrics YAML registry format reference page.

External Denominators

If several rates share the same denominator then the denominator should be defined as a counter and shared between rates using the denominator_metric property:

network:
  http_connections:
    type: counter
    description: >
      Total number of http connections made.
    ...

  http_connection_error:
    type: rate
    description: >
      How many HTTP connections error out out of the total connections made.
    denominator_metric: network.http_connections
    ...

  http_connection_slow:
    type: rate
    description: >
      How many HTTP connections were slow, out of the total connections made.
    denominator_metric: network.http_connections
    ...

The Glean JavaScript SDK does not support external denominators for Rate metrics, yet. Follow Bug 1745753 for updates on that features development.

Data Questions

  • How often did an HTTP connection error?
  • How many documents used a given CSS Property?

Reference