glean-parser 18.2.0__tar.gz → 19.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. {glean_parser-18.2.0 → glean_parser-19.1.0}/PKG-INFO +2 -2
  2. {glean_parser-18.2.0 → glean_parser-19.1.0}/README.md +1 -1
  3. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/__main__.py +3 -54
  4. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/go_server.py +50 -2
  5. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/lint.py +12 -4
  6. glean_parser-19.1.0/glean_parser/rust_sym.py +78 -0
  7. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/schemas/metrics.2-0-0.schema.yaml +3 -2
  8. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/schemas/pings.2-0-0.schema.yaml +2 -2
  9. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/go_server.jinja2 +26 -2
  10. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/javascript_server.jinja2 +1 -1
  11. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/python_server.jinja2 +24 -15
  12. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/ruby_server.jinja2 +1 -1
  13. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/rust_server.jinja2 +3 -3
  14. glean_parser-19.1.0/glean_parser/templates/rust_sym.jinja2 +196 -0
  15. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/translate.py +2 -0
  16. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/conftest.py +3 -1
  17. glean_parser-19.1.0/tests/data/go_server_labeled_boolean_metrics.yaml +26 -0
  18. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_custom_ping_only_compare.go +6 -2
  19. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_custom_ping_only_compare.rs +3 -3
  20. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_events_and_custom_ping_compare.go +10 -2
  21. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_events_and_custom_ping_compare.rs +3 -3
  22. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_events_compare.rb +1 -1
  23. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_events_only_compare.go +6 -2
  24. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_events_only_compare.rs +3 -3
  25. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test-js/package.json +1 -1
  26. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test-py/test.py +4 -0
  27. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_go_server.py +223 -2
  28. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_kotlin.py +3 -3
  29. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_lint.py +14 -11
  30. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_parser.py +17 -5
  31. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_python_server.py +24 -23
  32. glean_parser-19.1.0/tests/test_rust_sym.py +61 -0
  33. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_swift.py +2 -7
  34. glean_parser-18.2.0/glean_parser/coverage.py +0 -140
  35. {glean_parser-18.2.0 → glean_parser-19.1.0}/.gitignore +0 -0
  36. {glean_parser-18.2.0 → glean_parser-19.1.0}/AUTHORS.md +0 -0
  37. {glean_parser-18.2.0 → glean_parser-19.1.0}/LICENSE +0 -0
  38. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/__init__.py +0 -0
  39. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/data_review.py +0 -0
  40. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/javascript.py +0 -0
  41. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/javascript_server.py +0 -0
  42. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/kotlin.py +0 -0
  43. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/markdown.py +0 -0
  44. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/metrics.py +0 -0
  45. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/parser.py +0 -0
  46. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/pings.py +0 -0
  47. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/python_server.py +0 -0
  48. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/ruby_server.py +0 -0
  49. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/rust.py +0 -0
  50. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/rust_server.py +0 -0
  51. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/schemas/metrics.1-0-0.schema.yaml +0 -0
  52. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/schemas/pings.1-0-0.schema.yaml +0 -0
  53. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/schemas/tags.1-0-0.schema.yaml +0 -0
  54. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/swift.py +0 -0
  55. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/tags.py +0 -0
  56. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/data_review.jinja2 +0 -0
  57. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/javascript.buildinfo.jinja2 +0 -0
  58. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/javascript.jinja2 +0 -0
  59. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/kotlin.buildinfo.jinja2 +0 -0
  60. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/kotlin.jinja2 +0 -0
  61. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/markdown.jinja2 +0 -0
  62. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/qmldir.jinja2 +0 -0
  63. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/rust.jinja2 +0 -0
  64. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/templates/swift.jinja2 +0 -0
  65. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/translation_options.py +0 -0
  66. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/util.py +0 -0
  67. {glean_parser-18.2.0 → glean_parser-19.1.0}/glean_parser/validate_ping.py +0 -0
  68. {glean_parser-18.2.0 → glean_parser-19.1.0}/pyproject.toml +0 -0
  69. {glean_parser-18.2.0 → glean_parser-19.1.0}/server_telemetry/sdk-metrics-compat.yaml +0 -0
  70. {glean_parser-18.2.0 → glean_parser-19.1.0}/server_telemetry/server-side-pings.yaml +0 -0
  71. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/all_metrics.yaml +0 -0
  72. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/all_pings.yaml +0 -0
  73. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/attribution.yaml +0 -0
  74. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/bad_attribution.yamlx +0 -0
  75. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/bad_ping.yamlx +0 -0
  76. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/core.yaml +0 -0
  77. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/custom_ping_no_event_metrics.yaml +0 -0
  78. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/custom_ping_no_event_pings.yaml +0 -0
  79. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/dual_labeled.yaml +0 -0
  80. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/dual_labeled_invalid.yaml +0 -0
  81. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/duplicate_labeled.yaml +0 -0
  82. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/duplicate_send_in_ping.yaml +0 -0
  83. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/empty.yaml +0 -0
  84. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/event_key_ordering.yaml +0 -0
  85. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/events_data_sensitivity.yaml +0 -0
  86. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/events_with_types.yaml +0 -0
  87. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/fxa-server-metrics.yaml +0 -0
  88. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/fxa-server-pings.yaml +0 -0
  89. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/go_server_custom_ping_only_metrics.yaml +0 -0
  90. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/go_server_custom_ping_only_pings.yaml +0 -0
  91. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/go_server_events_and_custom_ping_metrics.yaml +0 -0
  92. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/go_server_events_and_custom_ping_pings.yaml +0 -0
  93. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/go_server_events_only_metrics.yaml +0 -0
  94. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/go_server_metrics_unsupported.yaml +0 -0
  95. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/invalid-ping-names.yaml +0 -0
  96. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/invalid.yamlx +0 -0
  97. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/jwe.yaml +0 -0
  98. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/metric-with-tags.yaml +0 -0
  99. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/mixed-expirations.yaml +0 -0
  100. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/name_too_similar.yaml +0 -0
  101. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/object.yaml +0 -0
  102. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/old_event_api.yamlx +0 -0
  103. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/ordering.yaml +0 -0
  104. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/pings.yaml +0 -0
  105. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/python_server_metrics_unsupported.yaml +0 -0
  106. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/rate.yaml +0 -0
  107. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/redefined_category.yamlx +0 -0
  108. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/redefined_metric.yamlx +0 -0
  109. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/redefined_ping.yamlx +0 -0
  110. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/reserved_categories.yamlx +0 -0
  111. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/ruby_server_metrics_unsupported.yaml +0 -0
  112. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/ruby_server_pings_unsupported.yaml +0 -0
  113. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/rust_server_custom_ping_only_metrics.yaml +0 -0
  114. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/rust_server_custom_ping_only_pings.yaml +0 -0
  115. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/rust_server_events_and_custom_ping_metrics.yaml +0 -0
  116. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/rust_server_events_and_custom_ping_pings.yaml +0 -0
  117. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/rust_server_events_only_metrics.yaml +0 -0
  118. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/rust_server_metrics_unsupported.yaml +0 -0
  119. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/same_name_different_category.yaml +0 -0
  120. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/schema-violation.yaml +0 -0
  121. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/send_if_empty_with_metrics.yaml +0 -0
  122. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_metrics_no_events_no_pings.yaml +0 -0
  123. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_metrics_with_event.yaml +0 -0
  124. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/server_pings.yaml +0 -0
  125. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/single_labeled.yaml +0 -0
  126. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/smaller.yaml +0 -0
  127. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/tags.yaml +0 -0
  128. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/telemetry_mirror.yaml +0 -0
  129. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/text.yaml +0 -0
  130. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/text_invalid.yaml +0 -0
  131. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/unknown_ping_used.yaml +0 -0
  132. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/wrong_key.yamlx +0 -0
  133. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/data/yaml_nits.yamlx +0 -0
  134. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/detekt.yml +0 -0
  135. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test-go/test.go.tmpl +0 -0
  136. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test-js/test.js.tmpl +0 -0
  137. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test-rb/test.rb.tmpl +0 -0
  138. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test-rs/test.rs.tmpl +0 -0
  139. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_cli.py +0 -0
  140. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_javascript.py +0 -0
  141. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_javascript_server.py +0 -0
  142. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_markdown.py +0 -0
  143. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_metrics.py +0 -0
  144. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_pings.py +0 -0
  145. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_ruby_server.py +0 -0
  146. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_rust.py +0 -0
  147. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_rust_server.py +0 -0
  148. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_tags.py +0 -0
  149. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_translate.py +0 -0
  150. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_utils.py +0 -0
  151. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/test_validate_ping.py +0 -0
  152. {glean_parser-18.2.0 → glean_parser-19.1.0}/tests/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: glean-parser
3
- Version: 18.2.0
3
+ Version: 19.1.0
4
4
  Summary: Parser tools for Mozilla's Glean telemetry
5
5
  Project-URL: Homepage, https://mozilla.github.io/glean
6
6
  Project-URL: Repository, https://github.com/mozilla/glean_parser
@@ -34,7 +34,7 @@ Parser tools for Mozilla's Glean telemetry.
34
34
 
35
35
  Contains various utilities for handling `metrics.yaml` and `pings.yaml` for [the
36
36
  Glean SDKs](https://mozilla.github.io/glean). This includes producing generated
37
- code for various integrations, linting and coverage testing.
37
+ code for various integrations and linting.
38
38
 
39
39
  ## Documentation
40
40
 
@@ -6,7 +6,7 @@ Parser tools for Mozilla's Glean telemetry.
6
6
 
7
7
  Contains various utilities for handling `metrics.yaml` and `pings.yaml` for [the
8
8
  Glean SDKs](https://mozilla.github.io/glean). This includes producing generated
9
- code for various integrations, linting and coverage testing.
9
+ code for various integrations and linting.
10
10
 
11
11
  ## Documentation
12
12
 
@@ -18,7 +18,6 @@ import json
18
18
  import glean_parser
19
19
 
20
20
 
21
- from . import coverage as mod_coverage
22
21
  from . import data_review as mod_data_review
23
22
  from . import lint
24
23
  from . import translate as mod_translate
@@ -172,7 +171,9 @@ def check(schema):
172
171
  type=click.INT,
173
172
  required=False,
174
173
  )
175
- def glinter(input, allow_reserved, allow_missing_files, require_tags, expire_by_version):
174
+ def glinter(
175
+ input, allow_reserved, allow_missing_files, require_tags, expire_by_version
176
+ ):
176
177
  """
177
178
  Runs a linter over the metrics.
178
179
  """
@@ -250,57 +251,6 @@ def dump(input, allow_reserved, allow_missing_files, require_tags):
250
251
  )
251
252
 
252
253
 
253
- @click.command()
254
- @click.option(
255
- "-c",
256
- "--coverage_file",
257
- type=click.Path(exists=True, dir_okay=False, file_okay=True, readable=True),
258
- required=True,
259
- multiple=True,
260
- )
261
- @click.argument(
262
- "metrics_files",
263
- type=click.Path(exists=True, dir_okay=False, file_okay=True, readable=True),
264
- nargs=-1,
265
- )
266
- @click.option(
267
- "-o",
268
- "--output",
269
- type=click.Path(exists=False, dir_okay=False, file_okay=True, writable=True),
270
- required=True,
271
- )
272
- @click.option(
273
- "--format",
274
- "-f",
275
- type=click.Choice(list(mod_coverage.OUTPUTTERS.keys())),
276
- required=True,
277
- )
278
- @click.option(
279
- "--allow-reserved",
280
- is_flag=True,
281
- help=(
282
- "If provided, allow the use of reserved fields. "
283
- "Should only be set when building the Glean library itself."
284
- ),
285
- )
286
- def coverage(coverage_file, metrics_files, format, output, allow_reserved):
287
- """
288
- Produce a coverage analysis file given raw coverage output and a set of
289
- metrics.yaml files.
290
- """
291
- sys.exit(
292
- mod_coverage.coverage(
293
- [Path(x) for x in coverage_file],
294
- [Path(x) for x in metrics_files],
295
- format,
296
- Path(output),
297
- {
298
- "allow_reserved": allow_reserved,
299
- },
300
- )
301
- )
302
-
303
-
304
254
  @click.command()
305
255
  @click.argument("bug", type=str)
306
256
  @click.argument(
@@ -334,7 +284,6 @@ main.add_command(translate)
334
284
  main.add_command(check)
335
285
  main.add_command(glinter)
336
286
  main.add_command(dump)
337
- main.add_command(coverage)
338
287
  main.add_command(data_review_request, "data-review")
339
288
 
340
289
 
@@ -32,7 +32,15 @@ from . import util
32
32
 
33
33
  # Adding a metric here will require updating the `generate_metric_type` function
34
34
  # and require adjustments to `metrics` variables the the template.
35
- SUPPORTED_METRIC_TYPES = ["string", "quantity", "event", "datetime", "boolean", "string_list"]
35
+ SUPPORTED_METRIC_TYPES = [
36
+ "string",
37
+ "quantity",
38
+ "event",
39
+ "datetime",
40
+ "boolean",
41
+ "labeled_boolean", # static labels only; dynamic labels are not supported
42
+ "string_list",
43
+ ]
36
44
 
37
45
 
38
46
  def generate_ping_type_name(ping_name: str) -> str:
@@ -80,6 +88,28 @@ def clean_string(s: str) -> str:
80
88
  return s.replace("\n", " ").rstrip()
81
89
 
82
90
 
91
+ def validate_labeled_boolean(metric: metrics.Metric) -> bool:
92
+ """
93
+ Validate that a labeled_boolean metric has static labels defined.
94
+
95
+ The Go server outputter requires labels to be listed in metrics.yaml
96
+ because it generates a Go struct with a field per label at build time.
97
+ Dynamic labels are not supported.
98
+
99
+ Returns:
100
+ bool: True if valid, False otherwise
101
+ """
102
+ if not getattr(metric, "ordered_labels", None):
103
+ print(
104
+ "❌ Ignoring labeled_boolean metric without static labels: "
105
+ + f"{metric.name}."
106
+ + " Define labels in metrics.yaml to use this metric type."
107
+ )
108
+ return False
109
+
110
+ return True
111
+
112
+
83
113
  def output_go(
84
114
  objs: metrics.ObjectTree, output_dir: Path, options: Optional[Dict[str, Any]]
85
115
  ) -> None:
@@ -111,6 +141,9 @@ def output_go(
111
141
  # unique list of event metrics used in any ping
112
142
  event_metrics: List[metrics.Metric] = []
113
143
 
144
+ # unique list of labeled_boolean metrics used in any ping
145
+ labeled_boolean_metrics: List[metrics.Metric] = []
146
+
114
147
  # Go through all metrics in objs and build a map of
115
148
  # ping->list of metric categories->list of metrics
116
149
  # for easier processing in the template.
@@ -127,10 +160,22 @@ def output_go(
127
160
  )
128
161
  continue
129
162
 
163
+ # Validate labeled_boolean metrics
164
+ if metric.type == "labeled_boolean" and not validate_labeled_boolean(
165
+ metric
166
+ ):
167
+ continue
168
+
130
169
  for ping in metric.send_in_pings:
131
170
  if metric.type == "event" and metric not in event_metrics:
132
171
  event_metrics.append(metric)
133
172
 
173
+ if (
174
+ metric.type == "labeled_boolean"
175
+ and metric not in labeled_boolean_metrics
176
+ ):
177
+ labeled_boolean_metrics.append(metric)
178
+
134
179
  metrics_by_type = ping_to_metrics[ping]
135
180
  metrics_list = metrics_by_type.setdefault(metric.type, [])
136
181
  metrics_list.append(metric)
@@ -149,6 +194,9 @@ def output_go(
149
194
  with filepath.open("w", encoding="utf-8") as fd:
150
195
  fd.write(
151
196
  template.render(
152
- parser_version=__version__, pings=ping_to_metrics, events=event_metrics
197
+ parser_version=__version__,
198
+ pings=ping_to_metrics,
199
+ events=event_metrics,
200
+ labeled_booleans=labeled_boolean_metrics,
153
201
  )
154
202
  )
@@ -35,7 +35,7 @@ NitGenerator = Generator["GlinterNit", None, None]
35
35
 
36
36
 
37
37
  def noop(*args):
38
- """ A noop `LintGenerator`. Never yields a GlinterNit."""
38
+ """A noop `LintGenerator`. Never yields a GlinterNit."""
39
39
  return
40
40
  yield
41
41
 
@@ -307,8 +307,12 @@ def check_event_on_non_events_ping(
307
307
  An event metric should usually go on the `events` ping or a custom ping,
308
308
  not on a builtin ping.
309
309
  """
310
- disallowed_pings = set(pings.RESERVED_PING_NAMES) - {"default", "events"} | {"health"}
311
- if metric.type == "event" and any([ping in disallowed_pings for ping in metric.send_in_pings]):
310
+ disallowed_pings = set(pings.RESERVED_PING_NAMES) - {"default", "events"} | {
311
+ "health"
312
+ }
313
+ if metric.type == "event" and any(
314
+ [ping in disallowed_pings for ping in metric.send_in_pings]
315
+ ):
312
316
  yield (
313
317
  "An event metric should usually go on the `events` ping or a custom ping, "
314
318
  + "not on a builtin ping."
@@ -709,7 +713,11 @@ def lint_metrics(
709
713
 
710
714
  for check_name, (check_func, check_type) in METRIC_CHECKS.items():
711
715
  new_nits = list(check_func(metric, parser_config))
712
- if check_unused_lints and check_name in metric.no_lint and not len(new_nits):
716
+ if (
717
+ check_unused_lints
718
+ and check_name in metric.no_lint
719
+ and not len(new_nits)
720
+ ):
713
721
  nits.append(
714
722
  GlinterNit(
715
723
  "UNUSED_NO_LINT",
@@ -0,0 +1,78 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # This Source Code Form is subject to the terms of the Mozilla Public
4
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
5
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
+
7
+ """
8
+ Outputter to generate Rust code for metrics.
9
+ """
10
+
11
+ from pathlib import Path
12
+ from typing import Any, Dict, Optional
13
+
14
+ from . import __version__
15
+ from . import metrics
16
+ from . import pings
17
+ from . import util
18
+ from .rust import (
19
+ rust_datatypes_filter,
20
+ ctor,
21
+ type_name,
22
+ extra_type_name,
23
+ structure_type_name,
24
+ extra_keys,
25
+ Category,
26
+ )
27
+
28
+
29
+ def output_rust(
30
+ objs: metrics.ObjectTree, output_dir: Path, options: Optional[Dict[str, Any]] = None
31
+ ) -> None:
32
+ """
33
+ Given a tree of objects, output Rust code to `output_dir`.
34
+
35
+ :param objs: A tree of objects (metrics and pings) as returned from
36
+ `parser.parse_objects`.
37
+ :param output_dir: Path to an output directory to write to.
38
+ :param options: options dictionary, not currently used for Rust
39
+ """
40
+
41
+ if options is None:
42
+ options = {}
43
+
44
+ template = util.get_jinja2_template(
45
+ "rust_sym.jinja2",
46
+ filters=(
47
+ ("rust", rust_datatypes_filter),
48
+ ("snake_case", util.snake_case),
49
+ ("camelize", util.camelize),
50
+ ("type_name", type_name),
51
+ ("extra_type_name", extra_type_name),
52
+ ("structure_type_name", structure_type_name),
53
+ ("ctor", ctor),
54
+ ("extra_keys", extra_keys),
55
+ ),
56
+ )
57
+
58
+ filename = "glean_metrics.rs"
59
+ filepath = output_dir / filename
60
+ categories = []
61
+
62
+ for category_key, category_val in objs.items():
63
+ contains_pings = any(
64
+ isinstance(obj, pings.Ping) for obj in category_val.values()
65
+ )
66
+
67
+ cat = Category(category_key, category_val, contains_pings)
68
+ categories.append(cat)
69
+
70
+ with filepath.open("w", encoding="utf-8") as fd:
71
+ fd.write(
72
+ template.render(
73
+ parser_version=__version__,
74
+ categories=categories,
75
+ extra_metric_args=util.extra_metric_args,
76
+ common_metric_args=util.common_metric_args,
77
+ )
78
+ )
@@ -254,7 +254,7 @@ definitions:
254
254
 
255
255
  A list of bug URLs (e.g. Bugzilla and Github) that are relevant to
256
256
  this metric, e.g., tracking its original implementation or later
257
- changes to it.
257
+ changes to it, including renewals.
258
258
 
259
259
  Prior to version 2.0.0 of the schema, bugs could also be integers.
260
260
  type: array
@@ -268,7 +268,8 @@ definitions:
268
268
  description: |
269
269
  **Required.**
270
270
 
271
- A list of URIs to any data collection reviews relevant to the metric.
271
+ A list of URLs to any data collection reviews relevant to the metric.
272
+ This should also include links to data reviews for renewals.
272
273
  type: array
273
274
  items:
274
275
  type: string
@@ -168,7 +168,7 @@ additionalProperties:
168
168
  ping, e.g., tracking its original implementation or later changes to
169
169
  it.
170
170
 
171
- It must be a URI to a bug page in a tracker.
171
+ It must be a URL to a bug page in a tracker.
172
172
 
173
173
  Prior to version 2.0.0 of the schema, bugs could also be integers.
174
174
  type: array
@@ -182,7 +182,7 @@ additionalProperties:
182
182
  description: |
183
183
  **Required.**
184
184
 
185
- A list of URIs to any data collection reviews relevant to the ping.
185
+ A list of URLs to any data collection reviews relevant to the ping.
186
186
  type: array
187
187
  items:
188
188
  type: string
@@ -73,7 +73,7 @@ type ping struct {
73
73
  Payload string `json:"payload"`
74
74
  }
75
75
 
76
- type metrics map[string]map[string]interface{}
76
+ type metrics map[string]map[string]any
77
77
 
78
78
  type pingPayload struct {
79
79
  ClientInfo clientInfo `json:"client_info"`
@@ -187,7 +187,7 @@ func newGleanEvent(category, name string, extra map[string]string) gleanEvent {
187
187
  return gleanEvent{
188
188
  Category: category,
189
189
  Name: name,
190
- Timestamp: time.Now().UnixMilli(),
190
+ Timestamp: 0,
191
191
  Extra: extra,
192
192
  }
193
193
  }
@@ -220,6 +220,18 @@ func (e {{ event|event_type_name }}) gleanEvent() gleanEvent {
220
220
  }
221
221
  {% endfor %}
222
222
  {% endif %}
223
+ {# Generate struct types for labeled_boolean metrics #}
224
+ {% if labeled_booleans %}
225
+ {% for metric in labeled_booleans %}
226
+
227
+ // {{ metric.description|clean_string }}
228
+ type {{ metric|metric_argument_name }} struct {
229
+ {% for label in metric.ordered_labels %}
230
+ {{ label|event_extra_name }} *bool `json:"{{ label }},omitempty"`
231
+ {% endfor %}
232
+ }
233
+ {% endfor %}
234
+ {% endif %}
223
235
  {# struct & methods for submitting pings #}
224
236
  {% for ping, metrics_by_type in pings.items() %}
225
237
  {% if metrics_by_type['event'] %}
@@ -240,7 +252,11 @@ type {{ ping|ping_type_name }} struct {
240
252
  {% for metric_type, metrics in metrics_by_type.items() %}
241
253
  {% if metric_type != 'event' %}
242
254
  {% for metric in metrics %}
255
+ {% if metric_type == 'labeled_boolean' %}
256
+ {{ metric|metric_argument_name }} {{ metric|metric_argument_name }} // {{ metric.description|clean_string }}
257
+ {% else %}
243
258
  {{ metric|metric_argument_name }} {{ metric_type|go_metric_type}} // {{ metric.description|clean_string }}
259
+ {% endif %}
244
260
  {% endfor %}
245
261
  {% endif %}
246
262
  {% endfor %}
@@ -254,6 +270,14 @@ func (g GleanEventsLogger) Record{{ ping|ping_type_name }}(
254
270
  requestInfo RequestInfo,
255
271
  params {{ ping|ping_type_name }},
256
272
  ) error {
273
+ {% if metrics_by_type['string_list'] %}
274
+ {% for metric in metrics_by_type['string_list'] %}
275
+ // Ensure nil string_list metrics serialize as empty arrays, not null
276
+ if params.{{ metric|metric_argument_name }} == nil {
277
+ params.{{ metric|metric_argument_name }} = []string{}
278
+ }
279
+ {% endfor %}
280
+ {% endif %}
257
281
  metrics := metrics{
258
282
  {% for metric_type, metrics in metrics_by_type.items() %}
259
283
  {% if metric_type != 'event' %}
@@ -126,7 +126,7 @@ class {{ ping|event_class_name(metrics_by_type) }} {
126
126
  const now = new Date();
127
127
  const timestamp = now.toISOString();
128
128
  {% if 'event' in metrics_by_type %}
129
- event.timestamp = now.getTime();
129
+ event.timestamp = 0;
130
130
  {% endif %}
131
131
  const eventPayload = {
132
132
  metrics: {
@@ -35,29 +35,34 @@ class {{ ping|camelize }}ServerEventLogger:
35
35
 
36
36
  def record(
37
37
  self,
38
- user_agent: str,
39
- ip_address: str,
38
+ user_agent: str | None = None,
39
+ ip_address: str | None = None,
40
40
  {% for metric_type, metrics in metrics_by_type.items() %}
41
41
  {% if metric_type != 'event' %}
42
42
  {% for metric in metrics %}
43
- {{ metric.category }}_{{ metric.name }}: {{ metric.type|py_metric_type }},
43
+ {{ metric.category }}_{{ metric.name }}: {{ metric.type|py_metric_type }} | None = None,
44
44
  {% endfor %}
45
45
  {% endif %}
46
46
  {% endfor %}
47
- events: list[dict[str, Any]]
47
+ events: list[dict[str, Any]] | None = None,
48
48
  ) -> None:
49
49
  now = datetime.now(timezone.utc)
50
50
  timestamp = now.isoformat()
51
+ events = [] if events is None else events
51
52
  for event in events:
52
- event["timestamp"] = int(1000.0 * now.timestamp()) # Milliseconds since epoch
53
+ event["timestamp"] = 0
53
54
  event_payload = {
54
55
  "metrics": {
55
56
  {% for metric_type, metrics in metrics_by_type.items() %}
56
57
  {% if metric_type != 'event' %}
57
58
  "{{ metric_type }}": {
58
- {% for metric in metrics %}
59
- "{{ metric.category }}.{{ metric.name }}": {{ metric.category }}_{{ metric.name }},
60
- {% endfor %}
59
+ key: value
60
+ for key, value in [
61
+ {% for metric in metrics %}
62
+ ("{{ metric.category }}.{{ metric.name }}", {{ metric.category }}_{{ metric.name }}),
63
+ {% endfor %}
64
+ ]
65
+ if value is not None
61
66
  },
62
67
  {% endif %}
63
68
  {% endfor %}
@@ -117,17 +122,17 @@ class {{ ping|camelize }}ServerEventLogger:
117
122
  {% for event in metrics_by_type["event"] %}
118
123
  def {{ event|record_event_function_name }}(
119
124
  self,
120
- user_agent: str,
121
- ip_address: str,
125
+ user_agent: str | None = None,
126
+ ip_address: str | None = None,
122
127
  {% for metric_type, metrics in metrics_by_type.items() %}
123
128
  {% if metric_type != 'event' %}
124
129
  {% for metric in metrics %}
125
- {{ metric.category }}_{{ metric.name }}: {{ metric.type|py_metric_type }},
130
+ {{ metric.category }}_{{ metric.name }}: {{ metric.type|py_metric_type }} | None = None,
126
131
  {% endfor %}
127
132
  {% endif %}
128
133
  {% endfor %}
129
134
  {% for extra, metadata in event.extra_keys.items() %}
130
- {{ extra }}: {{ metadata.type|py_metric_type }},
135
+ {{ extra }}: {{ metadata.type|py_metric_type }} | None = None,
131
136
  {% endfor %}
132
137
  ) -> None:
133
138
  """
@@ -156,9 +161,13 @@ class {{ ping|camelize }}ServerEventLogger:
156
161
  "name": "{{ event.name }}",
157
162
  {% if event.extra_keys %}
158
163
  "extra": {
159
- {% for extra, metadata in event.extra_keys.items() %}
160
- "{{ extra }}": str({{ extra }}){% if 'bool' == metadata.type|py_metric_type %}.lower(){% endif %},
161
- {% endfor %}
164
+ key: value
165
+ for key, value in [
166
+ {% for extra, metadata in event.extra_keys.items() %}
167
+ ("{{ extra }}", str({{ extra }}){% if 'bool' == metadata.type|py_metric_type %}.lower(){% endif %}),
168
+ {% endfor %}
169
+ ]
170
+ if value is not None
162
171
  },
163
172
  {% endif %}
164
173
  }
@@ -152,7 +152,7 @@ module Glean
152
152
  {
153
153
  'category' => '{{ event.category }}',
154
154
  'name' => '{{ event.name }}',
155
- 'timestamp' => (Time.now.utc.to_f * 1000).to_i,
155
+ 'timestamp' => 0,
156
156
  'extra' => [
157
157
  {% for extra, metadata in event.extra_keys.items() %}
158
158
  ['{{ extra }}', {{ extra }}.to_s],
@@ -108,7 +108,7 @@ pub fn new_glean_event(
108
108
  GleanEvent {
109
109
  category: category.to_owned(),
110
110
  name: name.to_owned(),
111
- timestamp: Utc::now().timestamp_millis(),
111
+ timestamp: 0,
112
112
  extra,
113
113
  }
114
114
  }
@@ -227,7 +227,7 @@ impl {{ ping|ping_events_type_name }} for {{ event|event_type_name }} {
227
227
  /// Create a GleanEvent for the above-defined Event struct ({{ event|event_type_name }}).
228
228
  /// Any metadata `extra` values are passed into the extra HashMap.
229
229
  fn glean_event(&self) -> GleanEvent {
230
- // Any `extra_keys` will be output below to be inserted into `extra`.
230
+ // Any `extra_keys` will be output below to be inserted into `extra`.
231
231
  // If there are none, an empty, immutable HashMap is created.
232
232
  {% if event.extra_keys.items()|length == 0 %}
233
233
  let extra: HashMap<String, String> = HashMap::new();
@@ -323,7 +323,7 @@ impl GleanEventsLogger {
323
323
  if let Some(event) = &params.event {
324
324
  events.push(event.glean_event());
325
325
  }
326
-
326
+
327
327
  {% else %}
328
328
  let events: Vec<GleanEvent> = Vec::new();
329
329
  {% endif %}