@@ -67,8 +67,8 @@ def __init__(
67
67
) -> None :
68
68
self ._lock = RLock ()
69
69
self ._sdk_config = sdk_config
70
- self ._instrument_view_instrument_matches : Dict [
71
- Instrument , List [_ViewInstrumentMatch ]
70
+ self ._instrumentation_scope_instrument_view_instrument_matches : Dict [
71
+ InstrumentationScope , Dict [ Instrument , List [_ViewInstrumentMatch ] ]
72
72
] = {}
73
73
self ._instrument_class_temporality = instrument_class_temporality
74
74
self ._instrument_class_aggregation = instrument_class_aggregation
@@ -79,13 +79,33 @@ def _get_or_init_view_instrument_match(
79
79
# Optimistically get the relevant views for the given instrument. Once set for a given
80
80
# instrument, the mapping will never change
81
81
82
- if instrument in self ._instrument_view_instrument_matches :
83
- return self ._instrument_view_instrument_matches [instrument ]
82
+ if instrument .instrumentation_scope in (
83
+ self ._instrumentation_scope_instrument_view_instrument_matches
84
+ ) and instrument in (
85
+ self ._instrumentation_scope_instrument_view_instrument_matches [
86
+ instrument .instrumentation_scope
87
+ ]
88
+ ):
89
+ return (
90
+ self ._instrumentation_scope_instrument_view_instrument_matches [
91
+ instrument .instrumentation_scope
92
+ ][instrument ]
93
+ )
84
94
85
95
with self ._lock :
86
96
# double check if it was set before we held the lock
87
- if instrument in self ._instrument_view_instrument_matches :
88
- return self ._instrument_view_instrument_matches [instrument ]
97
+ if instrument .instrumentation_scope in (
98
+ self ._instrumentation_scope_instrument_view_instrument_matches
99
+ ) and instrument in (
100
+ self ._instrumentation_scope_instrument_view_instrument_matches [
101
+ instrument .instrumentation_scope
102
+ ]
103
+ ):
104
+ return self ._instrumentation_scope_instrument_view_instrument_matches [
105
+ instrument .instrumentation_scope
106
+ ][
107
+ instrument
108
+ ]
89
109
90
110
# not present, hold the lock and add a new mapping
91
111
view_instrument_matches = []
@@ -105,9 +125,6 @@ def _get_or_init_view_instrument_match(
105
125
),
106
126
)
107
127
)
108
- self ._instrument_view_instrument_matches [
109
- instrument
110
- ] = view_instrument_matches
111
128
112
129
return view_instrument_matches
113
130
@@ -139,83 +156,93 @@ def collect(self) -> MetricsData:
139
156
) = {}
140
157
141
158
for (
142
- instrument ,
143
- view_instrument_matches ,
144
- ) in self ._instrument_view_instrument_matches .items ():
145
- aggregation_temporality = self ._instrument_class_temporality [
146
- instrument .__class__
147
- ]
159
+ instrument_view_instrument_matches
160
+ ) in (
161
+ self ._instrumentation_scope_instrument_view_instrument_matches .values ()
162
+ ):
163
+ for (
164
+ instrument ,
165
+ view_instrument_matches ,
166
+ ) in instrument_view_instrument_matches .items ():
167
+ aggregation_temporality = (
168
+ self ._instrument_class_temporality [
169
+ instrument .__class__
170
+ ]
171
+ )
148
172
149
- metrics : List [Metric ] = []
173
+ metrics : List [Metric ] = []
150
174
151
- for view_instrument_match in view_instrument_matches :
175
+ for view_instrument_match in view_instrument_matches :
152
176
153
- if isinstance (
154
- # pylint: disable=protected-access
155
- view_instrument_match ._aggregation ,
156
- _SumAggregation ,
157
- ):
158
- data = Sum (
159
- aggregation_temporality = aggregation_temporality ,
160
- data_points = view_instrument_match .collect (
161
- aggregation_temporality , collection_start_nanos
162
- ),
163
- is_monotonic = isinstance (
164
- instrument , (Counter , ObservableCounter )
165
- ),
166
- )
167
- elif isinstance (
168
- # pylint: disable=protected-access
169
- view_instrument_match ._aggregation ,
170
- _LastValueAggregation ,
171
- ):
172
- data = Gauge (
173
- data_points = view_instrument_match .collect (
174
- aggregation_temporality , collection_start_nanos
177
+ if isinstance (
178
+ # pylint: disable=protected-access
179
+ view_instrument_match ._aggregation ,
180
+ _SumAggregation ,
181
+ ):
182
+ data = Sum (
183
+ aggregation_temporality = aggregation_temporality ,
184
+ data_points = view_instrument_match .collect (
185
+ aggregation_temporality ,
186
+ collection_start_nanos ,
187
+ ),
188
+ is_monotonic = isinstance (
189
+ instrument , (Counter , ObservableCounter )
190
+ ),
175
191
)
176
- )
177
- elif isinstance (
178
- # pylint: disable=protected-access
179
- view_instrument_match ._aggregation ,
180
- _ExplicitBucketHistogramAggregation ,
181
- ):
182
- data = Histogram (
183
- data_points = view_instrument_match .collect (
184
- aggregation_temporality , collection_start_nanos
185
- ),
186
- aggregation_temporality = aggregation_temporality ,
187
- )
188
- elif isinstance (
189
- # pylint: disable=protected-access
190
- view_instrument_match ._aggregation ,
191
- _DropAggregation ,
192
- ):
193
- continue
194
-
195
- metrics .append (
196
- Metric (
192
+ elif isinstance (
197
193
# pylint: disable=protected-access
198
- name = view_instrument_match ._name ,
199
- description = view_instrument_match ._description ,
200
- unit = view_instrument_match ._instrument .unit ,
201
- data = data ,
194
+ view_instrument_match ._aggregation ,
195
+ _LastValueAggregation ,
196
+ ):
197
+ data = Gauge (
198
+ data_points = view_instrument_match .collect (
199
+ aggregation_temporality ,
200
+ collection_start_nanos ,
201
+ )
202
+ )
203
+ elif isinstance (
204
+ # pylint: disable=protected-access
205
+ view_instrument_match ._aggregation ,
206
+ _ExplicitBucketHistogramAggregation ,
207
+ ):
208
+ data = Histogram (
209
+ data_points = view_instrument_match .collect (
210
+ aggregation_temporality ,
211
+ collection_start_nanos ,
212
+ ),
213
+ aggregation_temporality = aggregation_temporality ,
214
+ )
215
+ elif isinstance (
216
+ # pylint: disable=protected-access
217
+ view_instrument_match ._aggregation ,
218
+ _DropAggregation ,
219
+ ):
220
+ continue
221
+
222
+ metrics .append (
223
+ Metric (
224
+ # pylint: disable=protected-access
225
+ name = view_instrument_match ._name ,
226
+ description = view_instrument_match ._description ,
227
+ unit = view_instrument_match ._instrument .unit ,
228
+ data = data ,
229
+ )
202
230
)
203
- )
204
231
205
- if instrument .instrumentation_scope not in (
206
- instrumentation_scope_scope_metrics
207
- ):
208
- instrumentation_scope_scope_metrics [
209
- instrument .instrumentation_scope
210
- ] = ScopeMetrics (
211
- scope = instrument .instrumentation_scope ,
212
- metrics = metrics ,
213
- schema_url = instrument .instrumentation_scope .schema_url ,
214
- )
215
- else :
216
- instrumentation_scope_scope_metrics [
217
- instrument .instrumentation_scope
218
- ].metrics .extend (metrics )
232
+ if instrument .instrumentation_scope not in (
233
+ instrumentation_scope_scope_metrics
234
+ ):
235
+ instrumentation_scope_scope_metrics [
236
+ instrument .instrumentation_scope
237
+ ] = ScopeMetrics (
238
+ scope = instrument .instrumentation_scope ,
239
+ metrics = metrics ,
240
+ schema_url = instrument .instrumentation_scope .schema_url ,
241
+ )
242
+ else :
243
+ instrumentation_scope_scope_metrics [
244
+ instrument .instrumentation_scope
245
+ ].metrics .extend (metrics )
219
246
220
247
return MetricsData (
221
248
resource_metrics = [
@@ -229,11 +256,30 @@ def collect(self) -> MetricsData:
229
256
]
230
257
)
231
258
259
+ # pylint: disable=too-many-branches
232
260
def _handle_view_instrument_match (
233
261
self ,
234
262
instrument : Instrument ,
235
263
view_instrument_matches : List ["_ViewInstrumentMatch" ],
236
264
) -> None :
265
+
266
+ if instrument .instrumentation_scope not in (
267
+ self ._instrumentation_scope_instrument_view_instrument_matches
268
+ ):
269
+ self ._instrumentation_scope_instrument_view_instrument_matches [
270
+ instrument .instrumentation_scope
271
+ ] = {}
272
+
273
+ if instrument not in (
274
+ self ._instrumentation_scope_instrument_view_instrument_matches [
275
+ instrument .instrumentation_scope
276
+ ]
277
+ ):
278
+ self ._instrumentation_scope_instrument_view_instrument_matches [
279
+ instrument .instrumentation_scope
280
+ ][instrument ] = view_instrument_matches
281
+
282
+ # pylint: disable=too-many-nested-blocks
237
283
for view in self ._sdk_config .views :
238
284
# pylint: disable=protected-access
239
285
if not view ._match (instrument ):
@@ -252,20 +298,64 @@ def _handle_view_instrument_match(
252
298
253
299
for (
254
300
existing_view_instrument_matches
255
- ) in self ._instrument_view_instrument_matches .values ():
301
+ ) in self ._instrumentation_scope_instrument_view_instrument_matches [
302
+ instrument .instrumentation_scope
303
+ ].values ():
256
304
for (
257
305
existing_view_instrument_match
258
306
) in existing_view_instrument_matches :
259
- if existing_view_instrument_match .conflicts (
260
- new_view_instrument_match
307
+
308
+ conflict_messages = []
309
+
310
+ if (
311
+ existing_view_instrument_match ._name
312
+ == new_view_instrument_match ._name
261
313
):
262
314
263
- _logger .warning (
264
- "Views %s and %s will cause conflicting "
265
- "metrics identities" ,
266
- existing_view_instrument_match ._view ,
267
- new_view_instrument_match ._view ,
268
- )
315
+ if (
316
+ existing_view_instrument_match ._description
317
+ != new_view_instrument_match ._description
318
+ ):
319
+ conflict_messages .append ("description" )
320
+
321
+ # The aggregation class is being used here instead of
322
+ # data point type since they are functionally
323
+ # equivalent.
324
+ if (
325
+ existing_view_instrument_match ._aggregation .__class__
326
+ != new_view_instrument_match ._aggregation .__class__
327
+ ):
328
+ conflict_messages .append ("aggregation" )
329
+
330
+ elif isinstance (
331
+ existing_view_instrument_match ._aggregation ,
332
+ _SumAggregation ,
333
+ ):
334
+ if (
335
+ existing_view_instrument_match ._aggregation ._instrument_is_monotonic
336
+ != new_view_instrument_match ._aggregation ._instrument_is_monotonic
337
+ ):
338
+ conflict_messages .append ("monotonicity" )
339
+
340
+ if (
341
+ existing_view_instrument_match ._aggregation ._instrument_temporality
342
+ != new_view_instrument_match ._aggregation ._instrument_temporality
343
+ ):
344
+ conflict_messages .append (
345
+ "aggregation temporality"
346
+ )
347
+
348
+ if conflict_messages :
349
+
350
+ _logger .warning (
351
+ "Views named %s will cause conflicting "
352
+ "metrics identities for instrument %s because "
353
+ "of different %s. Rename a view named %s." ,
354
+ existing_view_instrument_match ._view ._name ,
355
+ instrument .name ,
356
+ "," .join (conflict_messages ),
357
+ new_view_instrument_match ._view ._name ,
358
+ )
269
359
270
360
view_instrument_matches .append (new_view_instrument_match )
271
361
0 commit comments