@@ -188,19 +188,32 @@ def _instantiate_metrics(
188188 if category_key == "no_lint" :
189189 continue
190190 if not config .get ("allow_reserved" ) and category_key .split ("." )[0 ] == "glean" :
191- yield util .format_error (
192- filepath ,
193- f"For category '{ category_key } '" ,
194- "Categories beginning with 'glean' are reserved for "
195- "Glean internal use." ,
196- )
197- continue
191+ if category_key not in ("glean.attribution" , "glean.distribution" ):
192+ yield util .format_error (
193+ filepath ,
194+ f"For category '{ category_key } '" ,
195+ "Categories beginning with 'glean' are reserved for "
196+ "Glean internal use." ,
197+ )
198+ continue
198199 all_objects .setdefault (category_key , DictWrapper ())
199200
200201 if not isinstance (category_val , dict ):
201202 raise TypeError (f"Invalid content for { category_key } " )
202203
203204 for metric_key , metric_val in sorted (category_val .items ()):
205+ if (
206+ not config .get ("allow_reserved" )
207+ and category_key in ("glean.attribution" , "glean.distribution" )
208+ and metric_key != "ext"
209+ ):
210+ yield util .format_error (
211+ filepath ,
212+ f"For { category_key } .{ metric_key } " ,
213+ f"May only use semi-reserved category { category_key } with metric name 'ext'" ,
214+ metric_val .defined_in ["line" ],
215+ )
216+ continue
204217 try :
205218 metric_obj = Metric .make_metric (
206219 category_key , metric_key , metric_val , validated = True , config = config
@@ -214,18 +227,28 @@ def _instantiate_metrics(
214227 )
215228 metric_obj = None
216229 else :
217- if (
218- not config .get ("allow_reserved" )
219- and "all-pings" in metric_obj .send_in_pings
220- ):
221- yield util .format_error (
222- filepath ,
223- f"On instance { category_key } .{ metric_key } " ,
224- 'Only internal metrics may specify "all-pings" '
225- 'in "send_in_pings"' ,
226- metric_val .defined_in ["line" ],
227- )
228- metric_obj = None
230+ if not config .get ("allow_reserved" ):
231+ if "all-pings" in metric_obj .send_in_pings :
232+ yield util .format_error (
233+ filepath ,
234+ f"On instance { category_key } .{ metric_key } " ,
235+ 'Only internal metrics may specify "all-pings" '
236+ 'in "send_in_pings"' ,
237+ metric_val .defined_in ["line" ],
238+ )
239+ metric_obj = None
240+ elif (
241+ metric_obj .identifier ()
242+ in ("glean.attribution.ext" , "glean.distribution.ext" )
243+ and metric_obj .type != "object"
244+ ):
245+ yield util .format_error (
246+ filepath ,
247+ f"On instance { category_key } .{ metric_key } " ,
248+ "Extended attribution/distribution metrics must be of type 'object'" ,
249+ metric_val .defined_in ["line" ],
250+ )
251+ metric_obj = None
229252
230253 if metric_obj is not None :
231254 metric_obj .no_lint = sorted (set (metric_obj .no_lint + global_no_lint ))
@@ -481,16 +504,16 @@ def parse_objects(
481504 raise TypeError (f"Invalid content for { filepath } " )
482505
483506 for category_key , category_val in sorted (content .items ()):
484- if category_key .startswith ("$" ):
485- continue
507+ if category_key .startswith ("$" ):
508+ continue
486509
487- interesting_metrics_dict .setdefault (category_key , DictWrapper ())
510+ interesting_metrics_dict .setdefault (category_key , DictWrapper ())
488511
489- if not isinstance (category_val , dict ):
490- raise TypeError (f"Invalid category_val for { category_key } " )
512+ if not isinstance (category_val , dict ):
513+ raise TypeError (f"Invalid category_val for { category_key } " )
491514
492- for metric_key , metric_val in sorted (category_val .items ()):
493- interesting_metrics_dict [category_key ][metric_key ] = metric_val
515+ for metric_key , metric_val in sorted (category_val .items ()):
516+ interesting_metrics_dict [category_key ][metric_key ] = metric_val
494517
495518 for category_key , category_val in all_objects .items ():
496519 if category_key == "tags" :
0 commit comments