1111 from ray .util .metrics import Metric
1212except ImportError :
1313 ray_metrics = None
14+ import regex as re
1415
1516
1617class RayPrometheusMetric :
@@ -42,6 +43,21 @@ def labels(self, *labels, **labelskwargs):
4243
4344 return self
4445
46+ @staticmethod
47+ def _get_sanitized_opentelemetry_name (name : str ) -> str :
48+ """
49+ For compatibility with Ray + OpenTelemetry, the metric name must be
50+ sanitized. In particular, this replaces disallowed character (e.g., ':')
51+ with '_' in the metric name.
52+ Allowed characters: a-z, A-Z, 0-9, _
53+
54+ # ruff: noqa: E501
55+ Ref: https://github.com/open-telemetry/opentelemetry-cpp/blob/main/sdk/src/metrics/instrument_metadata_validator.cc#L22-L23
56+ Ref: https://github.com/ray-project/ray/blob/master/src/ray/stats/metric.cc#L107
57+ """
58+
59+ return re .sub (r"[^a-zA-Z0-9_]" , "_" , name )
60+
4561
4662class RayGaugeWrapper (RayPrometheusMetric ):
4763 """Wraps around ray.util.metrics.Gauge to provide same API as
@@ -58,6 +74,7 @@ def __init__(self,
5874 # implemented at the observability layer (Prometheus/Grafana).
5975 del multiprocess_mode
6076 labelnames_tuple = tuple (labelnames ) if labelnames else None
77+ name = self ._get_sanitized_opentelemetry_name (name )
6178 self .metric = ray_metrics .Gauge (name = name ,
6279 description = documentation ,
6380 tag_keys = labelnames_tuple )
@@ -79,6 +96,7 @@ def __init__(self,
7996 documentation : Optional [str ] = "" ,
8097 labelnames : Optional [list [str ]] = None ):
8198 labelnames_tuple = tuple (labelnames ) if labelnames else None
99+ name = self ._get_sanitized_opentelemetry_name (name )
82100 self .metric = ray_metrics .Counter (name = name ,
83101 description = documentation ,
84102 tag_keys = labelnames_tuple )
@@ -99,6 +117,7 @@ def __init__(self,
99117 labelnames : Optional [list [str ]] = None ,
100118 buckets : Optional [list [float ]] = None ):
101119 labelnames_tuple = tuple (labelnames ) if labelnames else None
120+ name = self ._get_sanitized_opentelemetry_name (name )
102121 boundaries = buckets if buckets else []
103122 self .metric = ray_metrics .Histogram (name = name ,
104123 description = documentation ,
0 commit comments