1717from collections import defaultdict
1818import logging
1919import time
20+ from typing import Any , Mapping
2021
2122from google .api .distribution_pb2 import Distribution
2223from google .api .metric_pb2 import Metric as GMetric
4243 NumberDataPoint ,
4344 PeriodicExportingMetricReader ,
4445)
46+ from opentelemetry .util .types import Attributes
4547
4648from google .cloud .bigtable .data ._metrics .handlers .opentelemetry import (
4749 OpenTelemetryMetricsHandler ,
8991 for n in INSTRUMENT_NAMES
9092]
9193
94+ # Maps OpenTelemetry data point resource attribute names to Cloud Monitoring MonitoredResource label names
95+ _RESOURCE_KEY_MAP = {
96+ "resource_project" : "project_id" ,
97+ "resource_instance" : "instance" ,
98+ "resource_cluster" : "cluster" ,
99+ "resource_table" : "table" ,
100+ "resource_zone" : "zone" ,
101+ }
102+
103+
104+ def _partition_attributes (
105+ attributes : Attributes
106+ ) -> tuple [dict [str , str ], dict [str , str ]]:
107+ """Split data point attributes into monitored resource labels and metric labels."""
108+ resource_labels = {label_name : "" for label_name in _RESOURCE_KEY_MAP .values ()}
109+ metric_labels = {}
110+ for attr_key , attr_value in attributes .items ():
111+ if attr_key in _RESOURCE_KEY_MAP :
112+ resource_labels [_RESOURCE_KEY_MAP [attr_key ]] = str (attr_value )
113+ elif not attr_key .startswith ("resource_" ):
114+ metric_labels [attr_key ] = str (attr_value )
115+ return resource_labels , metric_labels
116+
92117
93118class GoogleCloudMetricsHandler (OpenTelemetryMetricsHandler ):
94119 """
@@ -161,9 +186,10 @@ def export(
161186 for metric in scope_metric .metrics :
162187 for data_point in metric .data .data_points :
163188 if data_point .attributes :
164- project_id = data_point . attributes . get (
165- "resource_project" , ""
189+ resource_labels , metric_labels = _partition_attributes (
190+ data_point . attributes
166191 )
192+ project_id = resource_labels .get ("project_id" , "" )
167193 if not project_id :
168194 _LOGGER .warning (
169195 "Missing resource_project attribute for metric %s" ,
@@ -172,21 +198,7 @@ def export(
172198 continue
173199 monitored_resource = MonitoredResource (
174200 type = "bigtable_client_raw" ,
175- labels = {
176- "project_id" : project_id ,
177- "instance" : data_point .attributes .get (
178- "resource_instance" , ""
179- ),
180- "cluster" : data_point .attributes .get (
181- "resource_cluster" , ""
182- ),
183- "table" : data_point .attributes .get (
184- "resource_table" , ""
185- ),
186- "zone" : data_point .attributes .get (
187- "resource_zone" , ""
188- ),
189- },
201+ labels = resource_labels ,
190202 )
191203 try :
192204 point = self ._to_point (data_point )
@@ -204,11 +216,7 @@ def export(
204216 points = [point ],
205217 metric = GMetric (
206218 type = f"{ self .prefix } /{ metric .name } " ,
207- labels = {
208- k : str (v )
209- for k , v in data_point .attributes .items ()
210- if not k .startswith ("resource_" )
211- },
219+ labels = metric_labels ,
212220 ),
213221 unit = metric .unit ,
214222 )
0 commit comments