|
19 | 19 | from flask import Flask, request |
20 | 20 |
|
21 | 21 | from opentelemetry import trace |
| 22 | +from opentelemetry.instrumentation._labeler import ( |
| 23 | + clear_labeler, |
| 24 | + get_labeler, |
| 25 | +) |
22 | 26 | from opentelemetry.instrumentation._semconv import ( |
23 | 27 | HTTP_DURATION_HISTOGRAM_BUCKETS_NEW, |
24 | 28 | OTEL_SEMCONV_STABILITY_OPT_IN, |
@@ -120,6 +124,23 @@ def expected_attributes_new(override_attributes): |
120 | 124 | "http.server.request.duration": _server_duration_attrs_new_copy, |
121 | 125 | } |
122 | 126 |
|
| 127 | +_custom_attributes = ["custom_attr", "endpoint_type", "feature_flag"] |
| 128 | +_server_duration_attrs_old_with_custom = _server_duration_attrs_old.copy() |
| 129 | +_server_duration_attrs_old_with_custom.append("http.target") |
| 130 | +_server_duration_attrs_old_with_custom.extend(_custom_attributes) |
| 131 | +_server_duration_attrs_new_with_custom = _server_duration_attrs_new.copy() |
| 132 | +_server_duration_attrs_new_with_custom.append("http.route") |
| 133 | +_server_duration_attrs_new_with_custom.extend(_custom_attributes) |
| 134 | + |
| 135 | +_recommended_metrics_attrs_old_with_custom = { |
| 136 | + "http.server.active_requests": _server_active_requests_count_attrs_old, |
| 137 | + "http.server.duration": _server_duration_attrs_old_with_custom, |
| 138 | +} |
| 139 | +_recommended_metrics_attrs_new_with_custom = { |
| 140 | + "http.server.active_requests": _server_active_requests_count_attrs_new, |
| 141 | + "http.server.request.duration": _server_duration_attrs_new_with_custom, |
| 142 | +} |
| 143 | + |
123 | 144 |
|
124 | 145 | # pylint: disable=too-many-public-methods |
125 | 146 | class TestProgrammatic(InstrumentationTest, WsgiTestBase): |
@@ -151,7 +172,23 @@ def setUp(self): |
151 | 172 | ) |
152 | 173 | self.exclude_patch.start() |
153 | 174 |
|
| 175 | + clear_labeler() |
| 176 | + |
154 | 177 | self.app = Flask(__name__) |
| 178 | + |
| 179 | + @self.app.route("/test_labeler") |
| 180 | + def test_labeler_route(): |
| 181 | + labeler = get_labeler() |
| 182 | + labeler.add("custom_attr", "test_value") |
| 183 | + labeler.add_attributes( |
| 184 | + {"endpoint_type": "test", "feature_flag": True} |
| 185 | + ) |
| 186 | + return "OK" |
| 187 | + |
| 188 | + @self.app.route("/no_labeler") |
| 189 | + def test_no_labeler_route(): |
| 190 | + return "No labeler" |
| 191 | + |
155 | 192 | FlaskInstrumentor().instrument_app(self.app) |
156 | 193 |
|
157 | 194 | self._common_initialization() |
@@ -499,6 +536,42 @@ def test_flask_metrics(self): |
499 | 536 | ) |
500 | 537 | self.assertTrue(number_data_point_seen and histogram_data_point_seen) |
501 | 538 |
|
| 539 | + def test_flask_metrics_custom_attributes(self): |
| 540 | + start = default_timer() |
| 541 | + self.client.get("/test_labeler") |
| 542 | + self.client.get("/test_labeler") |
| 543 | + self.client.get("/test_labeler") |
| 544 | + duration = max(round((default_timer() - start) * 1000), 0) |
| 545 | + metrics_list = self.memory_metrics_reader.get_metrics_data() |
| 546 | + number_data_point_seen = False |
| 547 | + histogram_data_point_seen = False |
| 548 | + self.assertTrue(len(metrics_list.resource_metrics) != 0) |
| 549 | + for resource_metric in metrics_list.resource_metrics: |
| 550 | + self.assertTrue(len(resource_metric.scope_metrics) != 0) |
| 551 | + for scope_metric in resource_metric.scope_metrics: |
| 552 | + self.assertTrue(len(scope_metric.metrics) != 0) |
| 553 | + for metric in scope_metric.metrics: |
| 554 | + self.assertIn(metric.name, _expected_metric_names_old) |
| 555 | + data_points = list(metric.data.data_points) |
| 556 | + self.assertEqual(len(data_points), 1) |
| 557 | + for point in data_points: |
| 558 | + if isinstance(point, HistogramDataPoint): |
| 559 | + self.assertEqual(point.count, 3) |
| 560 | + self.assertAlmostEqual( |
| 561 | + duration, point.sum, delta=10 |
| 562 | + ) |
| 563 | + histogram_data_point_seen = True |
| 564 | + if isinstance(point, NumberDataPoint): |
| 565 | + number_data_point_seen = True |
| 566 | + for attr in point.attributes: |
| 567 | + self.assertIn( |
| 568 | + attr, |
| 569 | + _recommended_metrics_attrs_old_with_custom[ |
| 570 | + metric.name |
| 571 | + ], |
| 572 | + ) |
| 573 | + self.assertTrue(number_data_point_seen and histogram_data_point_seen) |
| 574 | + |
502 | 575 | def test_flask_metrics_new_semconv(self): |
503 | 576 | start = default_timer() |
504 | 577 | self.client.get("/hello/123") |
@@ -537,6 +610,46 @@ def test_flask_metrics_new_semconv(self): |
537 | 610 | ) |
538 | 611 | self.assertTrue(number_data_point_seen and histogram_data_point_seen) |
539 | 612 |
|
| 613 | + def test_flask_metrics_custom_attributes_new_semconv(self): |
| 614 | + start = default_timer() |
| 615 | + self.client.get("/test_labeler") |
| 616 | + self.client.get("/test_labeler") |
| 617 | + self.client.get("/test_labeler") |
| 618 | + duration_s = max(default_timer() - start, 0) |
| 619 | + metrics_list = self.memory_metrics_reader.get_metrics_data() |
| 620 | + number_data_point_seen = False |
| 621 | + histogram_data_point_seen = False |
| 622 | + self.assertTrue(len(metrics_list.resource_metrics) != 0) |
| 623 | + for resource_metric in metrics_list.resource_metrics: |
| 624 | + self.assertTrue(len(resource_metric.scope_metrics) != 0) |
| 625 | + for scope_metric in resource_metric.scope_metrics: |
| 626 | + self.assertTrue(len(scope_metric.metrics) != 0) |
| 627 | + for metric in scope_metric.metrics: |
| 628 | + self.assertIn(metric.name, _expected_metric_names_new) |
| 629 | + data_points = list(metric.data.data_points) |
| 630 | + self.assertEqual(len(data_points), 1) |
| 631 | + for point in data_points: |
| 632 | + if isinstance(point, HistogramDataPoint): |
| 633 | + self.assertEqual(point.count, 3) |
| 634 | + self.assertAlmostEqual( |
| 635 | + duration_s, point.sum, places=1 |
| 636 | + ) |
| 637 | + self.assertEqual( |
| 638 | + point.explicit_bounds, |
| 639 | + HTTP_DURATION_HISTOGRAM_BUCKETS_NEW, |
| 640 | + ) |
| 641 | + histogram_data_point_seen = True |
| 642 | + if isinstance(point, NumberDataPoint): |
| 643 | + number_data_point_seen = True |
| 644 | + for attr in point.attributes: |
| 645 | + self.assertIn( |
| 646 | + attr, |
| 647 | + _recommended_metrics_attrs_new_with_custom[ |
| 648 | + metric.name |
| 649 | + ], |
| 650 | + ) |
| 651 | + self.assertTrue(number_data_point_seen and histogram_data_point_seen) |
| 652 | + |
540 | 653 | def test_flask_metric_values(self): |
541 | 654 | start = default_timer() |
542 | 655 | self.client.post("/hello/756") |
|
0 commit comments