# Labeled Counters

Labeled counters are used to record different related counts that should sum up to a total. Each counter always starts from 0. Each time you record to a labeled counter, its value is incremented. Unless incremented by a positive value, a counter will not be reported in pings, that means: the value 0 is never sent in a ping.

## Recording API

### add

Increases one of the labels in a labeled counter metric by a certain amount. If no amount is passed it defaults to 1.

import org.mozilla.yourApplication.GleanMetrics.Stability


import org.mozilla.yourApplication.GleanMetrics.Stability;


Stability.crashCount["uncaught_exception"].add() // Adds 1 to the "uncaught_exception" counter.

from glean import load_metrics

# Adds 1 to the "uncaught_exception" counter.
# Adds 3 to the "native_code_crash" counter.

use glean_metrics::stability;


import * as stability from "./path/to/generated/files/stability.js";

// Adds 1 to the "uncaught_exception" counter.
// Adds 3 to the "native_code_crash" counter.


C++

#include "mozilla/glean/GleanMetrics.h"



JavaScript

Glean.stability.crashCount.uncaught_exception.add(1);


#### Recorded Errors

• invalid_value: if the counter is incremented by 0 or a negative value.
• invalid_type: if a floating point or non-number value is given.
• invalid_label:
• If the label contains invalid characters. Data is still recorded to the special label __other__.
• If the label exceeds the maximum number of allowed characters. Data is still recorded to the special label __other__.

#### Limits

• Only increments
• Saturates at the largest value that can be represented as a 32-bit signed integer.
• Labels must conform to the label formatting regular expression.
• Each label must have a maximum of 60 bytes, when encoded as UTF-8.
• The list of labels is limited to:
• 16 different dynamic labels if no static labels are defined. Additional labels will all record to the special label __other__.
• 100 labels if specified as static labels in metrics.yaml, see Labels. Unknown labels will be recorded under the special label __other__.

## Testing API

### testGetValue

Gets the recorded value for a given label in a labeled counter metric.
Returns the count if data is stored.
Returns a language-specific empty/null value if no data is stored.

import org.mozilla.yourApplication.GleanMetrics.Stability

// Do the counters have the expected values?
assertEquals(1, Stability.crashCount["uncaught_exception"].testGetValue())
assertEquals(3, Stability.crashCount["native_code_crash"].testGetValue())

import org.mozilla.yourApplication.GleanMetrics.Stability;

// Do the counters have the expected values?
assertEquals(1, Stability.INSTANCE.crashCount()["uncaught_exception"].testGetValue());
assertEquals(3, Stability.INSTANCE.crashCount()["native_code_crash"].testGetValue());

// Do the counters have the expected values?
XCTAssertEqual(1, Stability.crashCount["uncaught_exception"].testGetValue())
XCTAssertEqual(3, Stability.crashCount["native_code_crash"].testGetValue())

from glean import load_metrics

# Do the counters have the expected values?
assert 1 == metrics.stability.crash_count["uncaught_exception"].test_get_value()
assert 3 == metrics.stability.crash_count["native_code_crash"].test_get_value()

use glean_metrics::stability;

// Do the counters have the expected values?
assert_eq!(1, stability::crash_count.get("uncaught_exception").test_get_value().unwrap());
assert_eq!(3, stability::crash_count.get("native_code_crash").test_get_value().unwrap());

import * as stability from "./path/to/generated/files/stability.js";

// Do the counters have the expected values?
assert.strictEqual(1, await stability.crashCount["uncaught_exception"].testGetValue());
assert.strictEqual(3, await stability.crashCount["native_code_crash"].testGetValue());


C++

#include "mozilla/glean/GleanMetrics.h"

ASSERT_EQ(
1,
mozilla::glean::stability::crash_count.Get("uncaught_exception"_ns).TestGetValue().unwrap().ref());
ASSERT_EQ(
3,
mozilla::glean::stability::crash_count.Get("native_code_crash"_ns).TestGetValue().unwrap().ref());


JavaScript

Assert.equal(1, Glean.stability.crashCount["uncaught_exception"].testGetValue());
Assert.equal(3, Glean.stability.crashCount.native_code_crash.testGetValue());


### testGetNumRecordedErrors

Gets the number of errors recorded for a given labeled counter metric in total.

import org.mozilla.yourApplication.GleanMetrics.Stabilit

// Were there any invalid labels?
assertEquals(
0,
Stability.crashCount.testGetNumRecordedErrors(ErrorType.INVALID_LABEL)
)

import org.mozilla.yourApplication.GleanMetrics.Stability;

// Were there any invalid labels?
assertEquals(
0,
Stability.INSTANCE.crashCount().testGetNumRecordedErrors(ErrorType.INVALID_LABEL)
);

// Were there any invalid labels?
XCTAssertEqual(0, Stability.crashCount.testGetNumRecordedErrors(.invalidLabel))

from glean import load_metrics

# Were there any invalid labels?
assert 0 == metrics.stability.crash_count.test_get_num_recorded_errors(
ErrorType.INVALID_LABEL
)

use glean::ErrorType;

use glean_metrics::stability;

// Were there any invalid labels?
assert_eq!(
0,
stability::crash_count.test_get_num_recorded_errors(
ErrorType::InvalidLabel
)
);

import * as stability from "./path/to/generated/files/stability.js";
import { ErrorType } from "@mozilla/glean/error";

// Were there any invalid labels?
assert(
0,
await stability.crashCount.testGetNumRecordedErrors(ErrorType.InvalidLabel)
);


## Metric parameters

Example labeled counter metric definition:

accessibility:
features:
type: labeled_counter
description: >
Counts the number of crashes that occur in the application.
bugs:
- https://bugzilla.mozilla.org/000000
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=000000#c3
- me@mozilla.com
expires: 2020-10-01
labels:
- uncaught_exception
- native_code_crash
...


### Extra metric parameters

#### labels

Labeled metrics may have an optional labels parameter, containing a list of known labels. The labels in this list must match the following requirements:

##### Important

If the labels are specified in the metrics.yaml, using any label not listed in that file will be replaced with the special value __other__.

If the labels are not specified in the metrics.yaml, only 16 different dynamic labels may be used, after which the special value __other__ will be used.

Removing or changing labels, including their order in the registry file, is permitted. Avoid reusing labels that were removed in the past. It is best practice to add documentation about removed labels to the description field so that analysts will know of their existence and meaning in historical data. Special care must be taken when changing GeckoView metrics sent through the Glean SDK, as the index of the labels is used to report Gecko data through the Glean SDK.

## Data questions

• How many times did different types of crashes occur?