diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:37 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:37 +0000 |
commit | a90a5cba08fdf6c0ceb95101c275108a152a3aed (patch) | |
tree | 532507288f3defd7f4dcf1af49698bcb76034855 /third_party/python/glean_parser | |
parent | Adding debian version 126.0.1-1. (diff) | |
download | firefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.tar.xz firefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.zip |
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/python/glean_parser')
18 files changed, 284 insertions, 56 deletions
diff --git a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/AUTHORS.md b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/AUTHORS.md index 525116ee7e..525116ee7e 100644 --- a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/AUTHORS.md +++ b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/AUTHORS.md diff --git a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/LICENSE b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/LICENSE index a612ad9813..a612ad9813 100644 --- a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/LICENSE +++ b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/LICENSE diff --git a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/METADATA b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/METADATA index 0bab2150ba..65030fd86b 100644 --- a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/METADATA +++ b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 -Name: glean-parser -Version: 13.0.1 +Name: glean_parser +Version: 14.0.1 Summary: Parser tools for Mozilla's Glean telemetry Home-page: https://github.com/mozilla/glean_parser Author: The Glean Team @@ -77,7 +77,16 @@ $ glean_parser check < ping.json # Changelog -## Unreleased +## 14.0.1 + +- BUGFIX: Fix missing `ping_arg` in util.py ([#687](https://github.com/mozilla/glean_parser/pull/687)) + +## 14.0.0 + +- BREAKING CHANGE: Expose the optional `enabled` property on pings, defaulting to `enabled: true` ([#681](https://github.com/mozilla/glean_parser/pull/681)) +- BREAKING CHANGE: Support metadata field `ping_schedule` for pings ([bug 1804711](https://bugzilla.mozilla.org/show_bug.cgi?id=1804711)) +- Add support for event metric type in server JavaScript outputter ([DENG-2407](https://mozilla-hub.atlassian.net/browse/DENG-2407)) +- Add Swift and Kotlin codegen support for the object metric type object ([#685](https://github.com/mozilla/glean_parser/pull/685)) ## 13.0.1 diff --git a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/RECORD b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/RECORD index 8ebf523fd7..700ca80797 100644 --- a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/RECORD +++ b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/RECORD @@ -4,45 +4,45 @@ glean_parser/coverage.py,sha256=2IwC4XMDtDamMkBFoYilmqJzW4gyypq65YVCur8SNas,4405 glean_parser/data_review.py,sha256=BweeeTkNNS6HrIDkztawhbDByrk_-Avxpg7YeST3VAs,2152 glean_parser/go_server.py,sha256=s6lxK9IAFY55pNl3Rv4MHlV-nQwSoyhO9ppTQE9VCik,5346 glean_parser/javascript.py,sha256=w4ZhNBHBKWYk0h3t7G0Ud2tR__hRqzn9dlEXNKLdQrA,11230 -glean_parser/javascript_server.py,sha256=x75JfOaveEkPQe3ozYXdtDb1Zks-PxzncDOizsJbYos,7972 -glean_parser/kotlin.py,sha256=5z8_74xlqvHDsedwZhGf1_qb7swPEgIZumkJIuj3ef8,12598 +glean_parser/javascript_server.py,sha256=PZSTl63TR3cY8Y99jXMOLu-8rzgQarymzjnHJm9aYK0,8389 +glean_parser/kotlin.py,sha256=5nXnen4s2YOj503Z77HVTUgDHWdulB8BMl8vOie38o4,13365 glean_parser/lint.py,sha256=STqdgyOhR4Q3fHivSizgn9bOOyqrNHhzjaqyJxz6qzI,19948 glean_parser/markdown.py,sha256=GkCr1CrV6mnRQseT6FO1-JJ7Eup8X3lxUfRMBTxXpe4,9066 glean_parser/metrics.py,sha256=YAO8wPuRHTLkdT9M4zh9ZwoFI1_VS8O9oQqwZNYyDp0,14612 -glean_parser/parser.py,sha256=cUOnvSXKfEBg8YTpRcWiPcMwpFpK1TTqsVO_zjUtpR4,15309 -glean_parser/pings.py,sha256=AQ-fBmIx2GKQv6J2NyTFfHHZzSnApZZoC770LlstkoI,3180 +glean_parser/parser.py,sha256=3-uF-Hi5LlvdFc1NxZOKX0EoEyekZGnZV094eTIJut0,16361 +glean_parser/pings.py,sha256=-CIiMBVOTFULmNybV8YTFI7vmfOYOGQ5TD9hEfYPUII,3435 glean_parser/python_server.py,sha256=ERpYcbSwF19xKFagxX0mZAvlR1y6D7Ah5DSvW8LipCY,4791 glean_parser/ruby_server.py,sha256=e5lkfcLQAUMUBQDCjqNU82LkdUzT5x-G6HOnsUInbsU,5190 glean_parser/rust.py,sha256=UEHeIZlToxCBelfec5sl_l_uLZfk8f_OUXqa_ZoEvnk,7330 -glean_parser/swift.py,sha256=T1BSGahd9wUd6VDeNC89SdN6M34jKXDlydMpSI0QLOs,8379 +glean_parser/swift.py,sha256=paUzF6tItdktFwIQYCKsYpqXfn8zxR2coU_jMYrmwlc,8957 glean_parser/tags.py,sha256=bemKYvcbMO4JrghiNSe-A4BNNDtx_FlUPkgrPPJy84Y,1391 glean_parser/translate.py,sha256=luKQoraARZ2tjenHs0SVtCxflnYaMkzPYFfKEdKdSqQ,8403 glean_parser/translation_options.py,sha256=Lxzr6G7MP0tC_ZYlZXftS4j0SLiqO-5mGVTEc7ggXis,2037 -glean_parser/util.py,sha256=v81watw5nSPGRlFNNpTb7iUv9NZObiFIbyyg2oZ6EnY,16149 +glean_parser/util.py,sha256=wftmoWBUQM_o7pUwdhBp3HuDCVHIBw1PXtrfxwPLD0Q,16187 glean_parser/validate_ping.py,sha256=0TNvILH6dtzJDys3W8Kqorw6kk03me73OCUDtpoHcXU,2118 glean_parser/schemas/metrics.1-0-0.schema.yaml,sha256=cND3cvi6iBfPUVmtfIBQfGJV9AALpbvN7nu8E33_J-o,19566 glean_parser/schemas/metrics.2-0-0.schema.yaml,sha256=wx1q0L4C0-Vcwk1SPU6t8OfjDEQvgrwwEG6xfSHO1MI,26365 glean_parser/schemas/pings.1-0-0.schema.yaml,sha256=hwCnsKpEysmrmVp-QHGBArEkVY3vaU1rVsxlTwhAzws,4315 -glean_parser/schemas/pings.2-0-0.schema.yaml,sha256=vDyvFT8KwAwaqyWHG4y6pFNrsc3NO7OyDDagA2eTeqM,5415 +glean_parser/schemas/pings.2-0-0.schema.yaml,sha256=f8PClAlMoLTmX6ANq8Ai0CpiE74i3LOgU5SoTJpoh0M,6149 glean_parser/schemas/tags.1-0-0.schema.yaml,sha256=OGXIJlvvVW1vaqB_NVZnwKeZ-sLlfH57vjBSHbj6DNI,1231 glean_parser/templates/data_review.jinja2,sha256=jeYU29T1zLSyu9fKBBFu5BFPfIw8_hmOUXw8RXhRXK8,3287 glean_parser/templates/go_server.jinja2,sha256=Jy1e0uQqr_WZNoj-AWnygRmygX2jyj_GQMMV8mSah2k,6825 glean_parser/templates/javascript.buildinfo.jinja2,sha256=4mXiZCQIk9if4lxlA05kpSIL4a95IdwGwqle2OqqNAs,474 glean_parser/templates/javascript.jinja2,sha256=cT_bG-jC6m4afECXmcsqHwiiHjRuVtJnfv90OD2Mwxw,2669 -glean_parser/templates/javascript_server.jinja2,sha256=H991yQOKJMwSgM0bLEA-Q5Z15LWsfEPh6bTYz_owSCU,9423 +glean_parser/templates/javascript_server.jinja2,sha256=k-XI3QIhHQ1vbIPqSMTmCu93b1oZhm7KLmx9LfO3IJ0,9472 glean_parser/templates/kotlin.buildinfo.jinja2,sha256=X0lk2SNu5OIIj2i6mUyF9CWFQIonLgfqkgT5fA-5G6c,920 glean_parser/templates/kotlin.geckoview.jinja2,sha256=MJOgtoDXmBjE9pwk-G6T89y36RZuMbDWM_-DBN_gFJo,5099 -glean_parser/templates/kotlin.jinja2,sha256=3DqUMXJRkmTvSp_5IRyvGmw5iXYWdox7coMFe3YDxcc,5247 +glean_parser/templates/kotlin.jinja2,sha256=npMgDdWD9OItOZQ-dyLQZn_IKgnzee2EdJynhUa1ig8,7690 glean_parser/templates/markdown.jinja2,sha256=vAHHGGm28HRDPd3zO_wQMAUZIuxE9uQ7hl3NpXxcKV4,3425 glean_parser/templates/python_server.jinja2,sha256=gu2C1rkn760IqBCG2SWaK7o32T1ify94wDEsudLPUg8,7260 glean_parser/templates/qmldir.jinja2,sha256=m6IGsp-tgTiOfQ7VN8XW6GqX0gJqJkt3B6Pkaul6FVo,156 glean_parser/templates/ruby_server.jinja2,sha256=vm4BEenOqzomQNTLFfMOzlWHARnsWUjTBbnR-v2cadI,6247 -glean_parser/templates/rust.jinja2,sha256=wlV0OZvV3Mk2ulrqFkN1vGjdsahsupEy2TQvWxQKzww,5439 -glean_parser/templates/swift.jinja2,sha256=xkvVsTpfK0QK3tI32wGqzxm2hqFNaBQ6Y71rKIsCmAI,4944 -glean_parser-13.0.1.dist-info/AUTHORS.md,sha256=yxgj8MioO4wUnrh0gmfb8l3DJJrf-l4HmmEDbQsbbNI,455 -glean_parser-13.0.1.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725 -glean_parser-13.0.1.dist-info/METADATA,sha256=UYz6ZRXyv3ODi3yl2vRQHZVdm0XGerFp8pIOGWGwOKw,31604 -glean_parser-13.0.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92 -glean_parser-13.0.1.dist-info/entry_points.txt,sha256=mf9d3sv8BwSjjR58x9KDnpVkONCnv3fPQC2NjJl15Xg,68 -glean_parser-13.0.1.dist-info/top_level.txt,sha256=q7T3duD-9tYZFyDry6Wv2LcdMsK2jGnzdDFhxWcT2Z8,13 -glean_parser-13.0.1.dist-info/RECORD,, +glean_parser/templates/rust.jinja2,sha256=Ir_JqWRIUs1KLoYNDolgTRjWfWdzzBfouCP-YeTJa-c,5495 +glean_parser/templates/swift.jinja2,sha256=4f993l_zZk_Tz1efiz3nbvDK1H3Uq3dWQ2T6glT9XQ4,6695 +glean_parser-14.0.1.dist-info/AUTHORS.md,sha256=yxgj8MioO4wUnrh0gmfb8l3DJJrf-l4HmmEDbQsbbNI,455 +glean_parser-14.0.1.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725 +glean_parser-14.0.1.dist-info/METADATA,sha256=Ghvw-Y7woQUJ38P8TYT5TFt8sL61GJoZPBajaB0WLeQ,32276 +glean_parser-14.0.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92 +glean_parser-14.0.1.dist-info/entry_points.txt,sha256=mf9d3sv8BwSjjR58x9KDnpVkONCnv3fPQC2NjJl15Xg,68 +glean_parser-14.0.1.dist-info/top_level.txt,sha256=q7T3duD-9tYZFyDry6Wv2LcdMsK2jGnzdDFhxWcT2Z8,13 +glean_parser-14.0.1.dist-info/RECORD,, diff --git a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/WHEEL b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/WHEEL index bab98d6758..bab98d6758 100644 --- a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/WHEEL +++ b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/WHEEL diff --git a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/entry_points.txt b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/entry_points.txt index 08fde9d655..08fde9d655 100644 --- a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/entry_points.txt +++ b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/entry_points.txt diff --git a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/top_level.txt b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/top_level.txt index a7f3a37918..a7f3a37918 100644 --- a/third_party/python/glean_parser/glean_parser-13.0.1.dist-info/top_level.txt +++ b/third_party/python/glean_parser/glean_parser-14.0.1.dist-info/top_level.txt diff --git a/third_party/python/glean_parser/glean_parser/javascript_server.py b/third_party/python/glean_parser/glean_parser/javascript_server.py index f5099d2660..060575f38c 100644 --- a/third_party/python/glean_parser/glean_parser/javascript_server.py +++ b/third_party/python/glean_parser/glean_parser/javascript_server.py @@ -42,9 +42,12 @@ from . import util SUPPORTED_METRIC_TYPES = ["string", "event"] -def event_class_name(ping_name: str, event_metric_exists: bool) -> str: +def event_class_name( + ping_name: str, metrics_by_type: Dict[str, List[metrics.Metric]] +) -> str: # For compatibility with FxA codebase we don't want to add "Logger" suffix # when custom pings without event metrics are used. + event_metric_exists = "event" in metrics_by_type suffix = "Logger" if event_metric_exists else "" return util.Camelize(ping_name) + "ServerEvent" + suffix @@ -61,10 +64,13 @@ def generate_js_metric_type(metric: metrics.Metric) -> str: return metric.type -def generate_ping_factory_method(ping: str, event_metric_exists: bool) -> str: +def generate_ping_factory_method( + ping: str, metrics_by_type: Dict[str, List[metrics.Metric]] +) -> str: # `ServerEventLogger` better describes role of the class that this factory # method generates, but for compatibility with existing FxA codebase # we use `Event` suffix if no event metrics are defined. + event_metric_exists = "event" in metrics_by_type suffix = "ServerEventLogger" if event_metric_exists else "Event" return f"create{util.Camelize(ping)}{suffix}" @@ -136,6 +142,12 @@ def output( metrics_list = metrics_by_type.setdefault(metric.type, []) metrics_list.append(metric) + # Order pings_to_metrics for backwards compatibility with the existing FxA codebase. + # Put pings without `event` type metrics first. + ping_to_metrics = dict( + sorted(ping_to_metrics.items(), key=lambda item: "event" in item[1]) + ) + PING_METRIC_ERROR_MSG = ( " Server-side environment is simplified and this" + " parser doesn't generate individual metric files. Make sure to pass all" diff --git a/third_party/python/glean_parser/glean_parser/kotlin.py b/third_party/python/glean_parser/glean_parser/kotlin.py index 82cc63d237..6d9ea8dcf8 100644 --- a/third_party/python/glean_parser/glean_parser/kotlin.py +++ b/third_party/python/glean_parser/glean_parser/kotlin.py @@ -107,6 +107,11 @@ def type_name(obj: Union[metrics.Metric, pings.Ping]) -> str: return "{}<{}>".format(class_name(obj.type), generic) + generate_structure = getattr(obj, "_generate_structure", []) + if len(generate_structure): + generic = util.Camelize(obj.name) + "Object" + return "{}<{}>".format(class_name(obj.type), generic) + return class_name(obj.type) @@ -125,6 +130,21 @@ def extra_type_name(typ: str) -> str: return "UNSUPPORTED" +def structure_type_name(typ: str) -> str: + """ + Returns the corresponding Kotlin type for structure items. + """ + + if typ == "boolean": + return "Boolean" + elif typ == "string": + return "String" + elif typ == "number": + return "Int" + else: + return "UNSUPPORTED" + + def class_name(obj_type: str) -> str: """ Returns the Kotlin class name for a given metric or ping type. @@ -320,6 +340,7 @@ def output_kotlin( ("type_name", type_name), ("extra_type_name", extra_type_name), ("class_name", class_name), + ("structure_type_name", structure_type_name), ), ) @@ -333,6 +354,9 @@ def output_kotlin( has_labeled_metrics = any( getattr(metric, "labeled", False) for metric in category_val.values() ) + has_object_metrics = any( + isinstance(metric, metrics.Object) for metric in category_val.values() + ) with filepath.open("w", encoding="utf-8") as fd: fd.write( @@ -346,6 +370,7 @@ def output_kotlin( ping_args=util.ping_args, namespace=namespace, has_labeled_metrics=has_labeled_metrics, + has_object_metrics=has_object_metrics, glean_namespace=glean_namespace, ) ) diff --git a/third_party/python/glean_parser/glean_parser/parser.py b/third_party/python/glean_parser/glean_parser/parser.py index 5ca584ac1e..158676be73 100644 --- a/third_party/python/glean_parser/glean_parser/parser.py +++ b/third_party/python/glean_parser/glean_parser/parser.py @@ -11,7 +11,7 @@ Code for parsing metrics.yaml files. import functools from pathlib import Path import textwrap -from typing import Any, Dict, Generator, Iterable, Optional, Tuple, Union +from typing import Any, cast, Dict, Generator, Iterable, Optional, Set, Tuple, Union import jsonschema # type: ignore from jsonschema.exceptions import ValidationError # type: ignore @@ -267,6 +267,7 @@ def _instantiate_pings( """ global_no_lint = content.get("no_lint", []) assert isinstance(global_no_lint, list) + ping_schedule_reverse_map: Dict[str, Set[str]] = dict() for ping_key, ping_val in sorted(content.items()): if ping_key.startswith("$"): @@ -284,6 +285,22 @@ def _instantiate_pings( if not isinstance(ping_val, dict): raise TypeError(f"Invalid content for ping {ping_key}") ping_val["name"] = ping_key + + if "metadata" in ping_val and "ping_schedule" in ping_val["metadata"]: + if ping_key in ping_val["metadata"]["ping_schedule"]: + yield util.format_error( + filepath, + f"For ping '{ping_key}'", + "ping_schedule contains its own ping name", + ) + continue + for ping_schedule in ping_val["metadata"]["ping_schedule"]: + if ping_schedule not in ping_schedule_reverse_map: + ping_schedule_reverse_map[ping_schedule] = set() + ping_schedule_reverse_map[ping_schedule].add(ping_key) + + del ping_val["metadata"]["ping_schedule"] + try: ping_obj = Ping( defined_in=getattr(ping_val, "defined_in", None), @@ -313,6 +330,11 @@ def _instantiate_pings( all_objects.setdefault("pings", {})[ping_key] = ping_obj sources[ping_key] = filepath + for scheduler, scheduled in ping_schedule_reverse_map.items(): + if isinstance(all_objects["pings"][scheduler], Ping): + scheduler_obj: Ping = cast(Ping, all_objects["pings"][scheduler]) + scheduler_obj.schedules_pings = sorted(list(scheduled)) + def _instantiate_tags( all_objects: ObjectTree, diff --git a/third_party/python/glean_parser/glean_parser/pings.py b/third_party/python/glean_parser/glean_parser/pings.py index b4145ea68d..b3f2476c9a 100644 --- a/third_party/python/glean_parser/glean_parser/pings.py +++ b/third_party/python/glean_parser/glean_parser/pings.py @@ -31,6 +31,7 @@ class Ping: reasons: Optional[Dict[str, str]] = None, defined_in: Optional[Dict] = None, no_lint: Optional[List[str]] = None, + enabled: Optional[bool] = None, _validated: bool = False, ): # Avoid cyclical import @@ -46,6 +47,10 @@ class Ping: self.metadata = metadata self.precise_timestamps = self.metadata.get("precise_timestamps", True) self.include_info_sections = self.metadata.get("include_info_sections", True) + if enabled is None: + enabled = True + self.enabled = enabled + self.schedules_pings: List[str] = [] if data_reviews is None: data_reviews = [] self.data_reviews = data_reviews @@ -94,6 +99,7 @@ class Ping: modified_dict = util.remove_output_params( modified_dict, "include_info_sections" ) + modified_dict = util.remove_output_params(modified_dict, "schedules_pings") return modified_dict def identifier(self) -> str: diff --git a/third_party/python/glean_parser/glean_parser/schemas/pings.2-0-0.schema.yaml b/third_party/python/glean_parser/glean_parser/schemas/pings.2-0-0.schema.yaml index 6679a8066b..345812c805 100644 --- a/third_party/python/glean_parser/glean_parser/schemas/pings.2-0-0.schema.yaml +++ b/third_party/python/glean_parser/glean_parser/schemas/pings.2-0-0.schema.yaml @@ -96,6 +96,16 @@ additionalProperties: Interaction with `include_client_id`: `include_client_id` only takes effect when `metadata.include_info_sections` is `true`. type: boolean + ping_schedule: + title: Ping Schedule + description: | + An optional array of ping names. When one of the listed pings is + sent, then this ping will also be sent. A ping cannot list its own + name in `ping_schedule`. + type: array + items: + type: string + maxLength: 30 default: {} @@ -175,6 +185,18 @@ additionalProperties: additionalProperties: type: string + enabled: + title: Whether or not this ping is enabled + description: | + **Optional.** + + When `true`, the ping will be sent as usual. + When `false`, the ping will not be sent, but the data will continue to + be collected but will not be cleared when the ping is submitted. + + Defaults to `true` if omitted. + type: boolean + no_lint: title: Lint checks to skip description: | diff --git a/third_party/python/glean_parser/glean_parser/swift.py b/third_party/python/glean_parser/glean_parser/swift.py index c745c4d9ac..b121933b0f 100644 --- a/third_party/python/glean_parser/glean_parser/swift.py +++ b/third_party/python/glean_parser/glean_parser/swift.py @@ -106,12 +106,17 @@ def type_name(obj: Union[metrics.Metric, pings.Ping]) -> str: return "{}<{}>".format(class_name(obj.type), generic) + generate_structure = getattr(obj, "_generate_structure", []) + if len(generate_structure): + generic = util.Camelize(obj.name) + "Object" + return "{}<{}>".format(class_name(obj.type), generic) + return class_name(obj.type) def extra_type_name(typ: str) -> str: """ - Returns the corresponding Kotlin type for event's extra key types. + Returns the corresponding Swift type for event's extra key types. """ if typ == "boolean": @@ -124,6 +129,21 @@ def extra_type_name(typ: str) -> str: return "UNSUPPORTED" +def structure_type_name(typ: str) -> str: + """ + Returns the corresponding Swift type for structure items. + """ + + if typ == "boolean": + return "Bool" + elif typ == "string": + return "String" + elif typ == "number": + return "Int64" + else: + return "UNSUPPORTED" + + def class_name(obj_type: str) -> str: """ Returns the Swift class name for a given metric or ping type. @@ -215,6 +235,7 @@ def output_swift( ("class_name", class_name), ("variable_name", variable_name), ("extra_type_name", extra_type_name), + ("structure_type_name", structure_type_name), ), ) diff --git a/third_party/python/glean_parser/glean_parser/templates/javascript_server.jinja2 b/third_party/python/glean_parser/glean_parser/templates/javascript_server.jinja2 index 0a89f081f6..9df299fd2b 100644 --- a/third_party/python/glean_parser/glean_parser/templates/javascript_server.jinja2 +++ b/third_party/python/glean_parser/glean_parser/templates/javascript_server.jinja2 @@ -21,7 +21,7 @@ type LoggerOptions = { app: string; fmt?: 'heka' }; type Event = { category: string; name: string; - extra: Record<string, any>; + extra?: Record<string, any>; timestamp?: number; }; {% endif %} @@ -30,14 +30,14 @@ type Event = { let _logger{% if lang == "typescript" %}: Logger{% endif %}; {% for ping, metrics_by_type in pings.items() %} -class {{ ping|event_class_name(event_metric_exists) }} { +class {{ ping|event_class_name(metrics_by_type) }} { {% if lang == "typescript" %} _applicationId: string; _appDisplayVersion: string; _channel: string; {% endif %} /** - * Create {{ ping|event_class_name(event_metric_exists) }} instance. + * Create {{ ping|event_class_name(metrics_by_type) }} instance. * * @param {string} applicationId - The application ID. * @param {string} appDisplayVersion - The application display version. @@ -72,7 +72,7 @@ class {{ ping|event_class_name(event_metric_exists) }} { {% endif %} } } - {% if event_metric_exists %} + {% if 'event' in metrics_by_type %} #record({ {% else %} /** @@ -99,28 +99,28 @@ class {{ ping|event_class_name(event_metric_exists) }} { {% endfor %} {% endif %} {% endfor %} - {% if event_metric_exists %} + {% if 'event' in metrics_by_type %} event, {% endif %} {% if lang == "typescript" %} }: { - user_agent: string, - ip_address: string, + user_agent: string; + ip_address: string; {% for metric_type, metrics in metrics_by_type.items() %} {% if metric_type != 'event' %} {% for metric in metrics %} - {{ metric|metric_argument_name }}: {{ metric|js_metric_type }}, + {{ metric|metric_argument_name }}: {{ metric|js_metric_type }}; {% endfor %} {% endif %} {% endfor %} - {% if event_metric_exists %} - event: Event + {% if 'event' in metrics_by_type %} + event: Event; {% endif %} {% endif %} }) { const now = new Date(); const timestamp = now.toISOString(); - {% if event_metric_exists %} + {% if 'event' in metrics_by_type %} event.timestamp = now.getTime(); {% endif %} const eventPayload = { @@ -135,7 +135,7 @@ class {{ ping|event_class_name(event_metric_exists) }} { {% endif %} {% endfor %} }, - {% if event_metric_exists %} + {% if 'event' in metrics_by_type %} events: [event], {% endif %} ping_info: { @@ -171,7 +171,7 @@ class {{ ping|event_class_name(event_metric_exists) }} { // this is similar to how FxA currently logs with mozlog: https://github.com/mozilla/fxa/blob/4c5c702a7fcbf6f8c6b1f175e9172cdd21471eac/packages/fxa-auth-server/lib/log.js#L289 _logger.info(GLEAN_EVENT_MOZLOG_TYPE, ping); } - {% if event_metric_exists %} + {% if 'event' in metrics_by_type %} {% for event in metrics_by_type["event"] %} /** * Record and submit a {{ event.category }}_{{ event.name }} event: @@ -209,27 +209,27 @@ class {{ ping|event_class_name(event_metric_exists) }} { {% endfor %} {% if lang == "typescript" %} }: { - user_agent: string, - ip_address: string, + user_agent: string; + ip_address: string; {% for metric_type, metrics in metrics_by_type.items() %} {% if metric_type != 'event' %} {% for metric in metrics %} - {{ metric|metric_argument_name }}: {{ metric|js_metric_type }}, + {{ metric|metric_argument_name }}: {{ metric|js_metric_type }}; {% endfor %} {% endif %} {% endfor %} {% for extra, metadata in event.extra_keys.items() %} - {{ extra }}: {{metadata.type}}, + {{ extra }}: {{metadata.type}}; {% endfor %} {% endif %} }) { - let event = { - 'category': '{{ event.category }}', - 'name': '{{ event.name }}', + const event = { + category: '{{ event.category }}', + name: '{{ event.name }}', {% if event.extra_keys %} - 'extra': { + extra: { {% for extra, metadata in event.extra_keys.items() %} - '{{ extra }}': {{ extra }}, + {{ extra }}: {{ extra }}, {% endfor %} }, {% endif %} @@ -244,14 +244,14 @@ class {{ ping|event_class_name(event_metric_exists) }} { {% endfor %} {% endif %} {% endfor %} - event + event, }); } {% endfor %} {% endif %} } {% endfor %} -{% for ping in pings %} +{% for ping, metrics_by_type in pings.items() %} /** * Factory function that creates an instance of Glean Server Event Logger to @@ -262,11 +262,11 @@ class {{ ping|event_class_name(event_metric_exists) }} { * @param {Object} logger_options - The logger options. * @returns {EventsServerEventLogger} An instance of EventsServerEventLogger. */ -export const {{ ping|factory_method(event_metric_exists) }} = function ({ +export const {{ ping|factory_method(metrics_by_type) }} = function ({ applicationId, appDisplayVersion, channel, - logger_options + logger_options, {% if lang == "typescript" %} }: { applicationId: string; @@ -275,7 +275,7 @@ export const {{ ping|factory_method(event_metric_exists) }} = function ({ logger_options: LoggerOptions; {% endif %} }) { - return new {{ ping|event_class_name(event_metric_exists) }}( + return new {{ ping|event_class_name(metrics_by_type) }}( applicationId, appDisplayVersion, channel, diff --git a/third_party/python/glean_parser/glean_parser/templates/kotlin.jinja2 b/third_party/python/glean_parser/glean_parser/templates/kotlin.jinja2 index bd800af01d..71ba386a4c 100644 --- a/third_party/python/glean_parser/glean_parser/templates/kotlin.jinja2 +++ b/third_party/python/glean_parser/glean_parser/templates/kotlin.jinja2 @@ -66,6 +66,61 @@ data class {{ obj.name|Camelize }}{{ suffix }}( } {%- endmacro -%} +{%- macro generate_structure(name, struct) %} +{%- if struct.type == "array" -%} + @Serializable + data class {{ name }}(var items: MutableList<{{ name }}Item> = mutableListOf()) : ObjectSerialize { + fun add(elem: {{ name }}Item) = items.add(elem) + + fun addAll(elements: Collection<{{ name }}Item>) = items.addAll(elements) + + fun clear() = items.clear() + + fun remove(element: {{ name }}Item) = items.remove(element) + fun removeAll(elements: Collection<{{ name }}Item>) = items.removeAll(elements) + fun removeAt(index: Int) = items.removeAt(index) + + fun set(index: Int, element: {{ name }}Item) = items.set(index, element) + + override fun intoSerializedObject(): String { + return Json.encodeToString(items) + } + } + + {{ generate_structure(name ~ "Item", struct["items"]) }} + +{%- elif struct.type == "object" -%} + @Serializable + data class {{ name }}( + {% for itemname, val in struct.properties.items() %} + {% if val.type == "object" %} + var {{itemname|camelize}}: {{ name ~ "Item" ~ itemname|Camelize ~ "Object" }}? = null, + {% elif val.type == "array" %} + var {{itemname|camelize}}: {{ name ~ "Item" ~ itemname|Camelize }} = {{ name ~ "Item" ~ itemname|Camelize }}(), + {% else %} + var {{itemname|camelize}}: {{val.type|structure_type_name}}? = null, + {% endif %} + {% endfor %} + ): ObjectSerialize { + override fun intoSerializedObject(): String { + return Json.encodeToString(this) + } + } + + {% for itemname, val in struct.properties.items() %} + {% if val.type == "array" %} + {% set nested_name = name ~ "Item" ~ itemname|Camelize %} + {{ generate_structure(nested_name, val) }} + {% elif val.type == "object" %} + {% set nested_name = name ~ "Item" ~ itemname|Camelize ~ "Object" %} + {{ generate_structure(nested_name, val) }} + {% endif %} + {% endfor %} + +{% endif %} + +{% endmacro %} + /* ktlint-disable no-blank-line-before-rbrace */ @file:Suppress("PackageNaming", "MaxLineLength") package {{ namespace }} @@ -76,8 +131,9 @@ import {{ glean_namespace }}.private.HistogramType // ktlint-disable import-orde import {{ glean_namespace }}.private.Lifetime // ktlint-disable import-ordering no-unused-imports import {{ glean_namespace }}.private.MemoryUnit // ktlint-disable import-ordering no-unused-imports import {{ glean_namespace }}.private.NoExtras // ktlint-disable import-ordering no-unused-imports -import {{ glean_namespace }}.private.ReasonCode // ktlint-disable import-ordering no-unused-imports import {{ glean_namespace }}.private.NoReasonCodes // ktlint-disable import-ordering no-unused-imports +import {{ glean_namespace }}.private.ObjectSerialize // ktlint-disable import-ordering no-unused-imports +import {{ glean_namespace }}.private.ReasonCode // ktlint-disable import-ordering no-unused-imports import {{ glean_namespace }}.private.TimeUnit // ktlint-disable import-ordering no-unused-imports {% for obj_type in obj_types %} import {{ glean_namespace }}.private.{{ obj_type }} // ktlint-disable import-ordering @@ -85,6 +141,11 @@ import {{ glean_namespace }}.private.{{ obj_type }} // ktlint-disable import-ord {% if has_labeled_metrics %} import {{ glean_namespace }}.private.LabeledMetricType // ktlint-disable import-ordering {% endif %} +{% if has_object_metrics %} +import kotlinx.serialization.Serializable +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +{% endif %} internal object {{ category_name|Camelize }} { {% for obj in objs.values() %} @@ -97,6 +158,9 @@ internal object {{ category_name|Camelize }} { {% endfor %} {% endif %} {% else %} + {% if obj|attr("_generate_structure") %} + {{ generate_structure(obj.name|Camelize ~ "Object", obj._generate_structure) }} + {%- endif %} {% if obj|attr("_generate_enums") %} {% for name, suffix in obj["_generate_enums"] %} {% if obj|attr(name)|length %} diff --git a/third_party/python/glean_parser/glean_parser/templates/rust.jinja2 b/third_party/python/glean_parser/glean_parser/templates/rust.jinja2 index 4c54dd2b2c..269a007ac5 100644 --- a/third_party/python/glean_parser/glean_parser/templates/rust.jinja2 +++ b/third_party/python/glean_parser/glean_parser/templates/rust.jinja2 @@ -87,7 +87,7 @@ impl ExtraKeys for {{ obj.name|Camelize }}{{ suffix }} { /// {{ obj.description|wordwrap() | replace('\n', '\n/// ') }} #[rustfmt::skip] pub static {{ obj.name|snake_case }}: ::glean::private::__export::Lazy<::glean::private::PingType> = - ::glean::private::__export::Lazy::new(|| ::glean::private::PingType::new("{{ obj.name }}", {{ obj.include_client_id|rust }}, {{ obj.send_if_empty|rust }}, {{ obj.precise_timestamps|rust }}, {{ obj.include_info_sections|rust }}, {{ obj.reason_codes|rust }})); + ::glean::private::__export::Lazy::new(|| ::glean::private::PingType::new("{{ obj.name }}", {{ obj.include_client_id|rust }}, {{ obj.send_if_empty|rust }}, {{ obj.precise_timestamps|rust }}, {{ obj.include_info_sections|rust }}, {{ obj.enabled|rust }}, {{ obj.schedules_pings|rust }}, {{ obj.reason_codes|rust }})); {% endfor %} {% else %} pub mod {{ category.name|snake_case }} { diff --git a/third_party/python/glean_parser/glean_parser/templates/swift.jinja2 b/third_party/python/glean_parser/glean_parser/templates/swift.jinja2 index 714bf20ec2..fe51a078bc 100644 --- a/third_party/python/glean_parser/glean_parser/templates/swift.jinja2 +++ b/third_party/python/glean_parser/glean_parser/templates/swift.jinja2 @@ -11,7 +11,7 @@ Jinja2 template is not. Please file bugs! #} /* 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/. */ -{% macro obj_declaration(obj, suffix='', access='') %} +{%- macro obj_declaration(obj, suffix='', access='') %} {{ access }}static let {{ obj.name|camelize|variable_name }}{{ suffix }} = {{ obj|type_name }}( // generated from {{ obj.identifier() }} CommonMetricData( {% for arg_name in common_metric_args if obj[arg_name] is defined %} @@ -24,7 +24,7 @@ Jinja2 template is not. Please file bugs! #} ) {% endmacro %} -{% macro struct_decl(obj, name, suffix) %} +{%- macro struct_decl(obj, name, suffix) %} struct {{ obj.name|Camelize }}{{ suffix }}: EventExtras { {% for item, typ in obj|attr(name) %} var {{ item|camelize|variable_name }}: {{typ|extra_type_name}}? @@ -44,6 +44,46 @@ struct {{ obj.name|Camelize }}{{ suffix }}: EventExtras { } {% endmacro %} +{%- macro generate_structure(name, struct) %} +{%- if struct.type == "array" -%} + typealias {{ name }} = [{{ name }}Item] + + {{ generate_structure(name ~ "Item", struct["items"]) }} + +{%- elif struct.type == "object" -%} + struct {{ name }}: Codable, Equatable, ObjectSerialize { + {% for itemname, val in struct.properties.items() %} + {% if val.type == "object" %} + var {{itemname|camelize|variable_name}}: {{ name ~ "Item" ~ itemname|Camelize ~ "Object" }}? + {% elif val.type == "array" %} + var {{itemname|camelize|variable_name}}: {{ name ~ "Item" ~ itemname|Camelize }} + {% else %} + var {{itemname|camelize|variable_name}}: {{val.type|structure_type_name}}? + {% endif %} + {% endfor %} + + func intoSerializedObject() -> String { + let jsonEncoder = JSONEncoder() + let jsonData = try! jsonEncoder.encode(self) + let json = String(data: jsonData, encoding: String.Encoding.utf8)! + return json + } + } + + {% for itemname, val in struct.properties.items() %} + {% if val.type == "array" %} + {% set nested_name = name ~ "Item" ~ itemname|Camelize %} + {{ generate_structure(nested_name, val) }} + {% elif val.type == "object" %} + {% set nested_name = name ~ "Item" ~ itemname|Camelize ~ "Object" %} + {{ generate_structure(nested_name, val) }} + {% endif %} + {% endfor %} + +{%- endif -%} + +{% endmacro %} + {% if not allow_reserved %} import {{ glean_namespace }} @@ -97,6 +137,8 @@ extension {{ namespace }} { sendIfEmpty: {{obj.send_if_empty|swift}}, preciseTimestamps: {{obj.precise_timestamps|swift}}, includeInfoSections: {{obj.include_info_sections|swift}}, + enabled: {{obj.enabled|swift}}, + schedulesPings: {{obj.schedules_pings|swift}}, reasonCodes: {{obj.reason_codes|swift}} ) @@ -106,6 +148,9 @@ extension {{ namespace }} { {% else %} enum {{ category.name|Camelize }} { {% for obj in category.objs.values() %} + {% if obj|attr("_generate_structure") %} + {{ generate_structure(obj.name|Camelize ~ "Object", obj._generate_structure) }} + {%- endif %} {% if obj|attr("_generate_enums") %} {% for name, suffix in obj["_generate_enums"] %} {% if obj|attr(name)|length %} diff --git a/third_party/python/glean_parser/glean_parser/util.py b/third_party/python/glean_parser/glean_parser/util.py index f8bc7d4f53..a61e318dbe 100644 --- a/third_party/python/glean_parser/glean_parser/util.py +++ b/third_party/python/glean_parser/glean_parser/util.py @@ -531,6 +531,8 @@ ping_args = [ "send_if_empty", "precise_timestamps", "include_info_sections", + "enabled", + "schedules_pings", "reason_codes", ] |