opentelemetry-instrumentation-tornado 0.47b0__tar.gz → 0.49b0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (13) hide show
  1. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/PKG-INFO +4 -4
  2. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/pyproject.toml +3 -3
  3. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/src/opentelemetry/instrumentation/tornado/__init__.py +1 -2
  4. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/src/opentelemetry/instrumentation/tornado/client.py +36 -20
  5. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/src/opentelemetry/instrumentation/tornado/version.py +1 -1
  6. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/tests/test_instrumentation.py +45 -2
  7. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/.gitignore +0 -0
  8. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/LICENSE +0 -0
  9. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/README.rst +0 -0
  10. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/src/opentelemetry/instrumentation/tornado/package.py +0 -0
  11. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/tests/__init__.py +0 -0
  12. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/tests/test_metrics_instrumentation.py +0 -0
  13. {opentelemetry_instrumentation_tornado-0.47b0 → opentelemetry_instrumentation_tornado-0.49b0}/tests/tornado_test_app.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: opentelemetry-instrumentation-tornado
3
- Version: 0.47b0
3
+ Version: 0.49b0
4
4
  Summary: Tornado instrumentation for OpenTelemetry
5
5
  Project-URL: Homepage, https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-tornado
6
6
  Author-email: OpenTelemetry Authors <cncf-opentelemetry-contributors@lists.cncf.io>
@@ -17,9 +17,9 @@ Classifier: Programming Language :: Python :: 3.11
17
17
  Classifier: Programming Language :: Python :: 3.12
18
18
  Requires-Python: >=3.8
19
19
  Requires-Dist: opentelemetry-api~=1.12
20
- Requires-Dist: opentelemetry-instrumentation==0.47b0
21
- Requires-Dist: opentelemetry-semantic-conventions==0.47b0
22
- Requires-Dist: opentelemetry-util-http==0.47b0
20
+ Requires-Dist: opentelemetry-instrumentation==0.49b0
21
+ Requires-Dist: opentelemetry-semantic-conventions==0.49b0
22
+ Requires-Dist: opentelemetry-util-http==0.49b0
23
23
  Provides-Extra: instruments
24
24
  Requires-Dist: tornado>=5.1.1; extra == 'instruments'
25
25
  Description-Content-Type: text/x-rst
@@ -25,9 +25,9 @@ classifiers = [
25
25
  ]
26
26
  dependencies = [
27
27
  "opentelemetry-api ~= 1.12",
28
- "opentelemetry-instrumentation == 0.47b0",
29
- "opentelemetry-semantic-conventions == 0.47b0",
30
- "opentelemetry-util-http == 0.47b0",
28
+ "opentelemetry-instrumentation == 0.49b0",
29
+ "opentelemetry-semantic-conventions == 0.49b0",
30
+ "opentelemetry-util-http == 0.49b0",
31
31
  ]
32
32
 
33
33
  [project.optional-dependencies]
@@ -152,7 +152,6 @@ API
152
152
  ---
153
153
  """
154
154
 
155
-
156
155
  from collections import namedtuple
157
156
  from functools import partial
158
157
  from logging import getLogger
@@ -296,7 +295,7 @@ def _create_server_histograms(meter) -> Dict[str, Histogram]:
296
295
  MetricInstruments.HTTP_SERVER_DURATION: meter.create_histogram(
297
296
  name=MetricInstruments.HTTP_SERVER_DURATION,
298
297
  unit="ms",
299
- description="Duration of HTTP server requests.",
298
+ description="Measures the duration of inbound HTTP requests.",
300
299
  ),
301
300
  MetricInstruments.HTTP_SERVER_REQUEST_SIZE: meter.create_histogram(
302
301
  name=MetricInstruments.HTTP_SERVER_REQUEST_SIZE,
@@ -21,7 +21,7 @@ from opentelemetry import trace
21
21
  from opentelemetry.instrumentation.utils import http_status_to_status_code
22
22
  from opentelemetry.propagate import inject
23
23
  from opentelemetry.semconv.trace import SpanAttributes
24
- from opentelemetry.trace.status import Status
24
+ from opentelemetry.trace.status import Status, StatusCode
25
25
  from opentelemetry.util.http import remove_url_credentials
26
26
 
27
27
 
@@ -105,37 +105,53 @@ def _finish_tracing_callback(
105
105
  request_size_histogram,
106
106
  response_size_histogram,
107
107
  ):
108
+ response = None
108
109
  status_code = None
110
+ status = None
109
111
  description = None
110
- exc = future.exception()
111
-
112
- response = future.result()
113
112
 
114
- if span.is_recording() and exc:
113
+ exc = future.exception()
114
+ if exc:
115
+ description = f"{type(exc).__qualname__}: {exc}"
115
116
  if isinstance(exc, HTTPError):
117
+ response = exc.response
116
118
  status_code = exc.code
117
- description = f"{type(exc).__name__}: {exc}"
119
+ status = Status(
120
+ status_code=http_status_to_status_code(status_code),
121
+ description=description,
122
+ )
123
+ else:
124
+ status = Status(
125
+ status_code=StatusCode.ERROR,
126
+ description=description,
127
+ )
128
+ span.record_exception(exc)
118
129
  else:
130
+ response = future.result()
119
131
  status_code = response.code
132
+ status = Status(
133
+ status_code=http_status_to_status_code(status_code),
134
+ description=description,
135
+ )
120
136
 
121
137
  if status_code is not None:
122
138
  span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code)
123
- span.set_status(
124
- Status(
125
- status_code=http_status_to_status_code(status_code),
126
- description=description,
127
- )
128
- )
139
+ span.set_status(status)
129
140
 
130
- metric_attributes = _create_metric_attributes(response)
131
- request_size = int(response.request.headers.get("Content-Length", 0))
132
- response_size = int(response.headers.get("Content-Length", 0))
141
+ if response is not None:
142
+ metric_attributes = _create_metric_attributes(response)
143
+ request_size = int(response.request.headers.get("Content-Length", 0))
144
+ response_size = int(response.headers.get("Content-Length", 0))
133
145
 
134
- duration_histogram.record(
135
- response.request_time, attributes=metric_attributes
136
- )
137
- request_size_histogram.record(request_size, attributes=metric_attributes)
138
- response_size_histogram.record(response_size, attributes=metric_attributes)
146
+ duration_histogram.record(
147
+ response.request_time, attributes=metric_attributes
148
+ )
149
+ request_size_histogram.record(
150
+ request_size, attributes=metric_attributes
151
+ )
152
+ response_size_histogram.record(
153
+ response_size, attributes=metric_attributes
154
+ )
139
155
 
140
156
  if response_hook:
141
157
  response_hook(span, future)
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = "0.47b0"
15
+ __version__ = "0.49b0"
@@ -16,6 +16,7 @@
16
16
  from unittest.mock import Mock, patch
17
17
 
18
18
  from http_server_mock import HttpServerMock
19
+ from tornado.httpclient import HTTPClientError
19
20
  from tornado.testing import AsyncHTTPTestCase
20
21
 
21
22
  from opentelemetry import trace
@@ -32,7 +33,7 @@ from opentelemetry.instrumentation.tornado import (
32
33
  from opentelemetry.semconv.trace import SpanAttributes
33
34
  from opentelemetry.test.test_base import TestBase
34
35
  from opentelemetry.test.wsgitestutil import WsgiTestBase
35
- from opentelemetry.trace import SpanKind
36
+ from opentelemetry.trace import SpanKind, StatusCode
36
37
  from opentelemetry.util.http import (
37
38
  OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST,
38
39
  OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE,
@@ -493,7 +494,6 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
493
494
  self.assertEqual(len(spans), 3)
494
495
  self.assertTraceResponseHeaderMatchesSpan(response.headers, spans[1])
495
496
 
496
- self.memory_exporter.clear()
497
497
  set_global_response_propagator(orig)
498
498
 
499
499
  def test_credential_removal(self):
@@ -602,6 +602,49 @@ class TornadoHookTest(TornadoTest):
602
602
  self.memory_exporter.clear()
603
603
 
604
604
 
605
+ class TestTornadoHTTPClientInstrumentation(TornadoTest, WsgiTestBase):
606
+ def test_http_client_success_response(self):
607
+ response = self.fetch("/")
608
+ self.assertEqual(response.code, 201)
609
+
610
+ spans = self.memory_exporter.get_finished_spans()
611
+ self.assertEqual(len(spans), 3)
612
+ manual, server, client = self.sorted_spans(spans)
613
+ self.assertEqual(manual.name, "manual")
614
+ self.assertEqual(server.name, "GET /")
615
+ self.assertEqual(client.name, "GET")
616
+ self.assertEqual(client.status.status_code, StatusCode.UNSET)
617
+ self.memory_exporter.clear()
618
+
619
+ def test_http_client_failed_response(self):
620
+ # when an exception isn't thrown
621
+ response = self.fetch("/some-404")
622
+ self.assertEqual(response.code, 404)
623
+
624
+ spans = self.memory_exporter.get_finished_spans()
625
+ self.assertEqual(len(spans), 2)
626
+ server, client = self.sorted_spans(spans)
627
+ self.assertEqual(server.name, "GET /some-404")
628
+ self.assertEqual(client.name, "GET")
629
+ self.assertEqual(client.status.status_code, StatusCode.ERROR)
630
+ self.memory_exporter.clear()
631
+
632
+ # when an exception is thrown
633
+ try:
634
+ response = self.fetch("/some-404", raise_error=True)
635
+ self.assertEqual(response.code, 404)
636
+ except HTTPClientError:
637
+ pass # expected exception - continue
638
+
639
+ spans = self.memory_exporter.get_finished_spans()
640
+ self.assertEqual(len(spans), 2)
641
+ server, client = self.sorted_spans(spans)
642
+ self.assertEqual(server.name, "GET /some-404")
643
+ self.assertEqual(client.name, "GET")
644
+ self.assertEqual(client.status.status_code, StatusCode.ERROR)
645
+ self.memory_exporter.clear()
646
+
647
+
605
648
  class TestTornadoUninstrument(TornadoTest):
606
649
  def test_uninstrument(self):
607
650
  response = self.fetch("/")