Timespan
Timespans are used to make a measurement of how much time is spent in a particular task.
Irrespective of the timespan's lifetime
, both start
and stop
must occur within the same application session.
To measure the distribution of multiple timespans, see Timing Distributions. To record absolute times, see Datetimes.
It is not recommended to use timespans in multiple threads,
since calling start
or stop
out of order will be recorded as an invalid_state
error.
Recording API
start
Starts tracking time. Uses an internal monotonic timer.
import org.mozilla.yourApplication.GleanMetrics.Auth
fun onShowLogin() {
Auth.loginTime.start()
// ...
}
import org.mozilla.yourApplication.GleanMetrics.Auth;
void onShowLogin() {
Auth.INSTANCE.loginTime().start();
// ...
}
func onShowLogin() {
Auth.loginTime.start()
// ...
}
from glean import load_metrics
metrics = load_metrics("metrics.yaml")
def on_show_login():
metrics.auth.login_time.start()
# ...
use glean_metrics::auth;
fn show_login() {
auth::login_time.start();
// ...
}
import * as auth from "./path/to/generated/files/auth.js";
function onShowLogin() {
auth.loginTime.start();
// ...
}
C++
#include "mozilla/glean/GleanMetrics.h"
void OnShowLogin() {
mozilla::glean::auth::login_time.Start();
// ...
}
JavaScript
function onShowLogin() {
Glean.auth.loginTime.start();
// ...
}
Recorded errors
invalid_state
: If the metric is already tracking time (start
has already been called and notcancel
ed).
Limits
- The maximum resolution of the elapsed duration is limited by the clock used on each platform.
- This also determines the behavior of a timespan over sleep:
- On Android, the
SystemClock.elapsedRealtimeNanos()
function is used, so it is limited by the accuracy and performance of that timer. The time measurement includes time spent in sleep. - On iOS, the
mach_absolute_time
function is used, so it is limited by the accuracy and performance of that timer. The time measurement does not include time spent in sleep. - On Python 3.7 and later,
time.monotonic_ns()
is used. On earlier versions of Python,time.monotonics()
is used, which is not guaranteed to have nanosecond resolution. - On other platforms
time::precise_time_ns
is used, which uses a high-resolution performance counter in nanoseconds provided by the underlying platform.
- On Android, the
stop
Stops tracking time. The metric value is set to the elapsed time.
import org.mozilla.yourApplication.GleanMetrics.Auth
fun onLogin() {
Auth.loginTime.stop()
// ...
}
import org.mozilla.yourApplication.GleanMetrics.Auth;
void onLogin() {
Auth.INSTANCE.loginTime().stop();
// ...
}
func onLogin() {
Auth.loginTime.stop()
// ...
}
from glean import load_metrics
metrics = load_metrics("metrics.yaml")
def on_login():
metrics.auth.login_time.stop()
# ...
use glean_metrics::auth;;
fn login() {
auth::login_time.stop();
// ...
}
import * as auth from "./path/to/generated/files/auth.js";
function onLogin() {
auth.login_time.stop();
// ...
}
C++
#include "mozilla/glean/GleanMetrics.h"
void OnLogin() {
mozilla::glean::auth::login_time.Stop();
// ...
}
JavaScript
function onLogin() {
Glean.auth.loginTime.stop();
// ...
}
Recorded errors
invalid_state
: Callingstop
without callingstart
first, e.g. if thestart
happened on a previous application run.
cancel
Cancels a previous start
.
No error is recorded if there was no previous start
.
import org.mozilla.yourApplication.GleanMetrics.Auth
fun onLoginCancel() {
Auth.loginTime.cancel()
// ...
}
import org.mozilla.yourApplication.GleanMetrics.Auth;
void onLoginCancel() {
Auth.INSTANCE.loginTime().cancel();
// ...
}
func onLoginCancel() {
Auth.loginTime.cancel()
// ...
}
from glean import load_metrics
metrics = load_metrics("metrics.yaml")
def on_login_cancel():
metrics.auth.login_time.cancel()
# ...
use glean_metrics::auth;
fn login_cancel() {
auth::login_time.cancel();
// ...
}
import * as auth from "./path/to/generated/files/auth.js";
function onLoginCancel() {
auth.login_time.cancel();
// ...
}
C++
#include "mozilla/glean/GleanMetrics.h"
void OnLoginCancel() {
mozilla::glean::auth::login_time.Cancel();
// ...
}
JavaScript
function onLoginCancel() {
Glean.auth.loginTime.cancel();
// ...
}
measure
Some languages support convenient auto timing of blocks of code.
measure
is treated as a start
and stop
pair for the purposes of error recording.
Exceptions (if present in the language) are treated as a cancel
.
import org.mozilla.yourApplication.GleanMetrics.Auth
Auth.loginTime.measure {
// Process login flow
}
import org.mozilla.yourApplication.GleanMetrics.Auth
Auth.INSTANCE.loginTime().measure() -> {
// Process login flow
return null;
});
Auth.loginTime.measure {
// Process login flow
}
from glean import load_metrics
metrics = load_metrics("metrics.yaml")
with metrics.auth.login_time.measure():
# ... Do the login ...
setRawNanos
Explicitly sets the timespan's value.
Regardless of the time unit chosen for the metric, this API expects the raw value to be in nanoseconds.
Only use this if you have to
This API should only be used if the code being instrumented cannot make use of
start
,stop
, andcancel
ormeasure
. Time is hard, and this API can't help you with it.
import org.mozilla.yourApplication.GleanMetrics.Auth
fun afterLogin(loginElapsedNs: Long) {
Auth.loginTime.setRawNanos(loginElapsedNs)
// ...
}
import org.mozilla.yourApplication.GleanMetrics.Auth;
void afterLogin(long loginElapsedNs) {
Auth.INSTANCE.loginTime().setRawNanos(loginElapsedNs);
// ...
}
func afterLogin(_ loginElapsedNs: UInt64) {
Auth.loginTime.setRawNanos(loginElapsedNs)
// ...
}
from glean import load_metrics
metrics = load_metrics("metrics.yaml")
def after_login(login_elapsed_ns):
metrics.auth.login_time.set_raw_nanos(login_elapsed_ns)
# ...
use std::time::duration;
use glean_metrics::auth;
fn after_login(login_elapsed: Duration) {
auth::login_time.set_raw(login_elapsed);
// ...
}
import * as auth from "./path/to/generated/files/auth.js";
function onAfterLogin(loginElapsedNs) {
auth.loginTime.setRawNanos(loginElapsedNs);
// ...
}
These are different
Firefox Desktop's
setRaw
uses the units specified in the metric definition. e.g. if the Timespan'stime_unit
ismillisecond
, then the duration parameter is a count of milliseconds.
C++
#include "mozilla/glean/GleanMetrics.h"
void AfterLogin(uint32_t aDuration) {
mozilla::glean::auth::login_time.SetRaw(aDuration);
// ...
}
JavaScript
function afterLogin(aDuration) {
Glean.auth.loginTime.setRaw(aDuration);
// ...
}
Recorded errors
invalid_value
: if attempting to record a negative elapsed duration.invalid_state
: if this method is called after callingstart
or this method is called multiple times.invalid_type
: if a negative, floating point or non-number value is given.
Testing API
testGetValue
Get the currently-stored value.
Returns the timespan as a integer in the metric's time unit 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.Auth
assertTrue(Auth.loginTime.testGetValue() > 0)
import org.mozilla.yourApplication.GleanMetrics.Auth;
assertTrue(Auth.INSTANCE.loginTime().testGetValue() > 0);
XCTAssert(Auth.loginTime.testGetValue() > 0)
from glean import load_metrics
metrics = load_metrics("metrics.yaml")
assert metrics.auth.login_time.test_get_value() > 0
use glean_metrics::auth;
assert!(auth::login_time.test_get_value(None).unwrap() > 0);
import * as auth from "./path/to/generated/files/auth.js";
assert(await auth.loginTime.testGetValue() > 0);
C++
#include "mozilla/glean/GleanMetrics.h"
ASSERT_TRUE(mozilla::glean::auth::login_time.TestGetValue().isOk());
ASSERT_GE(mozilla::glean::auth::login_time.TestGetValue().unwrap().value(), 0);
JavaScript
// testGetValue will throw NS_ERROR_LOSS_OF_SIGNIFICANT_DATA on error.
Assert.ok(Glean.auth.loginTime.testGetValue() > 0);
testGetNumRecordedErrors
Gets the number of errors recorded during operations on this metric.
import org.mozilla.yourApplication.GleanMetrics.Auth
assertEquals(
0,
Auth.loginTime.testGetNumRecordedErrors(ErrorType.INVALID_VALUE)
)
import org.mozilla.yourApplication.GleanMetrics.Auth;
assertEquals(
0,
Auth.INSTANCE.loginTime().testGetNumRecordedErrors(ErrorType.INVALID_VALUE)
);
XCTAssertEqual(0, Auth.loginTime.testGetNumRecordedErrors(.invalidValue))
from glean import load_metrics
metrics = load_metrics("metrics.yaml")
assert 0 == metrics.auth.local_time.test_get_num_recorded_errors(
ErrorType.INVALID_VALUE
)
use glean_metrics::auth;
assert_eq!(1, auth::login_time.test_get_num_recorded_errors(ErrorType::InvalidValue));
import * as auth from "./path/to/generated/files/auth.js";
import { ErrorType } from "@mozilla/glean/error";;
assert.strictEqual(
1,
await auth.loginTime.testGetNumRecordedErrors(ErrorType.InvalidValue)
);
Metric parameters
Example timespan metric definition:
auth:
login_time:
type: timespan
description: >
Measures the time spent logging in.
time_unit: millisecond
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=000000
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=000000#c3
notification_emails:
- me@mozilla.com
expires: 2020-01-01
data_sensitivity:
- interaction
For a full reference on metrics parameters common to all metric types, refer to the metrics YAML registry format reference page.
Extra metric parameters
time_unit
Timespans have an optional time_unit
parameter to specify the smallest unit of resolution that the timespan will record.
The allowed values for time_unit
are:
nanosecond
microsecond
millisecond
(default)second
minute
hour
day
Consider the resolution that is required by your metric, and use the largest possible value that will provide useful information so as to not leak too much fine-grained information from the client.
Values are truncated
It is important to note that the value sent in the ping is truncated down to the nearest unit. Therefore, a measurement of 500 nanoseconds will be truncated to 0 microseconds.
Data questions
- How long did it take for the user to log in?