Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.

Commit c960835

Browse files
authored
Monitored Resource: replace gke_container with k8s_container in Stack… (#322)
* Monitored Resource: replace gke_container with k8s_container in Stackdriver exporter * minor fix
1 parent fea059e commit c960835

6 files changed

Lines changed: 306 additions & 48 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,6 @@ system_tests/local_test_setup
6363
# Make sure a generated file isn't accidentally committed.
6464
pylintrc
6565
pylintrc.test
66+
67+
# Ignore default file, used for exporting the trace spans.
68+
opencensus-traces.json

examples/stats/exporter/stackdriver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@
5353

5454
# Process video.
5555
# Record the processed video size.
56-
tag_value = tag_value_module.TagValue(1200)
56+
tag_value = tag_value_module.TagValue(str(1200))
5757
tag_map = tag_map_module.TagMap()
5858
tag_map.insert(FRONTEND_KEY, tag_value)
5959
measure_map = stats_recorder.new_measurement_map()
6060
measure_map.measure_int_put(VIDEO_SIZE_MEASURE, 25 * MiB)
6161

62-
measure_map.record(tag_map)
62+
measure_map.record(tag_map)

opencensus/stats/exporters/stackdriver_exporter.py

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
CONS_TIME_SERIES = "timeseries"
3333
EPOCH_DATETIME = datetime(1970, 1, 1)
3434
EPOCH_PATTERN = "%Y-%m-%dT%H:%M:%S.%fZ"
35+
GLOBAL_RESOURCE_TYPE = 'global'
3536

3637

3738
class Options(object):
@@ -188,26 +189,14 @@ def make_request(self, view_data, limit):
188189
time_series = []
189190
return requests
190191

191-
def create_time_series_list(self, v_data, resource_type, metric_prefix):
192+
def create_time_series_list(self, v_data, option_resource_type,
193+
metric_prefix):
192194
""" Create the TimeSeries object based on the view data
193195
"""
194196
series = monitoring_v3.types.TimeSeries()
195197
series.metric.type = namespaced_view_name(v_data.view.name,
196198
metric_prefix)
197-
198-
if resource_type == "":
199-
monitor_resource = MonitoredResourceUtil.get_instance()
200-
if monitor_resource is not None:
201-
series.resource.type = monitor_resource.resource_type
202-
labels = monitor_resource.get_resource_labels()
203-
for attribute_key, attribute_value in labels.items():
204-
attribute_value = 'aws:' + attribute_value if \
205-
attribute_key == 'region' else attribute_value
206-
series.resource.labels[attribute_key] = attribute_value
207-
else:
208-
series.resource.type = 'global'
209-
else:
210-
series.resource.type = resource_type
199+
set_monitored_resource(series, option_resource_type)
211200

212201
tag_agg = v_data.tag_value_aggregation_data_map
213202
for tag_value, agg in tag_agg.items():
@@ -330,6 +319,65 @@ def create_metric_descriptor(self, view):
330319
return descriptor
331320

332321

322+
def set_monitored_resource(series, option_resource_type):
323+
"""Set a resource(type and labels) that can be used for monitoring.
324+
:param series: TimeSeries object based on view data
325+
:param option_resource_type: Resource is an optional field that
326+
represents the Stackdriver MonitoredResource type.
327+
"""
328+
resource_type = GLOBAL_RESOURCE_TYPE
329+
330+
if option_resource_type == "":
331+
monitored_resource = MonitoredResourceUtil.get_instance()
332+
if monitored_resource is not None:
333+
resource_labels = monitored_resource.get_resource_labels()
334+
335+
if monitored_resource.resource_type == 'gke_container':
336+
resource_type = 'k8s_container'
337+
set_attribute_label(series, resource_labels, 'project_id')
338+
set_attribute_label(series, resource_labels, 'cluster_name')
339+
set_attribute_label(series, resource_labels, 'container_name')
340+
set_attribute_label(series, resource_labels, 'namespace_id',
341+
'namespace_name')
342+
set_attribute_label(series, resource_labels, 'pod_id',
343+
'pod_name')
344+
set_attribute_label(series, resource_labels, 'zone',
345+
'location')
346+
347+
elif monitored_resource.resource_type == 'gce_instance':
348+
resource_type = monitored_resource.resource_type
349+
set_attribute_label(series, resource_labels, 'project_id')
350+
set_attribute_label(series, resource_labels, 'instance_id')
351+
set_attribute_label(series, resource_labels, 'zone')
352+
353+
elif monitored_resource.resource_type == 'aws_ec2_instance':
354+
resource_type = monitored_resource.resource_type
355+
set_attribute_label(series, resource_labels, 'aws_account')
356+
set_attribute_label(series, resource_labels, 'instance_id')
357+
set_attribute_label(series, resource_labels, 'region',
358+
label_value_prefix='aws:')
359+
else:
360+
resource_type = option_resource_type
361+
series.resource.type = resource_type
362+
363+
364+
def set_attribute_label(series, resource_labels, attribute_key,
365+
canonical_key=None, label_value_prefix=''):
366+
"""Set a label to timeseries that can be used for monitoring
367+
:param series: TimeSeries object based on view data
368+
:param resource_labels: collection of labels
369+
:param attribute_key: actual label key
370+
:param canonical_key: exporter specific label key, Optional
371+
:param label_value_prefix: exporter specific label value prefix, Optional
372+
"""
373+
if attribute_key in resource_labels:
374+
if canonical_key is None:
375+
canonical_key = attribute_key
376+
377+
series.resource.labels[canonical_key] = \
378+
label_value_prefix + resource_labels[attribute_key]
379+
380+
333381
def new_stats_exporter(options):
334382
""" new_stats_exporter returns an exporter that
335383
uploads stats data to Stackdriver Monitoring.

opencensus/trace/exporters/stackdriver_exporter.py

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,21 +77,68 @@ def set_attributes(trace):
7777

7878

7979
def set_monitored_resource_attributes(span):
80+
"""Set labels to span that can be used for tracing.
81+
:param span: Span object
82+
"""
8083
monitored_resource = MonitoredResourceUtil.get_instance()
81-
8284
if monitored_resource is not None:
85+
resource_type = monitored_resource.resource_type
8386
resource_labels = monitored_resource.get_resource_labels()
84-
for attribute_key, attribute_value in resource_labels.items():
85-
86-
attribute_value = 'aws:' + attribute_value if \
87-
attribute_key == 'region' else attribute_value
88-
pair = {RESOURCE_LABEL % (monitored_resource.resource_type,
89-
attribute_key): attribute_value}
90-
pair_attrs = Attributes(pair) \
91-
.format_attributes_json() \
92-
.get('attributeMap')
9387

94-
_update_attr_map(span, pair_attrs)
88+
if resource_type == 'gke_container':
89+
resource_type = 'k8s_container'
90+
set_attribute_label(span, resource_type, resource_labels,
91+
'project_id')
92+
set_attribute_label(span, resource_type, resource_labels,
93+
'cluster_name')
94+
set_attribute_label(span, resource_type, resource_labels,
95+
'container_name')
96+
set_attribute_label(span, resource_type, resource_labels,
97+
'namespace_id', 'namespace_name')
98+
set_attribute_label(span, resource_type, resource_labels,
99+
'pod_id', 'pod_name')
100+
set_attribute_label(span, resource_type, resource_labels,
101+
'zone', 'location')
102+
103+
elif resource_type == 'gce_instance':
104+
set_attribute_label(span, resource_type, resource_labels,
105+
'project_id')
106+
set_attribute_label(span, resource_type, resource_labels,
107+
'instance_id')
108+
set_attribute_label(span, resource_type, resource_labels,
109+
'zone')
110+
111+
elif resource_type == 'aws_ec2_instance':
112+
set_attribute_label(span, resource_type, resource_labels,
113+
'aws_account')
114+
set_attribute_label(span, resource_type, resource_labels,
115+
'instance_id')
116+
set_attribute_label(span, resource_type, resource_labels,
117+
'region', label_value_prefix='aws:')
118+
119+
120+
def set_attribute_label(span, resource_type, resource_labels, attribute_key,
121+
canonical_key=None, label_value_prefix=''):
122+
"""Set a label to span that can be used for tracing.
123+
:param span: Span object
124+
:param resource_type: resource type
125+
:param resource_labels: collection of labels
126+
:param attribute_key: actual label key
127+
:param canonical_key: exporter specific label key, Optional
128+
:param label_value_prefix: exporter specific label value prefix, Optional
129+
"""
130+
131+
if attribute_key in resource_labels:
132+
if canonical_key is None:
133+
canonical_key = attribute_key
134+
135+
pair = {RESOURCE_LABEL % (resource_type, canonical_key):
136+
label_value_prefix + resource_labels[attribute_key]
137+
}
138+
pair_attrs = Attributes(pair).format_attributes_json()\
139+
.get('attributeMap')
140+
141+
_update_attr_map(span, pair_attrs)
95142

96143

97144
def set_common_attributes(span):

tests/unit/stats/exporter/test_stackdriver_stats.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ def test_create_timeseries_with_resource(self, monitor_resource_mock):
335335

336336
v_data = measure_map.measure_to_view_map.get_view(VIDEO_SIZE_VIEW_NAME, None)
337337

338+
# check for gce_instance monitored resource
338339
mocked_labels = {
339340
'instance_id': 'my-instance',
340341
'project_id': 'my-project',
@@ -351,11 +352,68 @@ def test_create_timeseries_with_resource(self, monitor_resource_mock):
351352
self.assertEquals(time_series.resource.type, "gce_instance")
352353
self.assertEquals(time_series.metric.type, "custom.googleapis.com/opencensus/my.org/views/video_size_test2")
353354
self.assertIsNotNone(time_series)
355+
self.assertEquals(time_series.resource.labels['instance_id'], 'my-instance')
356+
self.assertEquals(time_series.resource.labels['project_id'], 'my-project')
357+
self.assertEquals(time_series.resource.labels['zone'], 'us-east1')
354358

355359
time_series = exporter.create_time_series_list(v_data, "global", "")
356360
self.assertEquals(time_series.metric.type, "custom.googleapis.com/opencensus/my.org/views/video_size_test2")
357361
self.assertIsNotNone(time_series)
358362

363+
# check for gke_container monitored resource
364+
mocked_labels = {
365+
'instance_id': 'my-instance',
366+
'project_id': 'my-project',
367+
'zone': 'us-east1',
368+
'pod_id': 'localhost',
369+
'cluster_name': 'cluster',
370+
'namespace_id': 'namespace'
371+
}
372+
373+
monitor_resource_mock.return_value = mock.Mock()
374+
monitor_resource_mock.return_value.resource_type = 'gke_container'
375+
monitor_resource_mock.return_value.get_resource_labels.return_value = mocked_labels
376+
377+
time_series = exporter.create_time_series_list(v_data, "", "")
378+
self.assertEquals(time_series.resource.type, "k8s_container")
379+
self.assertEquals(time_series.metric.type, "custom.googleapis.com/opencensus/my.org/views/video_size_test2")
380+
self.assertIsNotNone(time_series)
381+
self.assertEquals(time_series.resource.labels['project_id'], 'my-project')
382+
self.assertEquals(time_series.resource.labels['location'], 'us-east1')
383+
self.assertEquals(time_series.resource.labels['pod_name'], 'localhost')
384+
self.assertEquals(time_series.resource.labels['namespace_name'], 'namespace')
385+
self.assertEquals(time_series.resource.labels['container_name'], '')
386+
387+
# check for aws_ec2_instance monitored resource
388+
mocked_labels = {
389+
'instance_id': 'my-instance',
390+
'aws_account': 'my-project',
391+
'region': 'us-east1',
392+
}
393+
394+
monitor_resource_mock.return_value = mock.Mock()
395+
monitor_resource_mock.return_value.resource_type = 'aws_ec2_instance'
396+
monitor_resource_mock.return_value.get_resource_labels.return_value = mocked_labels
397+
398+
time_series = exporter.create_time_series_list(v_data, "", "")
399+
self.assertEquals(time_series.resource.type, "aws_ec2_instance")
400+
self.assertEquals(time_series.metric.type, "custom.googleapis.com/opencensus/my.org/views/video_size_test2")
401+
self.assertIsNotNone(time_series)
402+
self.assertEquals(time_series.resource.labels['instance_id'], 'my-instance')
403+
self.assertEquals(time_series.resource.labels['aws_account'], 'my-project')
404+
self.assertEquals(time_series.resource.labels['region'], 'aws:us-east1')
405+
406+
# check for out of box monitored resource
407+
monitor_resource_mock.return_value = mock.Mock()
408+
monitor_resource_mock.return_value.resource_type = ''
409+
monitor_resource_mock.return_value.get_resource_labels.return_value = mock.Mock()
410+
411+
time_series = exporter.create_time_series_list(v_data, "", "")
412+
self.assertEquals(time_series.resource.type, 'global')
413+
self.assertEquals(time_series.metric.type, "custom.googleapis.com/opencensus/my.org/views/video_size_test2")
414+
self.assertIsNotNone(time_series)
415+
416+
359417
@mock.patch('opencensus.stats.exporters.stackdriver_exporter.'
360418
'MonitoredResourceUtil.get_instance', return_value=None)
361419
def test_create_timeseries_str_tagvalue(self, monitor_resource_mock):

0 commit comments

Comments
 (0)