opentelemetry-instrumentation-tornado 0.55b0__tar.gz → 0.56b0__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.
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/PKG-INFO +4 -4
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/pyproject.toml +3 -3
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/src/opentelemetry/instrumentation/tornado/__init__.py +53 -24
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/src/opentelemetry/instrumentation/tornado/client.py +12 -8
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/src/opentelemetry/instrumentation/tornado/version.py +1 -1
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/tests/test_instrumentation.py +140 -88
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/tests/tornado_test_app.py +12 -0
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/.gitignore +0 -0
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/LICENSE +0 -0
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/README.rst +0 -0
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/src/opentelemetry/instrumentation/tornado/package.py +0 -0
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/tests/__init__.py +0 -0
- {opentelemetry_instrumentation_tornado-0.55b0 → opentelemetry_instrumentation_tornado-0.56b0}/tests/test_metrics_instrumentation.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: opentelemetry-instrumentation-tornado
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.56b0
|
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
|
Project-URL: Repository, https://github.com/open-telemetry/opentelemetry-python-contrib
|
@@ -18,9 +18,9 @@ Classifier: Programming Language :: Python :: 3.12
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.13
|
19
19
|
Requires-Python: >=3.9
|
20
20
|
Requires-Dist: opentelemetry-api~=1.12
|
21
|
-
Requires-Dist: opentelemetry-instrumentation==0.
|
22
|
-
Requires-Dist: opentelemetry-semantic-conventions==0.
|
23
|
-
Requires-Dist: opentelemetry-util-http==0.
|
21
|
+
Requires-Dist: opentelemetry-instrumentation==0.56b0
|
22
|
+
Requires-Dist: opentelemetry-semantic-conventions==0.56b0
|
23
|
+
Requires-Dist: opentelemetry-util-http==0.56b0
|
24
24
|
Provides-Extra: instruments
|
25
25
|
Requires-Dist: tornado>=5.1.1; extra == 'instruments'
|
26
26
|
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.
|
29
|
-
"opentelemetry-semantic-conventions == 0.
|
30
|
-
"opentelemetry-util-http == 0.
|
28
|
+
"opentelemetry-instrumentation == 0.56b0",
|
29
|
+
"opentelemetry-semantic-conventions == 0.56b0",
|
30
|
+
"opentelemetry-util-http == 0.56b0",
|
31
31
|
]
|
32
32
|
|
33
33
|
[project.optional-dependencies]
|
@@ -162,6 +162,7 @@ from timeit import default_timer
|
|
162
162
|
from typing import Collection, Dict
|
163
163
|
|
164
164
|
import tornado.web
|
165
|
+
import tornado.websocket
|
165
166
|
import wrapt
|
166
167
|
from wrapt import wrap_function_wrapper
|
167
168
|
|
@@ -182,8 +183,19 @@ from opentelemetry.instrumentation.utils import (
|
|
182
183
|
from opentelemetry.metrics import get_meter
|
183
184
|
from opentelemetry.metrics._internal.instrument import Histogram
|
184
185
|
from opentelemetry.propagators import textmap
|
186
|
+
from opentelemetry.semconv._incubating.attributes.http_attributes import (
|
187
|
+
HTTP_CLIENT_IP,
|
188
|
+
HTTP_FLAVOR,
|
189
|
+
HTTP_HOST,
|
190
|
+
HTTP_METHOD,
|
191
|
+
HTTP_SCHEME,
|
192
|
+
HTTP_STATUS_CODE,
|
193
|
+
HTTP_TARGET,
|
194
|
+
)
|
195
|
+
from opentelemetry.semconv._incubating.attributes.net_attributes import (
|
196
|
+
NET_PEER_IP,
|
197
|
+
)
|
185
198
|
from opentelemetry.semconv.metrics import MetricInstruments
|
186
|
-
from opentelemetry.semconv.trace import SpanAttributes
|
187
199
|
from opentelemetry.trace.status import Status, StatusCode
|
188
200
|
from opentelemetry.util.http import (
|
189
201
|
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST,
|
@@ -351,12 +363,20 @@ def patch_handler_class(tracer, server_histograms, cls, request_hook=None):
|
|
351
363
|
"prepare",
|
352
364
|
partial(_prepare, tracer, server_histograms, request_hook),
|
353
365
|
)
|
354
|
-
_wrap(cls, "on_finish", partial(_on_finish, tracer, server_histograms))
|
355
366
|
_wrap(
|
356
367
|
cls,
|
357
368
|
"log_exception",
|
358
369
|
partial(_log_exception, tracer, server_histograms),
|
359
370
|
)
|
371
|
+
|
372
|
+
if issubclass(cls, tornado.websocket.WebSocketHandler):
|
373
|
+
_wrap(
|
374
|
+
cls,
|
375
|
+
"on_close",
|
376
|
+
partial(_websockethandler_on_close, tracer, server_histograms),
|
377
|
+
)
|
378
|
+
else:
|
379
|
+
_wrap(cls, "on_finish", partial(_on_finish, tracer, server_histograms))
|
360
380
|
return True
|
361
381
|
|
362
382
|
|
@@ -365,8 +385,11 @@ def unpatch_handler_class(cls):
|
|
365
385
|
return
|
366
386
|
|
367
387
|
unwrap(cls, "prepare")
|
368
|
-
unwrap(cls, "on_finish")
|
369
388
|
unwrap(cls, "log_exception")
|
389
|
+
if issubclass(cls, tornado.websocket.WebSocketHandler):
|
390
|
+
unwrap(cls, "on_close")
|
391
|
+
else:
|
392
|
+
unwrap(cls, "on_finish")
|
370
393
|
delattr(cls, _OTEL_PATCHED_KEY)
|
371
394
|
|
372
395
|
|
@@ -394,13 +417,21 @@ def _prepare(
|
|
394
417
|
|
395
418
|
|
396
419
|
def _on_finish(tracer, server_histograms, func, handler, args, kwargs):
|
397
|
-
|
398
|
-
|
399
|
-
|
420
|
+
try:
|
421
|
+
return func(*args, **kwargs)
|
422
|
+
finally:
|
423
|
+
_record_on_finish_metrics(server_histograms, handler)
|
424
|
+
_finish_span(tracer, handler)
|
400
425
|
|
401
|
-
_finish_span(tracer, handler)
|
402
426
|
|
403
|
-
|
427
|
+
def _websockethandler_on_close(
|
428
|
+
tracer, server_histograms, func, handler, args, kwargs
|
429
|
+
):
|
430
|
+
try:
|
431
|
+
func()
|
432
|
+
finally:
|
433
|
+
_record_on_finish_metrics(server_histograms, handler)
|
434
|
+
_finish_span(tracer, handler)
|
404
435
|
|
405
436
|
|
406
437
|
def _log_exception(tracer, server_histograms, func, handler, args, kwargs):
|
@@ -442,23 +473,21 @@ def _collect_custom_response_headers_attributes(response_headers):
|
|
442
473
|
|
443
474
|
def _get_attributes_from_request(request):
|
444
475
|
attrs = {
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
476
|
+
HTTP_METHOD: request.method,
|
477
|
+
HTTP_SCHEME: request.protocol,
|
478
|
+
HTTP_HOST: request.host,
|
479
|
+
HTTP_TARGET: request.path,
|
449
480
|
}
|
450
481
|
|
451
482
|
if request.remote_ip:
|
452
483
|
# NET_PEER_IP is the address of the network peer
|
453
484
|
# HTTP_CLIENT_IP is the address of the client, which might be different
|
454
485
|
# if Tornado is set to trust X-Forwarded-For headers (xheaders=True)
|
455
|
-
attrs[
|
486
|
+
attrs[HTTP_CLIENT_IP] = request.remote_ip
|
456
487
|
if hasattr(request.connection, "context") and getattr(
|
457
488
|
request.connection.context, "_orig_remote_ip", None
|
458
489
|
):
|
459
|
-
attrs[
|
460
|
-
request.connection.context._orig_remote_ip
|
461
|
-
)
|
490
|
+
attrs[NET_PEER_IP] = request.connection.context._orig_remote_ip
|
462
491
|
|
463
492
|
return extract_attributes_from_object(
|
464
493
|
request, _traced_request_attrs, attrs
|
@@ -550,7 +579,7 @@ def _finish_span(tracer, handler, error=None):
|
|
550
579
|
return
|
551
580
|
|
552
581
|
if ctx.span.is_recording():
|
553
|
-
ctx.span.set_attribute(
|
582
|
+
ctx.span.set_attribute(HTTP_STATUS_CODE, status_code)
|
554
583
|
otel_status_code = http_status_to_status_code(
|
555
584
|
status_code, server_span=True
|
556
585
|
)
|
@@ -601,7 +630,7 @@ def _record_on_finish_metrics(server_histograms, handler, error=None):
|
|
601
630
|
metric_attributes = _create_metric_attributes(handler)
|
602
631
|
|
603
632
|
if isinstance(error, tornado.web.HTTPError):
|
604
|
-
metric_attributes[
|
633
|
+
metric_attributes[HTTP_STATUS_CODE] = error.status_code
|
605
634
|
|
606
635
|
server_histograms[MetricInstruments.HTTP_SERVER_RESPONSE_SIZE].record(
|
607
636
|
response_size, attributes=metric_attributes
|
@@ -621,11 +650,11 @@ def _record_on_finish_metrics(server_histograms, handler, error=None):
|
|
621
650
|
|
622
651
|
def _create_active_requests_attributes(request):
|
623
652
|
metric_attributes = {
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
653
|
+
HTTP_METHOD: request.method,
|
654
|
+
HTTP_SCHEME: request.protocol,
|
655
|
+
HTTP_FLAVOR: request.version,
|
656
|
+
HTTP_HOST: request.host,
|
657
|
+
HTTP_TARGET: request.path,
|
629
658
|
}
|
630
659
|
|
631
660
|
return metric_attributes
|
@@ -633,6 +662,6 @@ def _create_active_requests_attributes(request):
|
|
633
662
|
|
634
663
|
def _create_metric_attributes(handler):
|
635
664
|
metric_attributes = _create_active_requests_attributes(handler.request)
|
636
|
-
metric_attributes[
|
665
|
+
metric_attributes[HTTP_STATUS_CODE] = handler.get_status()
|
637
666
|
|
638
667
|
return metric_attributes
|
@@ -20,9 +20,13 @@ from tornado.httpclient import HTTPError, HTTPRequest
|
|
20
20
|
from opentelemetry import trace
|
21
21
|
from opentelemetry.instrumentation.utils import http_status_to_status_code
|
22
22
|
from opentelemetry.propagate import inject
|
23
|
-
from opentelemetry.semconv.
|
23
|
+
from opentelemetry.semconv._incubating.attributes.http_attributes import (
|
24
|
+
HTTP_METHOD,
|
25
|
+
HTTP_STATUS_CODE,
|
26
|
+
HTTP_URL,
|
27
|
+
)
|
24
28
|
from opentelemetry.trace.status import Status, StatusCode
|
25
|
-
from opentelemetry.util.http import
|
29
|
+
from opentelemetry.util.http import redact_url
|
26
30
|
|
27
31
|
|
28
32
|
def _normalize_request(args, kwargs):
|
@@ -75,8 +79,8 @@ def fetch_async(
|
|
75
79
|
|
76
80
|
if span.is_recording():
|
77
81
|
attributes = {
|
78
|
-
|
79
|
-
|
82
|
+
HTTP_URL: redact_url(request.url),
|
83
|
+
HTTP_METHOD: request.method,
|
80
84
|
}
|
81
85
|
for key, value in attributes.items():
|
82
86
|
span.set_attribute(key, value)
|
@@ -135,7 +139,7 @@ def _finish_tracing_callback(
|
|
135
139
|
)
|
136
140
|
|
137
141
|
if status_code is not None:
|
138
|
-
span.set_attribute(
|
142
|
+
span.set_attribute(HTTP_STATUS_CODE, status_code)
|
139
143
|
span.set_status(status)
|
140
144
|
|
141
145
|
if response is not None:
|
@@ -160,9 +164,9 @@ def _finish_tracing_callback(
|
|
160
164
|
|
161
165
|
def _create_metric_attributes(response):
|
162
166
|
metric_attributes = {
|
163
|
-
|
164
|
-
|
165
|
-
|
167
|
+
HTTP_STATUS_CODE: response.code,
|
168
|
+
HTTP_URL: redact_url(response.request.url),
|
169
|
+
HTTP_METHOD: response.request.method,
|
166
170
|
}
|
167
171
|
|
168
172
|
return metric_attributes
|
@@ -13,8 +13,10 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
|
16
|
+
import asyncio
|
16
17
|
from unittest.mock import Mock, patch
|
17
18
|
|
19
|
+
import tornado.websocket
|
18
20
|
from http_server_mock import HttpServerMock
|
19
21
|
from tornado.httpclient import HTTPClientError
|
20
22
|
from tornado.testing import AsyncHTTPTestCase
|
@@ -30,7 +32,18 @@ from opentelemetry.instrumentation.tornado import (
|
|
30
32
|
patch_handler_class,
|
31
33
|
unpatch_handler_class,
|
32
34
|
)
|
33
|
-
from opentelemetry.semconv.
|
35
|
+
from opentelemetry.semconv._incubating.attributes.http_attributes import (
|
36
|
+
HTTP_CLIENT_IP,
|
37
|
+
HTTP_HOST,
|
38
|
+
HTTP_METHOD,
|
39
|
+
HTTP_SCHEME,
|
40
|
+
HTTP_STATUS_CODE,
|
41
|
+
HTTP_TARGET,
|
42
|
+
HTTP_URL,
|
43
|
+
)
|
44
|
+
from opentelemetry.semconv._incubating.attributes.net_attributes import (
|
45
|
+
NET_PEER_IP,
|
46
|
+
)
|
34
47
|
from opentelemetry.test.test_base import TestBase
|
35
48
|
from opentelemetry.test.wsgitestutil import WsgiTestBase
|
36
49
|
from opentelemetry.trace import SpanKind, StatusCode
|
@@ -146,13 +159,12 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
146
159
|
self.assertSpanHasAttributes(
|
147
160
|
server,
|
148
161
|
{
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
SpanAttributes.HTTP_STATUS_CODE: 201,
|
162
|
+
HTTP_METHOD: method,
|
163
|
+
HTTP_SCHEME: "http",
|
164
|
+
HTTP_HOST: "127.0.0.1:" + str(self.get_http_port()),
|
165
|
+
HTTP_TARGET: "/",
|
166
|
+
HTTP_CLIENT_IP: "127.0.0.1",
|
167
|
+
HTTP_STATUS_CODE: 201,
|
156
168
|
"tornado.handler": "tests.tornado_test_app.MainHandler",
|
157
169
|
},
|
158
170
|
)
|
@@ -164,9 +176,9 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
164
176
|
self.assertSpanHasAttributes(
|
165
177
|
client,
|
166
178
|
{
|
167
|
-
|
168
|
-
|
169
|
-
|
179
|
+
HTTP_URL: self.get_url("/"),
|
180
|
+
HTTP_METHOD: method,
|
181
|
+
HTTP_STATUS_CODE: 201,
|
170
182
|
},
|
171
183
|
)
|
172
184
|
|
@@ -224,13 +236,12 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
224
236
|
self.assertSpanHasAttributes(
|
225
237
|
server,
|
226
238
|
{
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
SpanAttributes.HTTP_STATUS_CODE: 201,
|
239
|
+
HTTP_METHOD: "GET",
|
240
|
+
HTTP_SCHEME: "http",
|
241
|
+
HTTP_HOST: "127.0.0.1:" + str(self.get_http_port()),
|
242
|
+
HTTP_TARGET: url,
|
243
|
+
HTTP_CLIENT_IP: "127.0.0.1",
|
244
|
+
HTTP_STATUS_CODE: 201,
|
234
245
|
"tornado.handler": f"tests.tornado_test_app.{handler_name}",
|
235
246
|
},
|
236
247
|
)
|
@@ -242,9 +253,9 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
242
253
|
self.assertSpanHasAttributes(
|
243
254
|
client,
|
244
255
|
{
|
245
|
-
|
246
|
-
|
247
|
-
|
256
|
+
HTTP_URL: self.get_url(url),
|
257
|
+
HTTP_METHOD: "GET",
|
258
|
+
HTTP_STATUS_CODE: 201,
|
248
259
|
},
|
249
260
|
)
|
250
261
|
|
@@ -263,13 +274,12 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
263
274
|
self.assertSpanHasAttributes(
|
264
275
|
server,
|
265
276
|
{
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
SpanAttributes.HTTP_STATUS_CODE: 500,
|
277
|
+
HTTP_METHOD: "GET",
|
278
|
+
HTTP_SCHEME: "http",
|
279
|
+
HTTP_HOST: "127.0.0.1:" + str(self.get_http_port()),
|
280
|
+
HTTP_TARGET: "/error",
|
281
|
+
HTTP_CLIENT_IP: "127.0.0.1",
|
282
|
+
HTTP_STATUS_CODE: 500,
|
273
283
|
"tornado.handler": "tests.tornado_test_app.BadHandler",
|
274
284
|
},
|
275
285
|
)
|
@@ -279,9 +289,9 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
279
289
|
self.assertSpanHasAttributes(
|
280
290
|
client,
|
281
291
|
{
|
282
|
-
|
283
|
-
|
284
|
-
|
292
|
+
HTTP_URL: self.get_url("/error"),
|
293
|
+
HTTP_METHOD: "GET",
|
294
|
+
HTTP_STATUS_CODE: 500,
|
285
295
|
},
|
286
296
|
)
|
287
297
|
|
@@ -298,13 +308,12 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
298
308
|
self.assertSpanHasAttributes(
|
299
309
|
server,
|
300
310
|
{
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
SpanAttributes.HTTP_STATUS_CODE: 404,
|
311
|
+
HTTP_METHOD: "GET",
|
312
|
+
HTTP_SCHEME: "http",
|
313
|
+
HTTP_HOST: "127.0.0.1:" + str(self.get_http_port()),
|
314
|
+
HTTP_TARGET: "/missing-url",
|
315
|
+
HTTP_CLIENT_IP: "127.0.0.1",
|
316
|
+
HTTP_STATUS_CODE: 404,
|
308
317
|
"tornado.handler": "tornado.web.ErrorHandler",
|
309
318
|
},
|
310
319
|
)
|
@@ -314,9 +323,9 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
314
323
|
self.assertSpanHasAttributes(
|
315
324
|
client,
|
316
325
|
{
|
317
|
-
|
318
|
-
|
319
|
-
|
326
|
+
HTTP_URL: self.get_url("/missing-url"),
|
327
|
+
HTTP_METHOD: "GET",
|
328
|
+
HTTP_STATUS_CODE: 404,
|
320
329
|
},
|
321
330
|
)
|
322
331
|
|
@@ -333,13 +342,12 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
333
342
|
self.assertSpanHasAttributes(
|
334
343
|
server,
|
335
344
|
{
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
SpanAttributes.HTTP_STATUS_CODE: 403,
|
345
|
+
HTTP_METHOD: "GET",
|
346
|
+
HTTP_SCHEME: "http",
|
347
|
+
HTTP_HOST: "127.0.0.1:" + str(self.get_http_port()),
|
348
|
+
HTTP_TARGET: "/raise_403",
|
349
|
+
HTTP_CLIENT_IP: "127.0.0.1",
|
350
|
+
HTTP_STATUS_CODE: 403,
|
343
351
|
"tornado.handler": "tests.tornado_test_app.RaiseHTTPErrorHandler",
|
344
352
|
},
|
345
353
|
)
|
@@ -349,9 +357,9 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
349
357
|
self.assertSpanHasAttributes(
|
350
358
|
client,
|
351
359
|
{
|
352
|
-
|
353
|
-
|
354
|
-
|
360
|
+
HTTP_URL: self.get_url("/raise_403"),
|
361
|
+
HTTP_METHOD: "GET",
|
362
|
+
HTTP_STATUS_CODE: 403,
|
355
363
|
},
|
356
364
|
)
|
357
365
|
|
@@ -378,13 +386,12 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
378
386
|
self.assertSpanHasAttributes(
|
379
387
|
server,
|
380
388
|
{
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
SpanAttributes.HTTP_STATUS_CODE: 202,
|
389
|
+
HTTP_METHOD: "GET",
|
390
|
+
HTTP_SCHEME: "http",
|
391
|
+
HTTP_HOST: "127.0.0.1:" + str(self.get_http_port()),
|
392
|
+
HTTP_TARGET: "/dyna",
|
393
|
+
HTTP_CLIENT_IP: "127.0.0.1",
|
394
|
+
HTTP_STATUS_CODE: 202,
|
388
395
|
"tornado.handler": "tests.tornado_test_app.DynamicHandler",
|
389
396
|
},
|
390
397
|
)
|
@@ -396,9 +403,9 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
396
403
|
self.assertSpanHasAttributes(
|
397
404
|
client,
|
398
405
|
{
|
399
|
-
|
400
|
-
|
401
|
-
|
406
|
+
HTTP_URL: self.get_url("/dyna"),
|
407
|
+
HTTP_METHOD: "GET",
|
408
|
+
HTTP_STATUS_CODE: 202,
|
402
409
|
},
|
403
410
|
)
|
404
411
|
|
@@ -419,13 +426,12 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
419
426
|
self.assertSpanHasAttributes(
|
420
427
|
server,
|
421
428
|
{
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
SpanAttributes.HTTP_STATUS_CODE: 200,
|
429
|
+
HTTP_METHOD: "GET",
|
430
|
+
HTTP_SCHEME: "http",
|
431
|
+
HTTP_HOST: "127.0.0.1:" + str(self.get_http_port()),
|
432
|
+
HTTP_TARGET: "/on_finish",
|
433
|
+
HTTP_CLIENT_IP: "127.0.0.1",
|
434
|
+
HTTP_STATUS_CODE: 200,
|
429
435
|
"tornado.handler": "tests.tornado_test_app.FinishedHandler",
|
430
436
|
},
|
431
437
|
)
|
@@ -437,9 +443,9 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
437
443
|
self.assertSpanHasAttributes(
|
438
444
|
client,
|
439
445
|
{
|
440
|
-
|
441
|
-
|
442
|
-
|
446
|
+
HTTP_URL: self.get_url("/on_finish"),
|
447
|
+
HTTP_METHOD: "GET",
|
448
|
+
HTTP_STATUS_CODE: 200,
|
443
449
|
},
|
444
450
|
)
|
445
451
|
|
@@ -450,6 +456,53 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
450
456
|
|
451
457
|
self.assertEqual(auditor.kind, SpanKind.INTERNAL)
|
452
458
|
|
459
|
+
@tornado.testing.gen_test()
|
460
|
+
async def test_websockethandler(self):
|
461
|
+
ws_client = await tornado.websocket.websocket_connect(
|
462
|
+
f"ws://127.0.0.1:{self.get_http_port()}/echo_socket"
|
463
|
+
)
|
464
|
+
|
465
|
+
await ws_client.write_message("world")
|
466
|
+
resp = await ws_client.read_message()
|
467
|
+
self.assertEqual(resp, "hello world")
|
468
|
+
|
469
|
+
ws_client.close()
|
470
|
+
await asyncio.sleep(0.5)
|
471
|
+
|
472
|
+
spans = self.sorted_spans(self.memory_exporter.get_finished_spans())
|
473
|
+
self.assertEqual(len(spans), 3)
|
474
|
+
close_span, msg_span, req_span = spans
|
475
|
+
|
476
|
+
self.assertEqual(req_span.name, "GET /echo_socket")
|
477
|
+
self.assertEqual(req_span.context.trace_id, msg_span.context.trace_id)
|
478
|
+
self.assertIsNone(req_span.parent)
|
479
|
+
self.assertEqual(req_span.kind, SpanKind.SERVER)
|
480
|
+
self.assertSpanHasAttributes(
|
481
|
+
req_span,
|
482
|
+
{
|
483
|
+
HTTP_METHOD: "GET",
|
484
|
+
HTTP_SCHEME: "http",
|
485
|
+
HTTP_HOST: f"127.0.0.1:{self.get_http_port()}",
|
486
|
+
HTTP_TARGET: "/echo_socket",
|
487
|
+
HTTP_CLIENT_IP: "127.0.0.1",
|
488
|
+
HTTP_STATUS_CODE: 101,
|
489
|
+
"tornado.handler": "tests.tornado_test_app.EchoWebSocketHandler",
|
490
|
+
},
|
491
|
+
)
|
492
|
+
|
493
|
+
self.assertEqual(msg_span.name, "audit_message")
|
494
|
+
self.assertFalse(msg_span.context.is_remote)
|
495
|
+
self.assertEqual(msg_span.kind, SpanKind.INTERNAL)
|
496
|
+
self.assertEqual(msg_span.parent.span_id, req_span.context.span_id)
|
497
|
+
|
498
|
+
self.assertEqual(close_span.name, "audit_on_close")
|
499
|
+
self.assertFalse(close_span.context.is_remote)
|
500
|
+
self.assertEqual(close_span.parent.span_id, req_span.context.span_id)
|
501
|
+
self.assertEqual(
|
502
|
+
close_span.context.trace_id, msg_span.context.trace_id
|
503
|
+
)
|
504
|
+
self.assertEqual(close_span.kind, SpanKind.INTERNAL)
|
505
|
+
|
453
506
|
def test_exclude_lists(self):
|
454
507
|
def test_excluded(path):
|
455
508
|
self.fetch(path)
|
@@ -463,9 +516,9 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
463
516
|
self.assertSpanHasAttributes(
|
464
517
|
client,
|
465
518
|
{
|
466
|
-
|
467
|
-
|
468
|
-
|
519
|
+
HTTP_URL: self.get_url(path),
|
520
|
+
HTTP_METHOD: "GET",
|
521
|
+
HTTP_STATUS_CODE: 200,
|
469
522
|
},
|
470
523
|
)
|
471
524
|
self.memory_exporter.clear()
|
@@ -496,8 +549,8 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
496
549
|
|
497
550
|
set_global_response_propagator(orig)
|
498
551
|
|
499
|
-
def
|
500
|
-
app = HttpServerMock("
|
552
|
+
def test_remove_sensitive_params(self):
|
553
|
+
app = HttpServerMock("test_remove_sensitive_params")
|
501
554
|
|
502
555
|
@app.route("/status/200")
|
503
556
|
def index():
|
@@ -505,7 +558,7 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
505
558
|
|
506
559
|
with app.run("localhost", 5000):
|
507
560
|
response = self.fetch(
|
508
|
-
"http://username:password@localhost:5000/status/200"
|
561
|
+
"http://username:password@localhost:5000/status/200?Signature=secret"
|
509
562
|
)
|
510
563
|
self.assertEqual(response.code, 200)
|
511
564
|
|
@@ -518,9 +571,9 @@ class TestTornadoInstrumentation(TornadoTest, WsgiTestBase):
|
|
518
571
|
self.assertSpanHasAttributes(
|
519
572
|
client,
|
520
573
|
{
|
521
|
-
|
522
|
-
|
523
|
-
|
574
|
+
HTTP_URL: "http://REDACTED:REDACTED@localhost:5000/status/200?Signature=REDACTED",
|
575
|
+
HTTP_METHOD: "GET",
|
576
|
+
HTTP_STATUS_CODE: 200,
|
524
577
|
},
|
525
578
|
)
|
526
579
|
|
@@ -538,14 +591,13 @@ class TestTornadoInstrumentationWithXHeaders(TornadoTest):
|
|
538
591
|
self.assertSpanHasAttributes(
|
539
592
|
spans.by_name("GET /"),
|
540
593
|
{
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
SpanAttributes.NET_PEER_IP: "127.0.0.1",
|
594
|
+
HTTP_METHOD: "GET",
|
595
|
+
HTTP_SCHEME: "http",
|
596
|
+
HTTP_HOST: "127.0.0.1:" + str(self.get_http_port()),
|
597
|
+
HTTP_TARGET: "/",
|
598
|
+
HTTP_CLIENT_IP: "12.34.56.78",
|
599
|
+
HTTP_STATUS_CODE: 201,
|
600
|
+
NET_PEER_IP: "127.0.0.1",
|
549
601
|
"tornado.handler": "tests.tornado_test_app.MainHandler",
|
550
602
|
},
|
551
603
|
)
|
@@ -2,6 +2,7 @@
|
|
2
2
|
import time
|
3
3
|
|
4
4
|
import tornado.web
|
5
|
+
import tornado.websocket
|
5
6
|
from tornado import gen
|
6
7
|
|
7
8
|
|
@@ -110,6 +111,16 @@ class RaiseHTTPErrorHandler(tornado.web.RequestHandler):
|
|
110
111
|
raise tornado.web.HTTPError(403)
|
111
112
|
|
112
113
|
|
114
|
+
class EchoWebSocketHandler(tornado.websocket.WebSocketHandler):
|
115
|
+
async def on_message(self, message):
|
116
|
+
with self.application.tracer.start_as_current_span("audit_message"):
|
117
|
+
self.write_message(f"hello {message}")
|
118
|
+
|
119
|
+
def on_close(self):
|
120
|
+
with self.application.tracer.start_as_current_span("audit_on_close"):
|
121
|
+
time.sleep(0.05)
|
122
|
+
|
123
|
+
|
113
124
|
def make_app(tracer):
|
114
125
|
app = tornado.web.Application(
|
115
126
|
[
|
@@ -122,6 +133,7 @@ def make_app(tracer):
|
|
122
133
|
(r"/ping", HealthCheckHandler),
|
123
134
|
(r"/test_custom_response_headers", CustomResponseHeaderHandler),
|
124
135
|
(r"/raise_403", RaiseHTTPErrorHandler),
|
136
|
+
(r"/echo_socket", EchoWebSocketHandler),
|
125
137
|
]
|
126
138
|
)
|
127
139
|
app.tracer = tracer
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|