99from enum import Enum , auto
1010from importlib .metadata import PackageNotFoundError
1111from importlib .metadata import version as importlib_version
12- from typing import Annotated , Any , ClassVar , Literal , Self , Union
12+ from typing import Annotated , Any , ClassVar , Literal , Mapping , Self , TypedDict , Union
1313from uuid import uuid4
1414
1515import numpy as np
@@ -1192,8 +1192,19 @@ class ServiceMetricMessage(BECMessage):
11921192
11931193class _StrDynamicMetricValue (BaseModel ):
11941194 value : str
1195+ possible_values : list [str ]
11951196 type_name : Literal ["str" ] = "str"
11961197
1198+ @model_validator (mode = "after" )
1199+ def _validate (self ) -> Self :
1200+ if self .value not in self .possible_values :
1201+ raise ValueError (
1202+ f"Invalid string metric: value '{ self .value } ' not in possible values: '{ self .possible_values } '. Provide the possible values for string metrics."
1203+ )
1204+ if len (set (self .possible_values )) != len (self .possible_values ):
1205+ raise ValueError (f"Duplicates in possible values: { self .possible_values } " )
1206+ return self
1207+
11971208
11981209class _IntDynamicMetricValue (BaseModel ):
11991210 value : int
@@ -1219,6 +1230,14 @@ class _BoolDynamicMetricValue(BaseModel):
12191230]
12201231
12211232
1233+ class StringMetricDict (TypedDict ):
1234+ value : str
1235+ possible_values : list [str ]
1236+
1237+
1238+ DynamicMetricDict = Mapping [str , StringMetricDict | int | float | bool ]
1239+
1240+
12221241class DynamicMetricMessage (BECMessage ):
12231242 """Message for propagating metrics to the log ingestor.
12241243
@@ -1230,14 +1249,16 @@ class DynamicMetricMessage(BECMessage):
12301249 timestamp : float = Field (default_factory = time .time )
12311250
12321251 @classmethod
1233- def from_dict (cls , metrics : dict [str , str | int | float | bool ], separator : str = "-" ):
1252+ def from_dict (cls , metrics : DynamicMetricDict , separator : str = "-" ):
1253+ def _fmt (value ):
1254+ if isinstance (value , dict ):
1255+ return {"type_name" : "str" , ** value }
1256+ return {"value" : value , "type_name" : type (value ).__name__ }
1257+
12341258 return cls .model_validate (
12351259 {
1236- "metrics" : {
1237- # Metric names are concatenated with the group in the ingestor
1238- separator + k : {"value" : v , "type_name" : type (v ).__name__ }
1239- for k , v in metrics .items ()
1240- }
1260+ # Metric names are concatenated with the group in the ingestor
1261+ "metrics" : {separator + k : _fmt (v ) for k , v in metrics .items ()}
12411262 }
12421263 )
12431264
0 commit comments