tusk-drift-python-sdk 0.1.22__tar.gz → 0.1.23__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.
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/PKG-INFO +9 -9
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/README.md +5 -5
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/drift_sdk.py +41 -16
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/mode_utils.py +3 -1
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/rust_core_binding.py +18 -7
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/otel_converter.py +3 -6
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/e2e-tests/src/app.py +23 -0
- tusk_drift_python_sdk-0.1.23/drift/instrumentation/django/e2e-tests/src/views.py +216 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/instrumentation.py +43 -5
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/middleware.py +3 -0
- tusk_drift_python_sdk-0.1.23/drift/instrumentation/e2e_common/external_http.py +55 -0
- tusk_drift_python_sdk-0.1.23/drift/instrumentation/e2e_common/mock_upstream/mock_server.py +348 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/e2e-tests/src/app.py +31 -11
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/instrumentation.py +3 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/e2e-tests/src/app.py +39 -9
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/greeter_pb2_grpc.py +1 -1
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/e2e-tests/src/app.py +40 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/e2e-tests/src/app.py +30 -8
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/instrumentation.py +3 -1
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/e2e-tests/src/app.py +64 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/e2e-tests/src/test_requests.py +3 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/instrumentation.py +2 -1
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/e2e-tests/src/app.py +25 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/socket/instrumentation.py +18 -3
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/e2e-tests/src/app.py +25 -2
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/instrumentation.py +11 -7
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/e2e-tests/src/app.py +147 -22
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/e2e-tests/src/test_requests.py +22 -11
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/instrumentation.py +207 -90
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/utils/psycopg_utils.py +63 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/utils/serialization.py +11 -1
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/handler.py +3 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/pyproject.toml +6 -4
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/PKG-INFO +9 -9
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/SOURCES.txt +2 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/requires.txt +3 -3
- tusk_drift_python_sdk-0.1.22/drift/instrumentation/django/e2e-tests/src/views.py +0 -153
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/LICENSE +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/batch_processor.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/communication/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/communication/communicator.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/communication/types.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/config.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/content_type_utils.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/data_normalization.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/json_schema_helper.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/logger.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/metrics.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/mock_utils.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/protobuf_utils.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/resilience.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/sampling.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/span_serialization.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/trace_blocking_manager.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/api.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/base.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/filesystem.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/memory.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/span_exporter.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/span_utils.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/td_attributes.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/td_span_processor.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/types.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/base.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/datetime/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/datetime/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/src/app.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/src/settings.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/src/urls.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/html_utils.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/e2e_common/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/e2e_common/base_runner.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/e2e_common/test_utils.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/app.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/greeter_pb2.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/grpc_server.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/types.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/utils.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/http/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/http/transform_engine.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/kinde/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/kinde/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/mocks.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/wrappers.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/pyjwt/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/pyjwt/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/e2e-tests/src/app.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/registry.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/socket/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/context.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/e2e-tests/src/app.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/e2e-tests/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/e2e-tests/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/__init__.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/instrumentation.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/response_capture.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/utilities.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/app.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/settings.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/urls.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/views.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/app.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/settings.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/urls.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/views.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-postgres/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-postgres/src/app.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-postgres/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-sqlalchemy/entrypoint.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-sqlalchemy/src/app.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-sqlalchemy/src/test_requests.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/version.py +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/setup.cfg +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/dependency_links.txt +0 -0
- {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tusk-drift-python-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.23
|
|
4
4
|
Summary: Python SDK for Tusk Drift instrumentation and replay
|
|
5
5
|
Author-email: Tusk <support@usetusk.ai>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -23,9 +23,9 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
23
23
|
Requires-Python: >=3.9
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
|
-
Requires-Dist: protobuf>=
|
|
26
|
+
Requires-Dist: protobuf>=3.20.0
|
|
27
27
|
Requires-Dist: PyYAML>=6.0
|
|
28
|
-
Requires-Dist: requests>=2.
|
|
28
|
+
Requires-Dist: requests>=2.28.0
|
|
29
29
|
Requires-Dist: tusk-drift-schemas>=0.1.24
|
|
30
30
|
Requires-Dist: aiohttp>=3.9.0
|
|
31
31
|
Requires-Dist: aiofiles>=23.0.0
|
|
@@ -42,7 +42,7 @@ Requires-Dist: starlette<0.42.0; extra == "fastapi"
|
|
|
42
42
|
Provides-Extra: django
|
|
43
43
|
Requires-Dist: Django>=4.2; extra == "django"
|
|
44
44
|
Provides-Extra: rust
|
|
45
|
-
Requires-Dist: drift-core-python>=0.1.
|
|
45
|
+
Requires-Dist: drift-core-python>=0.1.9; extra == "rust"
|
|
46
46
|
Provides-Extra: dev
|
|
47
47
|
Requires-Dist: Flask>=3.1.2; extra == "dev"
|
|
48
48
|
Requires-Dist: fastapi>=0.115.6; extra == "dev"
|
|
@@ -61,13 +61,13 @@ Dynamic: license-file
|
|
|
61
61
|
|
|
62
62
|
<p align="center">
|
|
63
63
|
<a href="https://pypi.org/project/tusk-drift-python-sdk/"><img src="https://img.shields.io/pypi/v/tusk-drift-python-sdk" alt="PyPI version"></a>
|
|
64
|
+
<a href="https://pypi.org/project/tusk-drift-python-sdk/"><img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/tusk-drift-python-sdk"></a>
|
|
64
65
|
<a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache 2.0"></a>
|
|
65
|
-
<a href="https://github.com/Use-Tusk/drift-python-sdk/commits/main/"><img src="https://img.shields.io/github/last-commit/Use-Tusk/drift-python-sdk" alt="GitHub last commit"></a>
|
|
66
66
|
<a href="https://x.com/usetusk"><img src="https://img.shields.io/twitter/url?url=https%3A%2F%2Fx.com%2Fusetusk&style=flat&logo=x&label=Tusk&color=BF40BF" alt="Tusk X account"></a>
|
|
67
67
|
<a href="https://join.slack.com/t/tusk-community/shared_invite/zt-3fve1s7ie-NAAUn~UpHsf1m_2tdoGjsQ"><img src="https://img.shields.io/badge/slack-badge?style=flat&logo=slack&label=Tusk&color=BF40BF" alt="Tusk Community Slack"></a>
|
|
68
68
|
</p>
|
|
69
69
|
|
|
70
|
-
The Python Tusk Drift SDK enables fast and deterministic API testing by capturing and replaying API calls made to/from your service. Automatically record real-world API calls, then replay them as tests using the [Tusk CLI](https://github.com/Use-Tusk/tusk-
|
|
70
|
+
The Python Tusk Drift SDK enables fast and deterministic API testing by capturing and replaying API calls made to/from your service. Automatically record real-world API calls, then replay them as tests using the [Tusk CLI](https://github.com/Use-Tusk/tusk-cli) to find regressions. During replay, all outbound requests are intercepted with recorded data to ensure consistent behavior without side-effects.
|
|
71
71
|
|
|
72
72
|
<div align="center">
|
|
73
73
|
|
|
@@ -124,7 +124,7 @@ If you're using packages or versions not listed above, please create an issue wi
|
|
|
124
124
|
|
|
125
125
|
### Step 1: Install the CLI
|
|
126
126
|
|
|
127
|
-
First, install the Tusk Drift CLI by following our [CLI installation guide](https://github.com/Use-Tusk/tusk-
|
|
127
|
+
First, install the Tusk Drift CLI by following our [CLI installation guide](https://github.com/Use-Tusk/tusk-cli?tab=readme-ov-file#install).
|
|
128
128
|
|
|
129
129
|
### Step 2: Set up Tusk Drift
|
|
130
130
|
|
|
@@ -135,7 +135,7 @@ Use our AI agent to automatically set up Tusk Drift for your service:
|
|
|
135
135
|
```bash
|
|
136
136
|
cd path/to/your/service
|
|
137
137
|
export ANTHROPIC_API_KEY=your-api-key
|
|
138
|
-
tusk setup
|
|
138
|
+
tusk drift setup
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
The agent will analyze your codebase, install the SDK, instrument it into your application, create configuration files, and test the setup with recording and replay.
|
|
@@ -156,7 +156,7 @@ Alternatively, you can set up Tusk Drift manually:
|
|
|
156
156
|
|
|
157
157
|
*For more information about Rust acceleration, refer to [this doc](docs/rust-core-bindings).*
|
|
158
158
|
|
|
159
|
-
2. Create configuration: Run `tusk init` to create your `.tusk/config.yaml` config file interactively, or create it manually per the [configuration docs](https://github.com/Use-Tusk/tusk-
|
|
159
|
+
2. Create configuration: Run `tusk init` to create your `.tusk/config.yaml` config file interactively, or create it manually per the [configuration docs](https://github.com/Use-Tusk/tusk-cli/blob/main/docs/drift/configuration.md).
|
|
160
160
|
|
|
161
161
|
3. Initialize the SDK: Refer to the [initialization guide](docs/initialization.md) to instrument the SDK in your service.
|
|
162
162
|
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<a href="https://pypi.org/project/tusk-drift-python-sdk/"><img src="https://img.shields.io/pypi/v/tusk-drift-python-sdk" alt="PyPI version"></a>
|
|
7
|
+
<a href="https://pypi.org/project/tusk-drift-python-sdk/"><img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/tusk-drift-python-sdk"></a>
|
|
7
8
|
<a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache 2.0"></a>
|
|
8
|
-
<a href="https://github.com/Use-Tusk/drift-python-sdk/commits/main/"><img src="https://img.shields.io/github/last-commit/Use-Tusk/drift-python-sdk" alt="GitHub last commit"></a>
|
|
9
9
|
<a href="https://x.com/usetusk"><img src="https://img.shields.io/twitter/url?url=https%3A%2F%2Fx.com%2Fusetusk&style=flat&logo=x&label=Tusk&color=BF40BF" alt="Tusk X account"></a>
|
|
10
10
|
<a href="https://join.slack.com/t/tusk-community/shared_invite/zt-3fve1s7ie-NAAUn~UpHsf1m_2tdoGjsQ"><img src="https://img.shields.io/badge/slack-badge?style=flat&logo=slack&label=Tusk&color=BF40BF" alt="Tusk Community Slack"></a>
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
|
-
The Python Tusk Drift SDK enables fast and deterministic API testing by capturing and replaying API calls made to/from your service. Automatically record real-world API calls, then replay them as tests using the [Tusk CLI](https://github.com/Use-Tusk/tusk-
|
|
13
|
+
The Python Tusk Drift SDK enables fast and deterministic API testing by capturing and replaying API calls made to/from your service. Automatically record real-world API calls, then replay them as tests using the [Tusk CLI](https://github.com/Use-Tusk/tusk-cli) to find regressions. During replay, all outbound requests are intercepted with recorded data to ensure consistent behavior without side-effects.
|
|
14
14
|
|
|
15
15
|
<div align="center">
|
|
16
16
|
|
|
@@ -67,7 +67,7 @@ If you're using packages or versions not listed above, please create an issue wi
|
|
|
67
67
|
|
|
68
68
|
### Step 1: Install the CLI
|
|
69
69
|
|
|
70
|
-
First, install the Tusk Drift CLI by following our [CLI installation guide](https://github.com/Use-Tusk/tusk-
|
|
70
|
+
First, install the Tusk Drift CLI by following our [CLI installation guide](https://github.com/Use-Tusk/tusk-cli?tab=readme-ov-file#install).
|
|
71
71
|
|
|
72
72
|
### Step 2: Set up Tusk Drift
|
|
73
73
|
|
|
@@ -78,7 +78,7 @@ Use our AI agent to automatically set up Tusk Drift for your service:
|
|
|
78
78
|
```bash
|
|
79
79
|
cd path/to/your/service
|
|
80
80
|
export ANTHROPIC_API_KEY=your-api-key
|
|
81
|
-
tusk setup
|
|
81
|
+
tusk drift setup
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
The agent will analyze your codebase, install the SDK, instrument it into your application, create configuration files, and test the setup with recording and replay.
|
|
@@ -99,7 +99,7 @@ Alternatively, you can set up Tusk Drift manually:
|
|
|
99
99
|
|
|
100
100
|
*For more information about Rust acceleration, refer to [this doc](docs/rust-core-bindings).*
|
|
101
101
|
|
|
102
|
-
2. Create configuration: Run `tusk init` to create your `.tusk/config.yaml` config file interactively, or create it manually per the [configuration docs](https://github.com/Use-Tusk/tusk-
|
|
102
|
+
2. Create configuration: Run `tusk init` to create your `.tusk/config.yaml` config file interactively, or create it manually per the [configuration docs](https://github.com/Use-Tusk/tusk-cli/blob/main/docs/drift/configuration.md).
|
|
103
103
|
|
|
104
104
|
3. Initialize the SDK: Refer to the [initialization guide](docs/initialization.md) to instrument the SDK in your service.
|
|
105
105
|
|
|
@@ -5,6 +5,7 @@ import atexit
|
|
|
5
5
|
import json
|
|
6
6
|
import logging
|
|
7
7
|
import os
|
|
8
|
+
import platform
|
|
8
9
|
import random
|
|
9
10
|
import stat
|
|
10
11
|
import time
|
|
@@ -17,10 +18,11 @@ from opentelemetry.sdk.trace import TracerProvider
|
|
|
17
18
|
from opentelemetry.trace import SpanKind as OTelSpanKind
|
|
18
19
|
|
|
19
20
|
from ..instrumentation.registry import install_hooks
|
|
21
|
+
from ..version import SDK_VERSION
|
|
20
22
|
from .communication.communicator import CommunicatorConfig, ProtobufCommunicator
|
|
21
23
|
from .communication.types import MockRequestInput, MockResponseOutput
|
|
22
24
|
from .config import TuskConfig, TuskFileConfig, load_tusk_config
|
|
23
|
-
from .logger import LogLevel, configure_logger
|
|
25
|
+
from .logger import LogLevel, configure_logger, get_log_level
|
|
24
26
|
from .sampling import should_sample, validate_sampling_rate
|
|
25
27
|
from .trace_blocking_manager import TraceBlockingManager, should_block_span
|
|
26
28
|
from .tracing import TdSpanAttributes, TdSpanExporter, TdSpanExporterConfig
|
|
@@ -99,13 +101,40 @@ class TuskDrift:
|
|
|
99
101
|
logger.info("Rust core path enabled at startup (env=%s, reason=%s).", env_display, status["reason"])
|
|
100
102
|
return
|
|
101
103
|
|
|
102
|
-
logger.
|
|
103
|
-
"Rust core path
|
|
104
|
+
logger.info(
|
|
105
|
+
"Rust core path unavailable at startup; using Python path instead (env=%s, reason=%s, error=%s).",
|
|
104
106
|
env_display,
|
|
105
107
|
status["reason"],
|
|
106
108
|
status["binding_error"],
|
|
107
109
|
)
|
|
108
110
|
|
|
111
|
+
def _log_startup_summary(self, env: str, use_remote_export: bool) -> None:
|
|
112
|
+
service_name = (
|
|
113
|
+
self.file_config.service.name
|
|
114
|
+
if self.file_config and self.file_config.service and self.file_config.service.name
|
|
115
|
+
else "unknown"
|
|
116
|
+
)
|
|
117
|
+
service_id = (
|
|
118
|
+
self.file_config.service.id
|
|
119
|
+
if self.file_config and self.file_config.service and self.file_config.service.id
|
|
120
|
+
else "<unset>"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
logger.info(
|
|
124
|
+
"SDK initialized successfully (version=%s, mode=%s, env=%s, service=%s, serviceId=%s, exportSpans=%s, samplingRate=%s, logLevel=%s, runtime=python %s, platform=%s/%s).",
|
|
125
|
+
SDK_VERSION,
|
|
126
|
+
self.mode,
|
|
127
|
+
env,
|
|
128
|
+
service_name,
|
|
129
|
+
service_id,
|
|
130
|
+
use_remote_export,
|
|
131
|
+
self._sampling_rate,
|
|
132
|
+
get_log_level(),
|
|
133
|
+
platform.python_version(),
|
|
134
|
+
platform.system().lower(),
|
|
135
|
+
platform.machine().lower(),
|
|
136
|
+
)
|
|
137
|
+
|
|
109
138
|
@classmethod
|
|
110
139
|
def initialize(
|
|
111
140
|
cls,
|
|
@@ -216,8 +245,6 @@ class TuskDrift:
|
|
|
216
245
|
export_spans_enabled and effective_api_key is not None and effective_observable_service_id is not None
|
|
217
246
|
)
|
|
218
247
|
|
|
219
|
-
from ..version import SDK_VERSION as sdk_version
|
|
220
|
-
|
|
221
248
|
exporter_config = TdSpanExporterConfig(
|
|
222
249
|
base_directory=base_dir,
|
|
223
250
|
mode=instance.mode,
|
|
@@ -226,7 +253,7 @@ class TuskDrift:
|
|
|
226
253
|
api_key=effective_api_key,
|
|
227
254
|
tusk_backend_base_url=effective_backend_url,
|
|
228
255
|
environment=env,
|
|
229
|
-
sdk_version=
|
|
256
|
+
sdk_version=SDK_VERSION,
|
|
230
257
|
sdk_instance_id=instance._sdk_instance_id,
|
|
231
258
|
)
|
|
232
259
|
instance.span_exporter = TdSpanExporter(exporter_config)
|
|
@@ -236,7 +263,7 @@ class TuskDrift:
|
|
|
236
263
|
resource = Resource.create(
|
|
237
264
|
{
|
|
238
265
|
"service.name": service_name,
|
|
239
|
-
"service.version":
|
|
266
|
+
"service.version": SDK_VERSION,
|
|
240
267
|
"deployment.environment": env,
|
|
241
268
|
}
|
|
242
269
|
)
|
|
@@ -281,7 +308,7 @@ class TuskDrift:
|
|
|
281
308
|
atexit.register(instance.shutdown)
|
|
282
309
|
|
|
283
310
|
cls._initialized = True
|
|
284
|
-
|
|
311
|
+
instance._log_startup_summary(env=env, use_remote_export=use_remote_export)
|
|
285
312
|
|
|
286
313
|
return instance
|
|
287
314
|
|
|
@@ -416,7 +443,7 @@ class TuskDrift:
|
|
|
416
443
|
pass
|
|
417
444
|
|
|
418
445
|
try:
|
|
419
|
-
import httpx
|
|
446
|
+
import httpx
|
|
420
447
|
|
|
421
448
|
from ..instrumentation.httpx import HttpxInstrumentation
|
|
422
449
|
|
|
@@ -446,7 +473,7 @@ class TuskDrift:
|
|
|
446
473
|
pass
|
|
447
474
|
|
|
448
475
|
try:
|
|
449
|
-
import sqlalchemy
|
|
476
|
+
import sqlalchemy
|
|
450
477
|
|
|
451
478
|
from ..instrumentation.sqlalchemy import SqlAlchemyInstrumentation
|
|
452
479
|
|
|
@@ -463,7 +490,7 @@ class TuskDrift:
|
|
|
463
490
|
|
|
464
491
|
# Try psycopg2 first
|
|
465
492
|
try:
|
|
466
|
-
import psycopg2
|
|
493
|
+
import psycopg2
|
|
467
494
|
|
|
468
495
|
from ..instrumentation.psycopg2 import Psycopg2Instrumentation
|
|
469
496
|
|
|
@@ -475,7 +502,7 @@ class TuskDrift:
|
|
|
475
502
|
|
|
476
503
|
# Try psycopg (v3)
|
|
477
504
|
try:
|
|
478
|
-
import psycopg
|
|
505
|
+
import psycopg
|
|
479
506
|
|
|
480
507
|
from ..instrumentation.psycopg import PsycopgInstrumentation
|
|
481
508
|
|
|
@@ -491,7 +518,7 @@ class TuskDrift:
|
|
|
491
518
|
logger.debug("Both psycopg2 and psycopg available - instrumented both")
|
|
492
519
|
|
|
493
520
|
try:
|
|
494
|
-
import redis
|
|
521
|
+
import redis
|
|
495
522
|
|
|
496
523
|
from ..instrumentation.redis import RedisInstrumentation
|
|
497
524
|
|
|
@@ -501,7 +528,7 @@ class TuskDrift:
|
|
|
501
528
|
pass
|
|
502
529
|
|
|
503
530
|
try:
|
|
504
|
-
import grpc
|
|
531
|
+
import grpc
|
|
505
532
|
|
|
506
533
|
from ..instrumentation.grpc import GrpcInstrumentation
|
|
507
534
|
|
|
@@ -619,8 +646,6 @@ class TuskDrift:
|
|
|
619
646
|
if self._td_span_processor:
|
|
620
647
|
self._td_span_processor.update_app_ready(True)
|
|
621
648
|
|
|
622
|
-
logger.debug("Application marked as ready")
|
|
623
|
-
|
|
624
649
|
if self.mode == TuskDriftMode.REPLAY:
|
|
625
650
|
logger.debug("Replay mode active - ready to serve mocked responses")
|
|
626
651
|
elif self.mode == TuskDriftMode.RECORD:
|
|
@@ -113,7 +113,9 @@ def handle_replay_mode(
|
|
|
113
113
|
|
|
114
114
|
# Background request: App is ready + not within a trace (no parent span) + not a server request
|
|
115
115
|
if is_app_ready and not current_span_info and not is_server_request:
|
|
116
|
-
logger.
|
|
116
|
+
logger.warning(
|
|
117
|
+
"[ModeUtils] Background request detected during replay (no active trace context). This typically means a background job, scheduled task, or middleware (e.g., rate limiters, message consumers) is running outside of a test trace. To avoid errors, disable these services when TUSK_DRIFT_MODE=REPLAY."
|
|
118
|
+
)
|
|
117
119
|
return no_op_request_handler()
|
|
118
120
|
|
|
119
121
|
return replay_mode_handler()
|
{tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/rust_core_binding.py
RENAMED
|
@@ -9,7 +9,10 @@ from __future__ import annotations
|
|
|
9
9
|
import json
|
|
10
10
|
import logging
|
|
11
11
|
import os
|
|
12
|
-
from typing import Any
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from .types import PackageType, SpanKind, StatusCode
|
|
13
16
|
|
|
14
17
|
logger = logging.getLogger(__name__)
|
|
15
18
|
|
|
@@ -161,16 +164,16 @@ def build_span_proto_bytes(
|
|
|
161
164
|
package_name: str,
|
|
162
165
|
instrumentation_name: str,
|
|
163
166
|
submodule_name: str,
|
|
164
|
-
package_type:
|
|
167
|
+
package_type: PackageType,
|
|
165
168
|
environment: str | None,
|
|
166
|
-
kind:
|
|
169
|
+
kind: SpanKind,
|
|
167
170
|
input_schema: dict[str, Any],
|
|
168
171
|
output_schema: dict[str, Any],
|
|
169
172
|
input_schema_hash: str,
|
|
170
173
|
output_schema_hash: str,
|
|
171
174
|
input_value_hash: str,
|
|
172
175
|
output_value_hash: str,
|
|
173
|
-
status_code:
|
|
176
|
+
status_code: StatusCode,
|
|
174
177
|
status_message: str,
|
|
175
178
|
is_pre_app_start: bool,
|
|
176
179
|
is_root_span: bool,
|
|
@@ -190,6 +193,14 @@ def build_span_proto_bytes(
|
|
|
190
193
|
if binding is None:
|
|
191
194
|
return None
|
|
192
195
|
try:
|
|
196
|
+
from .types import PackageType, SpanKind, StatusCode
|
|
197
|
+
|
|
198
|
+
if not isinstance(package_type, PackageType):
|
|
199
|
+
raise TypeError(f"package_type must be PackageType, got {type(package_type).__name__}")
|
|
200
|
+
if not isinstance(kind, SpanKind):
|
|
201
|
+
raise TypeError(f"kind must be SpanKind, got {type(kind).__name__}")
|
|
202
|
+
if not isinstance(status_code, StatusCode):
|
|
203
|
+
raise TypeError(f"status_code must be StatusCode, got {type(status_code).__name__}")
|
|
193
204
|
return binding.build_span_proto_bytes_pyobject(
|
|
194
205
|
trace_id,
|
|
195
206
|
span_id,
|
|
@@ -198,16 +209,16 @@ def build_span_proto_bytes(
|
|
|
198
209
|
package_name,
|
|
199
210
|
instrumentation_name,
|
|
200
211
|
submodule_name,
|
|
201
|
-
package_type,
|
|
212
|
+
package_type.value,
|
|
202
213
|
environment,
|
|
203
|
-
kind,
|
|
214
|
+
kind.value,
|
|
204
215
|
input_schema,
|
|
205
216
|
output_schema,
|
|
206
217
|
input_schema_hash,
|
|
207
218
|
output_schema_hash,
|
|
208
219
|
input_value_hash,
|
|
209
220
|
output_value_hash,
|
|
210
|
-
status_code,
|
|
221
|
+
status_code.value,
|
|
211
222
|
status_message,
|
|
212
223
|
is_pre_app_start,
|
|
213
224
|
is_root_span,
|
{tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/otel_converter.py
RENAMED
|
@@ -420,9 +420,6 @@ def otel_span_to_clean_span_data(
|
|
|
420
420
|
# Convert kind
|
|
421
421
|
kind = otel_span_kind_to_drift(otel_span.kind)
|
|
422
422
|
|
|
423
|
-
kind_value = kind.value if hasattr(kind, "value") else kind
|
|
424
|
-
status_code_value = status.code.value if hasattr(status.code, "value") else status.code
|
|
425
|
-
package_type_value = package_type.value if hasattr(package_type, "value") else package_type
|
|
426
423
|
span_proto_bytes = build_span_proto_bytes(
|
|
427
424
|
trace_id=trace_id,
|
|
428
425
|
span_id=span_id,
|
|
@@ -431,16 +428,16 @@ def otel_span_to_clean_span_data(
|
|
|
431
428
|
package_name=package_name,
|
|
432
429
|
instrumentation_name=instrumentation_name,
|
|
433
430
|
submodule_name=submodule_name,
|
|
434
|
-
package_type=
|
|
431
|
+
package_type=package_type,
|
|
435
432
|
environment=environment,
|
|
436
|
-
kind=
|
|
433
|
+
kind=kind,
|
|
437
434
|
input_schema=input_schema,
|
|
438
435
|
output_schema=output_schema,
|
|
439
436
|
input_schema_hash=input_schema_hash,
|
|
440
437
|
output_schema_hash=output_schema_hash,
|
|
441
438
|
input_value_hash=input_value_hash,
|
|
442
439
|
output_value_hash=output_value_hash,
|
|
443
|
-
status_code=
|
|
440
|
+
status_code=status.code,
|
|
444
441
|
status_message=status.message,
|
|
445
442
|
is_pre_app_start=is_pre_app_start,
|
|
446
443
|
is_root_span=is_root_span,
|
|
@@ -6,6 +6,10 @@ import aiohttp
|
|
|
6
6
|
from flask import Flask, jsonify, request
|
|
7
7
|
|
|
8
8
|
from drift import TuskDrift
|
|
9
|
+
from drift.instrumentation.e2e_common.external_http import (
|
|
10
|
+
external_http_timeout_seconds,
|
|
11
|
+
upstream_url,
|
|
12
|
+
)
|
|
9
13
|
|
|
10
14
|
# Initialize SDK
|
|
11
15
|
sdk = TuskDrift.initialize(
|
|
@@ -14,6 +18,25 @@ sdk = TuskDrift.initialize(
|
|
|
14
18
|
)
|
|
15
19
|
|
|
16
20
|
app = Flask(__name__)
|
|
21
|
+
EXTERNAL_HTTP_TIMEOUT_SECONDS = external_http_timeout_seconds()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _configure_aiohttp_for_mock_and_timeouts():
|
|
25
|
+
original_request = aiohttp.ClientSession._request
|
|
26
|
+
|
|
27
|
+
async def patched_request(self, method, str_or_url, *args, **kwargs):
|
|
28
|
+
session_timeout = getattr(self, "_timeout", None)
|
|
29
|
+
default_timeout = getattr(aiohttp.client, "DEFAULT_TIMEOUT", None)
|
|
30
|
+
using_default_session_timeout = session_timeout is default_timeout or session_timeout == default_timeout
|
|
31
|
+
if "timeout" not in kwargs and using_default_session_timeout:
|
|
32
|
+
kwargs["timeout"] = aiohttp.ClientTimeout(total=EXTERNAL_HTTP_TIMEOUT_SECONDS)
|
|
33
|
+
rewritten = upstream_url(str(str_or_url))
|
|
34
|
+
return await original_request(self, method, rewritten, *args, **kwargs)
|
|
35
|
+
|
|
36
|
+
aiohttp.ClientSession._request = patched_request
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
_configure_aiohttp_for_mock_and_timeouts()
|
|
17
40
|
|
|
18
41
|
|
|
19
42
|
# =============================================================================
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Django views for e2e test application."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from django.http import HttpResponse, JsonResponse
|
|
8
|
+
from django.middleware.csrf import get_token
|
|
9
|
+
from django.views.decorators.csrf import csrf_exempt
|
|
10
|
+
from django.views.decorators.http import require_GET, require_http_methods, require_POST
|
|
11
|
+
from opentelemetry import context as otel_context
|
|
12
|
+
|
|
13
|
+
from drift.instrumentation.e2e_common.external_http import (
|
|
14
|
+
external_http_timeout_seconds,
|
|
15
|
+
upstream_url,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
EXTERNAL_HTTP_TIMEOUT_SECONDS = external_http_timeout_seconds()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _run_with_context(ctx, fn, *args, **kwargs):
|
|
22
|
+
"""Helper to run a function with OpenTelemetry context in a thread pool."""
|
|
23
|
+
token = otel_context.attach(ctx)
|
|
24
|
+
try:
|
|
25
|
+
return fn(*args, **kwargs)
|
|
26
|
+
finally:
|
|
27
|
+
otel_context.detach(token)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@require_GET
|
|
31
|
+
def health(request):
|
|
32
|
+
"""Health check endpoint."""
|
|
33
|
+
return JsonResponse({"status": "healthy"})
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@require_GET
|
|
37
|
+
def get_weather(request):
|
|
38
|
+
"""Fetch weather data from external API."""
|
|
39
|
+
try:
|
|
40
|
+
response = requests.get(
|
|
41
|
+
upstream_url("https://api.open-meteo.com/v1/forecast"),
|
|
42
|
+
params={
|
|
43
|
+
"latitude": 40.7128,
|
|
44
|
+
"longitude": -74.0060,
|
|
45
|
+
"current_weather": "true",
|
|
46
|
+
},
|
|
47
|
+
timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
|
|
48
|
+
)
|
|
49
|
+
weather = response.json()
|
|
50
|
+
|
|
51
|
+
return JsonResponse(
|
|
52
|
+
{
|
|
53
|
+
"location": "New York",
|
|
54
|
+
"weather": weather.get("current_weather", {}),
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
except Exception as e:
|
|
58
|
+
return JsonResponse(
|
|
59
|
+
{
|
|
60
|
+
"location": "New York",
|
|
61
|
+
"weather": {},
|
|
62
|
+
"fallback": True,
|
|
63
|
+
"error": f"Failed to fetch weather: {str(e)}",
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@require_GET
|
|
69
|
+
def get_user(request, user_id: str):
|
|
70
|
+
"""Fetch user data from external API with seed."""
|
|
71
|
+
try:
|
|
72
|
+
response = requests.get(
|
|
73
|
+
upstream_url("https://randomuser.me/api/"),
|
|
74
|
+
params={"seed": user_id},
|
|
75
|
+
timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
|
|
76
|
+
)
|
|
77
|
+
return JsonResponse(response.json())
|
|
78
|
+
except Exception as e:
|
|
79
|
+
return JsonResponse({"results": [], "fallback": True, "error": f"Failed to fetch user: {str(e)}"})
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@csrf_exempt
|
|
83
|
+
@require_POST
|
|
84
|
+
def create_post(request):
|
|
85
|
+
"""Create a new post via external API."""
|
|
86
|
+
data = {}
|
|
87
|
+
try:
|
|
88
|
+
data = json.loads(request.body)
|
|
89
|
+
response = requests.post(
|
|
90
|
+
upstream_url("https://jsonplaceholder.typicode.com/posts"),
|
|
91
|
+
json={
|
|
92
|
+
"title": data.get("title"),
|
|
93
|
+
"body": data.get("body"),
|
|
94
|
+
"userId": data.get("userId", 1),
|
|
95
|
+
},
|
|
96
|
+
timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
|
|
97
|
+
)
|
|
98
|
+
return JsonResponse(response.json(), status=201)
|
|
99
|
+
except Exception as e:
|
|
100
|
+
return JsonResponse(
|
|
101
|
+
{
|
|
102
|
+
"id": -1,
|
|
103
|
+
"title": data.get("title", ""),
|
|
104
|
+
"body": data.get("body", ""),
|
|
105
|
+
"userId": data.get("userId", 1),
|
|
106
|
+
"fallback": True,
|
|
107
|
+
"error": f"Failed to create post: {str(e)}",
|
|
108
|
+
},
|
|
109
|
+
status=201,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@require_GET
|
|
114
|
+
def get_post(request, post_id: int):
|
|
115
|
+
"""Fetch post and comments in parallel using ThreadPoolExecutor."""
|
|
116
|
+
try:
|
|
117
|
+
ctx = otel_context.get_current()
|
|
118
|
+
|
|
119
|
+
with ThreadPoolExecutor(max_workers=2) as executor:
|
|
120
|
+
post_future = executor.submit(
|
|
121
|
+
_run_with_context,
|
|
122
|
+
ctx,
|
|
123
|
+
requests.get,
|
|
124
|
+
upstream_url(f"https://jsonplaceholder.typicode.com/posts/{post_id}"),
|
|
125
|
+
timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
|
|
126
|
+
)
|
|
127
|
+
comments_future = executor.submit(
|
|
128
|
+
_run_with_context,
|
|
129
|
+
ctx,
|
|
130
|
+
requests.get,
|
|
131
|
+
upstream_url(f"https://jsonplaceholder.typicode.com/posts/{post_id}/comments"),
|
|
132
|
+
timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
post_response = post_future.result()
|
|
136
|
+
comments_response = comments_future.result()
|
|
137
|
+
|
|
138
|
+
return JsonResponse(
|
|
139
|
+
{
|
|
140
|
+
"post": post_response.json(),
|
|
141
|
+
"comments": comments_response.json(),
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
except Exception as e:
|
|
145
|
+
return JsonResponse(
|
|
146
|
+
{
|
|
147
|
+
"post": {},
|
|
148
|
+
"comments": [],
|
|
149
|
+
"fallback": True,
|
|
150
|
+
"error": f"Failed to fetch post: {str(e)}",
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@csrf_exempt
|
|
156
|
+
@require_http_methods(["DELETE"])
|
|
157
|
+
def delete_post(request, post_id: int):
|
|
158
|
+
"""Delete a post via external API."""
|
|
159
|
+
try:
|
|
160
|
+
requests.delete(
|
|
161
|
+
upstream_url(f"https://jsonplaceholder.typicode.com/posts/{post_id}"),
|
|
162
|
+
timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
|
|
163
|
+
)
|
|
164
|
+
return JsonResponse({"message": f"Post {post_id} deleted successfully"})
|
|
165
|
+
except Exception as e:
|
|
166
|
+
return JsonResponse(
|
|
167
|
+
{
|
|
168
|
+
"message": f"Post {post_id} delete fallback",
|
|
169
|
+
"fallback": True,
|
|
170
|
+
"error": f"Failed to delete post: {str(e)}",
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@require_GET
|
|
176
|
+
def get_activity(request):
|
|
177
|
+
"""Fetch a random activity suggestion."""
|
|
178
|
+
try:
|
|
179
|
+
response = requests.get(
|
|
180
|
+
upstream_url("https://bored-api.appbrewery.com/random"),
|
|
181
|
+
timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
|
|
182
|
+
)
|
|
183
|
+
return JsonResponse(response.json())
|
|
184
|
+
except Exception as e:
|
|
185
|
+
return JsonResponse(
|
|
186
|
+
{
|
|
187
|
+
"activity": "Take a short walk",
|
|
188
|
+
"type": "relaxation",
|
|
189
|
+
"participants": 1,
|
|
190
|
+
"fallback": True,
|
|
191
|
+
"error": f"Failed to fetch activity: {str(e)}",
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@require_GET
|
|
197
|
+
def csrf_form(request):
|
|
198
|
+
"""Return an HTML form with CSRF token for testing CSRF normalization.
|
|
199
|
+
|
|
200
|
+
This endpoint tests that CSRF tokens are properly normalized during
|
|
201
|
+
recording so that replay comparisons succeed.
|
|
202
|
+
"""
|
|
203
|
+
csrf_token = get_token(request)
|
|
204
|
+
html = f"""<!DOCTYPE html>
|
|
205
|
+
<html>
|
|
206
|
+
<head><title>CSRF Test Form</title></head>
|
|
207
|
+
<body>
|
|
208
|
+
<h1>CSRF Test Form</h1>
|
|
209
|
+
<form method="POST" action="/api/submit">
|
|
210
|
+
<input type="hidden" name="csrfmiddlewaretoken" value="{csrf_token}">
|
|
211
|
+
<input type="text" name="message" placeholder="Enter message">
|
|
212
|
+
<button type="submit">Submit</button>
|
|
213
|
+
</form>
|
|
214
|
+
</body>
|
|
215
|
+
</html>"""
|
|
216
|
+
return HttpResponse(html, content_type="text/html")
|