Skip to content

Commit ed82f64

Browse files
authored
Stats: Make defensive copy and set end time for ViewData when export. (census-instrumentation#512)
* Stats: Make defensive copy and set end time for ViewData when export. * Add test for shared exported view data * Rename method. * Fix one test. * Optimize import.
1 parent df87dba commit ed82f64

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

opencensus/stats/measure_to_view_map.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,7 @@ def get_view(self, view_name, timestamp):
6666
else:
6767
return None
6868

69-
view_data_copy = copy.copy(view_data)
70-
tvdam_copy = copy.deepcopy(view_data.tag_value_aggregation_data_map)
71-
view_data_copy._tag_value_aggregation_data_map = tvdam_copy
72-
view_data_copy.end()
73-
return view_data_copy
69+
return self.copy_and_finalize_view_data(view_data)
7470

7571
def filter_exported_views(self, all_views):
7672
"""returns the subset of the given view that should be exported"""
@@ -124,9 +120,11 @@ def record(self, tags, measurement_map, timestamp, attachments=None):
124120

125121
def export(self, view_datas):
126122
"""export view datas to registered exporters"""
123+
view_datas_copy = \
124+
[self.copy_and_finalize_view_data(vd) for vd in view_datas]
127125
if len(self.exporters) > 0:
128126
for e in self.exporters:
129-
e.export(view_datas)
127+
e.export(view_datas_copy)
130128

131129
def get_metrics(self, timestamp):
132130
"""Get a Metric for each registered view.
@@ -145,3 +143,11 @@ def get_metrics(self, timestamp):
145143
metric = metric_utils.view_data_to_metric(vd, timestamp)
146144
if metric is not None:
147145
yield metric
146+
147+
# TODO(issue #470): remove this method once we export immutable stats.
148+
def copy_and_finalize_view_data(self, view_data):
149+
view_data_copy = copy.copy(view_data)
150+
tvdam_copy = copy.deepcopy(view_data.tag_value_aggregation_data_map)
151+
view_data_copy._tag_value_aggregation_data_map = tvdam_copy
152+
view_data_copy.end()
153+
return view_data_copy

tests/unit/stats/test_measure_to_view_map.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,23 @@
1717
import mock
1818

1919
from opencensus.stats import measure_to_view_map as measure_to_view_map_module
20+
from opencensus.stats.aggregation import CountAggregation
2021
from opencensus.stats.measure import BaseMeasure
2122
from opencensus.stats.measure import MeasureInt
2223
from opencensus.stats.view import View
2324
from opencensus.stats.view_data import ViewData
25+
from opencensus.tags import tag_key as tag_key_module
26+
27+
28+
METHOD_KEY = tag_key_module.TagKey("method")
29+
REQUEST_COUNT_MEASURE = MeasureInt(
30+
"request_count", "number of requests", "1")
31+
REQUEST_COUNT_VIEW_NAME = "request_count_view"
32+
COUNT = CountAggregation()
33+
REQUEST_COUNT_VIEW = View(
34+
REQUEST_COUNT_VIEW_NAME,
35+
"number of requests broken down by methods",
36+
[METHOD_KEY], REQUEST_COUNT_MEASURE, COUNT)
2437

2538

2639
class TestMeasureToViewMap(unittest.TestCase):
@@ -378,3 +391,24 @@ def test_export(self):
378391
measure_to_view_map._registered_measures = {}
379392
measure_to_view_map.export(view_data)
380393
self.assertTrue(True)
394+
395+
def test_export_duplicates_viewdata(self):
396+
"""Check that we copy view data on export."""
397+
mtvm = measure_to_view_map_module.MeasureToViewMap()
398+
399+
exporter = mock.Mock()
400+
mtvm.exporters.append(exporter)
401+
402+
timestamp1 = mock.Mock()
403+
timestamp2 = mock.Mock()
404+
view_data = ViewData(REQUEST_COUNT_VIEW, timestamp1, timestamp2)
405+
mtvm.export([view_data])
406+
mtvm.export([view_data])
407+
self.assertEqual(exporter.export.call_count, 2)
408+
409+
exported_call1, exported_call2 = exporter.export.call_args_list
410+
exported_vd1 = exported_call1[0][0][0]
411+
exported_vd2 = exported_call2[0][0][0]
412+
self.assertIsNot(exported_vd1, exported_vd2)
413+
self.assertIsNot(exported_vd1.end_time, view_data.end_time)
414+
self.assertIsNot(exported_vd2.end_time, view_data.end_time)

0 commit comments

Comments
 (0)