# 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/.
import sys
from os
import path
import yaml
header =
"""
# 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/.
# THIS FILE IS AUTO-GENERATED BY glean_metrics.py. DO NOT EDIT!
"""
source_path = path.join(path.dirname(__file__),
"generated_metrics.yaml")
def make_bugzilla_url(bug):
return f
"https://bugzilla.mozilla.org/{bug}"
def remove_non_glean_fields(glean):
"""Remove all known fields in the glean descriptor which aren't directly
forwarded to the glean metrics definition file.
"""
if glean[
"type"] ==
"string_list":
glean.pop(
"delimiter")
glean.pop(
"custom_convert",
None)
def generate_string(annotations):
output = {
"$schema":
"moz://mozilla.org/schemas/glean/metrics/2-0-0",
"$tags": [
"Toolkit :: Crash Reporting"],
}
for name, definition
in annotations:
glean = definition.get(
"glean")
if glean
is None:
continue
metric_category, _, metric_name = glean.pop(
"metric").rpartition(
".")
remove_non_glean_fields(glean)
bug_urls = [
make_bugzilla_url(bug)
for bug
in definition.get(
"bugs", [
"1950749"])
]
glean.update({
"description": definition[
"description"].strip(),
"notification_emails": [
"crash-reporting-wg@mozilla.org",
"stability@mozilla.org",
],
"bugs": bug_urls,
"data_reviews": bug_urls.copy(),
# Copy so the produced yaml doesn't use anchors
"data_sensitivity": [
"technical"],
"expires":
"never",
"send_in_pings": [
"crash"],
})
output.setdefault(metric_category, {})[metric_name] = glean
return header + yaml.safe_dump(output, explicit_start=
True)
def import_path(mod, path):
import importlib.util
spec = importlib.util.spec_from_file_location(mod, path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def main(output, annotations_path):
with open(annotations_path)
as annotations_file:
annotations = yaml.safe_load(annotations_file)
out = generate_string(annotations)
# Check whether the source path contents match what we would generate.
source_contents =
""
if path.exists(source_path):
with open(source_path)
as file:
source_contents = file.read()
if source_contents != out:
sys.exit(f
"{source_path} contents outdated; run ./mach crash-ping-metrics")
output.write(out)
return {source_path}
if __name__.startswith(
"mach.commands"):
from mach.decorators
import Command
@Command(
"crash-ping-metrics",
category=
"misc",
description=
"Generate the crash ping annotations Glean metrics files.",
)
def crash_ping_metrics(command_context):
load = import_path(
"annotations.load",
path.join(path.dirname(__file__),
"..",
"annotations",
"load.py"),
)
annotations = load.read_annotations()
with open(source_path,
"w")
as file:
file.write(generate_string(annotations))