sentry-sdk 3.0.0a6__tar.gz → 3.0.0a7__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.

Potentially problematic release.


This version of sentry-sdk might be problematic. Click here for more details.

Files changed (204) hide show
  1. {sentry_sdk-3.0.0a6/sentry_sdk.egg-info → sentry_sdk-3.0.0a7}/PKG-INFO +1 -1
  2. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/_init_implementation.py +5 -0
  3. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/consts.py +4 -2
  4. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/threading.py +1 -1
  5. sentry_sdk-3.0.0a7/sentry_sdk/spotlight.py +75 -0
  6. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/transport.py +6 -1
  7. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7/sentry_sdk.egg-info}/PKG-INFO +1 -1
  8. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/setup.py +1 -1
  9. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_client.py +2 -2
  10. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_transport.py +49 -19
  11. sentry_sdk-3.0.0a6/sentry_sdk/spotlight.py +0 -236
  12. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/LICENSE +0 -0
  13. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/MANIFEST.in +0 -0
  14. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/README.md +0 -0
  15. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/pyproject.toml +0 -0
  16. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/__init__.py +0 -0
  17. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/_compat.py +0 -0
  18. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/_log_batcher.py +0 -0
  19. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/_lru_cache.py +0 -0
  20. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/_queue.py +0 -0
  21. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/_types.py +0 -0
  22. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/_werkzeug.py +0 -0
  23. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/ai/__init__.py +0 -0
  24. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/ai/monitoring.py +0 -0
  25. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/ai/utils.py +0 -0
  26. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/api.py +0 -0
  27. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/attachments.py +0 -0
  28. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/client.py +0 -0
  29. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/crons/__init__.py +0 -0
  30. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/crons/api.py +0 -0
  31. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/crons/consts.py +0 -0
  32. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/crons/decorator.py +0 -0
  33. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/debug.py +0 -0
  34. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/envelope.py +0 -0
  35. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/feature_flags.py +0 -0
  36. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/__init__.py +0 -0
  37. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/_asgi_common.py +0 -0
  38. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/_wsgi_common.py +0 -0
  39. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/aiohttp.py +0 -0
  40. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/anthropic.py +0 -0
  41. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/argv.py +0 -0
  42. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/ariadne.py +0 -0
  43. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/arq.py +0 -0
  44. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/asgi.py +0 -0
  45. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/asyncio.py +0 -0
  46. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/asyncpg.py +0 -0
  47. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/atexit.py +0 -0
  48. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/aws_lambda.py +0 -0
  49. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/beam.py +0 -0
  50. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/boto3.py +0 -0
  51. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/bottle.py +0 -0
  52. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/celery/__init__.py +0 -0
  53. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/celery/beat.py +0 -0
  54. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/celery/utils.py +0 -0
  55. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/chalice.py +0 -0
  56. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/clickhouse_driver.py +0 -0
  57. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/cloud_resource_context.py +0 -0
  58. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/cohere.py +0 -0
  59. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/dedupe.py +0 -0
  60. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/django/__init__.py +0 -0
  61. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/django/asgi.py +0 -0
  62. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/django/caching.py +0 -0
  63. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/django/middleware.py +0 -0
  64. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/django/signals_handlers.py +0 -0
  65. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/django/templates.py +0 -0
  66. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/django/transactions.py +0 -0
  67. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/django/views.py +0 -0
  68. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/dramatiq.py +0 -0
  69. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/excepthook.py +0 -0
  70. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/executing.py +0 -0
  71. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/falcon.py +0 -0
  72. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/fastapi.py +0 -0
  73. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/flask.py +0 -0
  74. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/gcp.py +0 -0
  75. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/gnu_backtrace.py +0 -0
  76. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/gql.py +0 -0
  77. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/graphene.py +0 -0
  78. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/grpc/__init__.py +0 -0
  79. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/grpc/aio/__init__.py +0 -0
  80. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/grpc/aio/client.py +0 -0
  81. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/grpc/aio/server.py +0 -0
  82. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/grpc/client.py +0 -0
  83. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/grpc/consts.py +0 -0
  84. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/grpc/server.py +0 -0
  85. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/httpx.py +0 -0
  86. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/huey.py +0 -0
  87. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/huggingface_hub.py +0 -0
  88. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/langchain.py +0 -0
  89. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/launchdarkly.py +0 -0
  90. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/litestar.py +0 -0
  91. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/logging.py +0 -0
  92. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/loguru.py +0 -0
  93. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/modules.py +0 -0
  94. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai.py +0 -0
  95. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/__init__.py +0 -0
  96. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/consts.py +0 -0
  97. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/patches/__init__.py +0 -0
  98. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/patches/agent_run.py +0 -0
  99. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/patches/models.py +0 -0
  100. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/patches/runner.py +0 -0
  101. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/patches/tools.py +0 -0
  102. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/spans/__init__.py +0 -0
  103. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +0 -0
  104. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/spans/ai_client.py +0 -0
  105. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/spans/execute_tool.py +0 -0
  106. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/spans/handoff.py +0 -0
  107. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +0 -0
  108. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openai_agents/utils.py +0 -0
  109. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/openfeature.py +0 -0
  110. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/pure_eval.py +0 -0
  111. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/pymongo.py +0 -0
  112. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/pyramid.py +0 -0
  113. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/quart.py +0 -0
  114. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/ray.py +0 -0
  115. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/__init__.py +0 -0
  116. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/_async_common.py +0 -0
  117. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/_sync_common.py +0 -0
  118. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/consts.py +0 -0
  119. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/modules/__init__.py +0 -0
  120. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/modules/caches.py +0 -0
  121. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/modules/queries.py +0 -0
  122. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/rb.py +0 -0
  123. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/redis.py +0 -0
  124. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/redis_cluster.py +0 -0
  125. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +0 -0
  126. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/redis/utils.py +0 -0
  127. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/rq.py +0 -0
  128. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/rust_tracing.py +0 -0
  129. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/sanic.py +0 -0
  130. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/serverless.py +0 -0
  131. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/socket.py +0 -0
  132. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/spark/__init__.py +0 -0
  133. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/spark/spark_driver.py +0 -0
  134. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/spark/spark_worker.py +0 -0
  135. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/sqlalchemy.py +0 -0
  136. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/starlette.py +0 -0
  137. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/starlite.py +0 -0
  138. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/statsig.py +0 -0
  139. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/stdlib.py +0 -0
  140. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/strawberry.py +0 -0
  141. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/sys_exit.py +0 -0
  142. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/tornado.py +0 -0
  143. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/trytond.py +0 -0
  144. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/typer.py +0 -0
  145. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/unleash.py +0 -0
  146. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/integrations/wsgi.py +0 -0
  147. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/logger.py +0 -0
  148. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/monitor.py +0 -0
  149. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/opentelemetry/__init__.py +0 -0
  150. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/opentelemetry/consts.py +0 -0
  151. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/opentelemetry/contextvars_context.py +0 -0
  152. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/opentelemetry/propagator.py +0 -0
  153. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/opentelemetry/sampler.py +0 -0
  154. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/opentelemetry/scope.py +0 -0
  155. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/opentelemetry/span_processor.py +0 -0
  156. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/opentelemetry/tracing.py +0 -0
  157. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/opentelemetry/utils.py +0 -0
  158. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/profiler/__init__.py +0 -0
  159. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/profiler/continuous_profiler.py +0 -0
  160. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/profiler/transaction_profiler.py +0 -0
  161. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/profiler/utils.py +0 -0
  162. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/py.typed +0 -0
  163. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/scope.py +0 -0
  164. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/scrubber.py +0 -0
  165. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/serializer.py +0 -0
  166. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/session.py +0 -0
  167. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/sessions.py +0 -0
  168. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/tracing.py +0 -0
  169. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/tracing_utils.py +0 -0
  170. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/types.py +0 -0
  171. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/utils.py +0 -0
  172. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk/worker.py +0 -0
  173. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk.egg-info/SOURCES.txt +0 -0
  174. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk.egg-info/dependency_links.txt +0 -0
  175. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk.egg-info/entry_points.txt +0 -0
  176. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk.egg-info/not-zip-safe +0 -0
  177. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk.egg-info/requires.txt +0 -0
  178. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/sentry_sdk.egg-info/top_level.txt +0 -0
  179. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/setup.cfg +0 -0
  180. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_ai_monitoring.py +0 -0
  181. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_api.py +0 -0
  182. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_basics.py +0 -0
  183. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_breadcrumbs.py +0 -0
  184. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_conftest.py +0 -0
  185. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_crons.py +0 -0
  186. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_dsc.py +0 -0
  187. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_envelope.py +0 -0
  188. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_exceptiongroup.py +0 -0
  189. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_feature_flags.py +0 -0
  190. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_full_stack_frames.py +0 -0
  191. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_gevent.py +0 -0
  192. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_import.py +0 -0
  193. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_logs.py +0 -0
  194. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_lru_cache.py +0 -0
  195. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_monitor.py +0 -0
  196. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_propagationcontext.py +0 -0
  197. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_scope.py +0 -0
  198. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_scrubber.py +0 -0
  199. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_serializer.py +0 -0
  200. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_sessions.py +0 -0
  201. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_spotlight.py +0 -0
  202. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_tracing_utils.py +0 -0
  203. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_types.py +0 -0
  204. {sentry_sdk-3.0.0a6 → sentry_sdk-3.0.0a7}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sentry-sdk
3
- Version: 3.0.0a6
3
+ Version: 3.0.0a7
4
4
  Summary: Python client for Sentry (https://sentry.io)
5
5
  Home-page: https://github.com/getsentry/sentry-python
6
6
  Author: Sentry Team and Contributors
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+ import warnings
2
3
 
3
4
  from typing import TYPE_CHECKING
4
5
 
@@ -25,6 +26,10 @@ def _init(*args: Optional[str], **kwargs: Any) -> None:
25
26
  setup_scope_context_management()
26
27
  client = sentry_sdk.Client(*args, **kwargs)
27
28
  sentry_sdk.get_global_scope().set_client(client)
29
+ warnings.warn(
30
+ "We won't be continuing development on SDK 3.0. Please use the last stable version of the SDK to get access to the newest features and fixes. See https://github.com/getsentry/sentry-python/discussions/4955",
31
+ stacklevel=2,
32
+ )
28
33
  _check_python_deprecations()
29
34
 
30
35
 
@@ -77,7 +77,6 @@ if TYPE_CHECKING:
77
77
  "transport_compression_level": Optional[int],
78
78
  "transport_compression_algo": Optional[CompressionAlgo],
79
79
  "transport_num_pools": Optional[int],
80
- "transport_http2": Optional[bool],
81
80
  "transport_async": Optional[bool],
82
81
  },
83
82
  total=False,
@@ -971,6 +970,7 @@ class ClientConstructor:
971
970
  max_stack_frames: Optional[int] = DEFAULT_MAX_STACK_FRAMES,
972
971
  enable_logs: bool = False,
973
972
  before_send_log: Optional[Callable[[Log, Hint], Optional[Log]]] = None,
973
+ http2: Optional[bool] = None,
974
974
  ) -> None:
975
975
  """Initialize the Sentry SDK with the given parameters. All parameters described here can be used in a call to `sentry_sdk.init()`.
976
976
 
@@ -1343,6 +1343,8 @@ class ClientConstructor:
1343
1343
  This is relative to the tracing sample rate - e.g. `0.5` means 50% of sampled transactions will be
1344
1344
  profiled.
1345
1345
 
1346
+ :param http2: Defaults to `True`, enables HTTP/2 support for the SDK.
1347
+
1346
1348
  :param profiles_sampler:
1347
1349
 
1348
1350
  :param profiler_mode:
@@ -1389,4 +1391,4 @@ DEFAULT_OPTIONS = _get_default_options()
1389
1391
  del _get_default_options
1390
1392
 
1391
1393
 
1392
- VERSION = "3.0.0a6"
1394
+ VERSION = "3.0.0a7"
@@ -38,7 +38,7 @@ class ThreadingIntegration(Integration):
38
38
 
39
39
  try:
40
40
  from django import VERSION as django_version # noqa: N811
41
- import channels # type: ignore[import-not-found]
41
+ import channels # type: ignore
42
42
 
43
43
  channels_version = channels.__version__
44
44
  except ImportError:
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+ import io
3
+ import logging
4
+ import urllib3
5
+ import sys
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from typing import Any, Dict, Optional
11
+
12
+ from sentry_sdk.utils import (
13
+ logger as sentry_logger,
14
+ )
15
+ from sentry_sdk.envelope import Envelope
16
+
17
+
18
+ logger = logging.getLogger("spotlight")
19
+
20
+
21
+ DEFAULT_SPOTLIGHT_URL = "http://localhost:8969/stream"
22
+ DJANGO_SPOTLIGHT_MIDDLEWARE_PATH = "sentry_sdk.spotlight.SpotlightMiddleware"
23
+
24
+
25
+ class SpotlightClient:
26
+ def __init__(self, url: str) -> None:
27
+ self.url = url
28
+ self.http = urllib3.PoolManager()
29
+ self.fails = 0
30
+
31
+ def capture_envelope(self, envelope: Envelope) -> None:
32
+ body = io.BytesIO()
33
+ envelope.serialize_into(body)
34
+ try:
35
+ req = self.http.request(
36
+ url=self.url,
37
+ body=body.getvalue(),
38
+ method="POST",
39
+ headers={
40
+ "Content-Type": "application/x-sentry-envelope",
41
+ },
42
+ )
43
+ req.close()
44
+ self.fails = 0
45
+ except Exception as e:
46
+ if self.fails < 2:
47
+ sentry_logger.warning(str(e))
48
+ self.fails += 1
49
+ elif self.fails == 2:
50
+ self.fails += 1
51
+ sentry_logger.warning(
52
+ "Looks like Spotlight is not running, will keep trying to send events but will not log errors."
53
+ )
54
+ # omitting self.fails += 1 in the `else:` case intentionally
55
+ # to avoid overflowing the variable if Spotlight never becomes reachable
56
+
57
+
58
+ def setup_spotlight(options: Dict[str, Any]) -> Optional[SpotlightClient]:
59
+ _handler = logging.StreamHandler(sys.stderr)
60
+ _handler.setFormatter(logging.Formatter(" [spotlight] %(levelname)s: %(message)s"))
61
+ logger.addHandler(_handler)
62
+ logger.setLevel(logging.INFO)
63
+
64
+ url = options.get("spotlight")
65
+
66
+ if url is True:
67
+ url = DEFAULT_SPOTLIGHT_URL
68
+
69
+ if not isinstance(url, str):
70
+ return None
71
+
72
+ client = SpotlightClient(url)
73
+ logger.info("Enabled Spotlight using sidecar at %s", url)
74
+
75
+ return client
@@ -1051,7 +1051,12 @@ else:
1051
1051
  def make_transport(options: Dict[str, Any]) -> Optional[Transport]:
1052
1052
  ref_transport = options["transport"]
1053
1053
 
1054
- use_http2_transport = options.get("_experiments", {}).get("transport_http2", False)
1054
+ # We default to using HTTP2 transport if the user also has the required h2
1055
+ # library installed (through the subclass check). The reason is h2 not being
1056
+ # available on py3.7 which we still support.
1057
+ use_http2_transport = options.get("http2") is not False and not issubclass(
1058
+ Http2Transport, HttpTransport
1059
+ )
1055
1060
  use_async_transport = options.get("_experiments", {}).get("transport_async", False)
1056
1061
  async_integration = any(
1057
1062
  integration.__class__.__name__ == "AsyncioIntegration"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sentry-sdk
3
- Version: 3.0.0a6
3
+ Version: 3.0.0a7
4
4
  Summary: Python client for Sentry (https://sentry.io)
5
5
  Home-page: https://github.com/getsentry/sentry-python
6
6
  Author: Sentry Team and Contributors
@@ -21,7 +21,7 @@ def get_file_text(file_name):
21
21
 
22
22
  setup(
23
23
  name="sentry-sdk",
24
- version="3.0.0a6",
24
+ version="3.0.0a7",
25
25
  author="Sentry Team and Contributors",
26
26
  author_email="hello@sentry.io",
27
27
  url="https://github.com/getsentry/sentry-python",
@@ -257,8 +257,8 @@ def test_proxy(monkeypatch, testcase, http2):
257
257
 
258
258
  kwargs = {}
259
259
 
260
- if http2:
261
- kwargs["_experiments"] = {"transport_http2": True}
260
+ if not http2:
261
+ kwargs["http2"] = False
262
262
 
263
263
  if testcase["arg_http_proxy"] is not None:
264
264
  kwargs["http_proxy"] = testcase["arg_http_proxy"]
@@ -83,7 +83,7 @@ def mock_transaction_envelope(span_count: int) -> Envelope:
83
83
  @pytest.mark.parametrize("use_pickle", (True, False))
84
84
  @pytest.mark.parametrize("compression_level", (0, 9, None))
85
85
  @pytest.mark.parametrize("compression_algo", ("gzip", "br", "<invalid>", None))
86
- @pytest.mark.parametrize("http2", [True, False] if PY38 else [False])
86
+ @pytest.mark.parametrize("http2", [None, False])
87
87
  def test_transport_works(
88
88
  capturing_server,
89
89
  request,
@@ -106,11 +106,9 @@ def test_transport_works(
106
106
  if compression_algo is not None:
107
107
  experiments["transport_compression_algo"] = compression_algo
108
108
 
109
- if http2:
110
- experiments["transport_http2"] = True
111
-
112
109
  client = make_client(
113
110
  debug=debug,
111
+ http2=http2,
114
112
  _experiments=experiments,
115
113
  )
116
114
 
@@ -245,7 +243,7 @@ def test_transport_num_pools(make_client, num_pools, expected_num_pools):
245
243
  if num_pools is not None:
246
244
  _experiments["transport_num_pools"] = num_pools
247
245
 
248
- client = make_client(_experiments=_experiments)
246
+ client = make_client(_experiments=_experiments, http2=False)
249
247
 
250
248
  options = client.transport._get_pool_options()
251
249
  assert options["num_pools"] == expected_num_pools
@@ -255,17 +253,13 @@ def test_transport_num_pools(make_client, num_pools, expected_num_pools):
255
253
  "http2", [True, False] if sys.version_info >= (3, 8) else [False]
256
254
  )
257
255
  def test_two_way_ssl_authentication(make_client, http2):
258
- _experiments = {}
259
- if http2:
260
- _experiments["transport_http2"] = True
261
-
262
256
  current_dir = os.path.dirname(__file__)
263
257
  cert_file = f"{current_dir}/test.pem"
264
258
  key_file = f"{current_dir}/test.key"
265
259
  client = make_client(
266
260
  cert_file=cert_file,
267
261
  key_file=key_file,
268
- _experiments=_experiments,
262
+ http2=http2,
269
263
  )
270
264
  options = client.transport._get_pool_options()
271
265
 
@@ -290,20 +284,20 @@ def test_socket_options(make_client):
290
284
 
291
285
 
292
286
  def test_keep_alive_true(make_client):
293
- client = make_client(keep_alive=True)
287
+ client = make_client(keep_alive=True, http2=False)
294
288
 
295
289
  options = client.transport._get_pool_options()
296
290
  assert options["socket_options"] == KEEP_ALIVE_SOCKET_OPTIONS
297
291
 
298
292
 
299
293
  def test_keep_alive_on_by_default(make_client):
300
- client = make_client()
294
+ client = make_client(http2=False)
301
295
  options = client.transport._get_pool_options()
302
296
  assert "socket_options" not in options
303
297
 
304
298
 
305
299
  def test_default_timeout(make_client):
306
- client = make_client()
300
+ client = make_client(http2=False)
307
301
 
308
302
  options = client.transport._get_pool_options()
309
303
  assert "timeout" in options
@@ -312,7 +306,7 @@ def test_default_timeout(make_client):
312
306
 
313
307
  @pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
314
308
  def test_default_timeout_http2(make_client):
315
- client = make_client(_experiments={"transport_http2": True})
309
+ client = make_client()
316
310
 
317
311
  with mock.patch(
318
312
  "sentry_sdk.transport.httpcore.ConnectionPool.request",
@@ -335,7 +329,7 @@ def test_default_timeout_http2(make_client):
335
329
 
336
330
  @pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
337
331
  def test_http2_with_https_dsn(make_client):
338
- client = make_client(_experiments={"transport_http2": True})
332
+ client = make_client()
339
333
  client.transport.parsed_dsn.scheme = "https"
340
334
  options = client.transport._get_pool_options()
341
335
  assert options["http2"] is True
@@ -343,7 +337,7 @@ def test_http2_with_https_dsn(make_client):
343
337
 
344
338
  @pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
345
339
  def test_no_http2_with_http_dsn(make_client):
346
- client = make_client(_experiments={"transport_http2": True})
340
+ client = make_client()
347
341
  client.transport.parsed_dsn.scheme = "http"
348
342
  options = client.transport._get_pool_options()
349
343
  assert options["http2"] is False
@@ -356,19 +350,44 @@ def test_socket_options_override_keep_alive(make_client):
356
350
  (socket.SOL_TCP, socket.TCP_KEEPCNT, 6),
357
351
  ]
358
352
 
359
- client = make_client(socket_options=socket_options, keep_alive=False)
353
+ client = make_client(socket_options=socket_options, keep_alive=False, http2=False)
360
354
 
361
355
  options = client.transport._get_pool_options()
362
356
  assert options["socket_options"] == socket_options
363
357
 
364
358
 
359
+ @pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
360
+ def test_socket_options_merge_with_keep_alive_http2(make_client):
361
+ socket_options = [
362
+ (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 42),
363
+ (socket.SOL_TCP, socket.TCP_KEEPINTVL, 42),
364
+ ]
365
+
366
+ client = make_client(socket_options=socket_options)
367
+
368
+ options = client.transport._get_pool_options()
369
+ try:
370
+ assert options["socket_options"] == [
371
+ (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 42),
372
+ (socket.SOL_TCP, socket.TCP_KEEPINTVL, 42),
373
+ (socket.SOL_TCP, socket.TCP_KEEPIDLE, 45),
374
+ (socket.SOL_TCP, socket.TCP_KEEPCNT, 6),
375
+ ]
376
+ except AttributeError:
377
+ assert options["socket_options"] == [
378
+ (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 42),
379
+ (socket.SOL_TCP, socket.TCP_KEEPINTVL, 42),
380
+ (socket.SOL_TCP, socket.TCP_KEEPCNT, 6),
381
+ ]
382
+
383
+
365
384
  def test_socket_options_merge_with_keep_alive(make_client):
366
385
  socket_options = [
367
386
  (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 42),
368
387
  (socket.SOL_TCP, socket.TCP_KEEPINTVL, 42),
369
388
  ]
370
389
 
371
- client = make_client(socket_options=socket_options, keep_alive=True)
390
+ client = make_client(socket_options=socket_options, keep_alive=True, http2=False)
372
391
 
373
392
  options = client.transport._get_pool_options()
374
393
  try:
@@ -386,12 +405,23 @@ def test_socket_options_merge_with_keep_alive(make_client):
386
405
  ]
387
406
 
388
407
 
389
- def test_socket_options_override_defaults(make_client):
408
+ @pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
409
+ def test_socket_options_override_defaults_http2(make_client):
390
410
  # If socket_options are set to [], this doesn't mean the user doesn't want
391
411
  # any custom socket_options, but rather that they want to disable the urllib3
392
412
  # socket option defaults, so we need to set this and not ignore it.
393
413
  client = make_client(socket_options=[])
394
414
 
415
+ options = client.transport._get_pool_options()
416
+ assert options["socket_options"] == KEEP_ALIVE_SOCKET_OPTIONS
417
+
418
+
419
+ def test_socket_options_override_defaults(make_client):
420
+ # If socket_options are set to [], this doesn't mean the user doesn't want
421
+ # any custom socket_options, but rather that they want to disable the urllib3
422
+ # socket option defaults, so we need to set this and not ignore it.
423
+ client = make_client(http2=False, socket_options=[])
424
+
395
425
  options = client.transport._get_pool_options()
396
426
  assert options["socket_options"] == []
397
427
 
@@ -1,236 +0,0 @@
1
- from __future__ import annotations
2
- import io
3
- import logging
4
- import os
5
- import urllib.parse
6
- import urllib.request
7
- import urllib.error
8
- import urllib3
9
- import sys
10
-
11
- from itertools import chain, product
12
-
13
- from typing import TYPE_CHECKING
14
-
15
- if TYPE_CHECKING:
16
- from typing import Any, Callable, Dict, Optional
17
-
18
- from sentry_sdk.utils import (
19
- logger as sentry_logger,
20
- env_to_bool,
21
- capture_internal_exceptions,
22
- )
23
- from sentry_sdk.envelope import Envelope
24
-
25
-
26
- logger = logging.getLogger("spotlight")
27
-
28
-
29
- DEFAULT_SPOTLIGHT_URL = "http://localhost:8969/stream"
30
- DJANGO_SPOTLIGHT_MIDDLEWARE_PATH = "sentry_sdk.spotlight.SpotlightMiddleware"
31
-
32
-
33
- class SpotlightClient:
34
- def __init__(self, url: str) -> None:
35
- self.url = url
36
- self.http = urllib3.PoolManager()
37
- self.fails = 0
38
-
39
- def capture_envelope(self, envelope: Envelope) -> None:
40
- body = io.BytesIO()
41
- envelope.serialize_into(body)
42
- try:
43
- req = self.http.request(
44
- url=self.url,
45
- body=body.getvalue(),
46
- method="POST",
47
- headers={
48
- "Content-Type": "application/x-sentry-envelope",
49
- },
50
- )
51
- req.close()
52
- self.fails = 0
53
- except Exception as e:
54
- if self.fails < 2:
55
- sentry_logger.warning(str(e))
56
- self.fails += 1
57
- elif self.fails == 2:
58
- self.fails += 1
59
- sentry_logger.warning(
60
- "Looks like Spotlight is not running, will keep trying to send events but will not log errors."
61
- )
62
- # omitting self.fails += 1 in the `else:` case intentionally
63
- # to avoid overflowing the variable if Spotlight never becomes reachable
64
-
65
-
66
- try:
67
- from django.utils.deprecation import MiddlewareMixin
68
- from django.http import HttpResponseServerError, HttpResponse, HttpRequest
69
- from django.conf import settings
70
-
71
- SPOTLIGHT_JS_ENTRY_PATH = "/assets/main.js"
72
- SPOTLIGHT_JS_SNIPPET_PATTERN = (
73
- "<script>window.__spotlight = {{ initOptions: {{ sidecarUrl: '{spotlight_url}', fullPage: false }} }};</script>\n"
74
- '<script type="module" crossorigin src="{spotlight_js_url}"></script>\n'
75
- )
76
- SPOTLIGHT_ERROR_PAGE_SNIPPET = (
77
- '<html><base href="{spotlight_url}">\n'
78
- '<script>window.__spotlight = {{ initOptions: {{ fullPage: true, startFrom: "/errors/{event_id}" }}}};</script>\n'
79
- )
80
- CHARSET_PREFIX = "charset="
81
- BODY_TAG_NAME = "body"
82
- BODY_CLOSE_TAG_POSSIBILITIES = tuple(
83
- "</{}>".format("".join(chars))
84
- for chars in product(*zip(BODY_TAG_NAME.upper(), BODY_TAG_NAME.lower()))
85
- )
86
-
87
- class SpotlightMiddleware(MiddlewareMixin): # type: ignore[misc]
88
- _spotlight_script: Optional[str] = None
89
- _spotlight_url: Optional[str] = None
90
-
91
- def __init__(self, get_response: Callable[..., HttpResponse]) -> None:
92
- super().__init__(get_response)
93
-
94
- import sentry_sdk.api
95
-
96
- self.sentry_sdk = sentry_sdk.api
97
-
98
- spotlight_client = self.sentry_sdk.get_client().spotlight
99
- if spotlight_client is None:
100
- sentry_logger.warning(
101
- "Cannot find Spotlight client from SpotlightMiddleware, disabling the middleware."
102
- )
103
- return None
104
- # Spotlight URL has a trailing `/stream` part at the end so split it off
105
- self._spotlight_url = urllib.parse.urljoin(spotlight_client.url, "../")
106
-
107
- @property
108
- def spotlight_script(self) -> Optional[str]:
109
- if self._spotlight_url is not None and self._spotlight_script is None:
110
- try:
111
- spotlight_js_url = urllib.parse.urljoin(
112
- self._spotlight_url, SPOTLIGHT_JS_ENTRY_PATH
113
- )
114
- req = urllib.request.Request(
115
- spotlight_js_url,
116
- method="HEAD",
117
- )
118
- urllib.request.urlopen(req)
119
- self._spotlight_script = SPOTLIGHT_JS_SNIPPET_PATTERN.format(
120
- spotlight_url=self._spotlight_url,
121
- spotlight_js_url=spotlight_js_url,
122
- )
123
- except urllib.error.URLError as err:
124
- sentry_logger.debug(
125
- "Cannot get Spotlight JS to inject at %s. SpotlightMiddleware will not be very useful.",
126
- spotlight_js_url,
127
- exc_info=err,
128
- )
129
-
130
- return self._spotlight_script
131
-
132
- def process_response(
133
- self, _request: HttpRequest, response: HttpResponse
134
- ) -> Optional[HttpResponse]:
135
- content_type_header = tuple(
136
- p.strip()
137
- for p in response.headers.get("Content-Type", "").lower().split(";")
138
- )
139
- content_type = content_type_header[0]
140
- if len(content_type_header) > 1 and content_type_header[1].startswith(
141
- CHARSET_PREFIX
142
- ):
143
- encoding = content_type_header[1][len(CHARSET_PREFIX) :]
144
- else:
145
- encoding = "utf-8"
146
-
147
- if (
148
- self.spotlight_script is not None
149
- and not response.streaming
150
- and content_type == "text/html"
151
- ):
152
- content_length = len(response.content)
153
- injection = self.spotlight_script.encode(encoding)
154
- injection_site = next(
155
- (
156
- idx
157
- for idx in (
158
- response.content.rfind(body_variant.encode(encoding))
159
- for body_variant in BODY_CLOSE_TAG_POSSIBILITIES
160
- )
161
- if idx > -1
162
- ),
163
- content_length,
164
- )
165
-
166
- # This approach works even when we don't have a `</body>` tag
167
- response.content = (
168
- response.content[:injection_site]
169
- + injection
170
- + response.content[injection_site:]
171
- )
172
-
173
- if response.has_header("Content-Length"):
174
- response.headers["Content-Length"] = content_length + len(injection)
175
-
176
- return response
177
-
178
- def process_exception(
179
- self, _request: HttpRequest, exception: Exception
180
- ) -> Optional[HttpResponseServerError]:
181
- if not settings.DEBUG or not self._spotlight_url:
182
- return None
183
-
184
- try:
185
- spotlight = (
186
- urllib.request.urlopen(self._spotlight_url).read().decode("utf-8")
187
- )
188
- except urllib.error.URLError:
189
- return None
190
- else:
191
- event_id = self.sentry_sdk.capture_exception(exception)
192
- return HttpResponseServerError(
193
- spotlight.replace(
194
- "<html>",
195
- SPOTLIGHT_ERROR_PAGE_SNIPPET.format(
196
- spotlight_url=self._spotlight_url, event_id=event_id
197
- ),
198
- )
199
- )
200
-
201
- except ImportError:
202
- settings = None
203
-
204
-
205
- def setup_spotlight(options: Dict[str, Any]) -> Optional[SpotlightClient]:
206
- _handler = logging.StreamHandler(sys.stderr)
207
- _handler.setFormatter(logging.Formatter(" [spotlight] %(levelname)s: %(message)s"))
208
- logger.addHandler(_handler)
209
- logger.setLevel(logging.INFO)
210
-
211
- url = options.get("spotlight")
212
-
213
- if url is True:
214
- url = DEFAULT_SPOTLIGHT_URL
215
-
216
- if not isinstance(url, str):
217
- return None
218
-
219
- with capture_internal_exceptions():
220
- if (
221
- settings is not None
222
- and settings.DEBUG
223
- and env_to_bool(os.environ.get("SENTRY_SPOTLIGHT_ON_ERROR", "1"))
224
- and env_to_bool(os.environ.get("SENTRY_SPOTLIGHT_MIDDLEWARE", "1"))
225
- ):
226
- middleware = settings.MIDDLEWARE
227
- if DJANGO_SPOTLIGHT_MIDDLEWARE_PATH not in middleware:
228
- settings.MIDDLEWARE = type(middleware)(
229
- chain(middleware, (DJANGO_SPOTLIGHT_MIDDLEWARE_PATH,))
230
- )
231
- logger.info("Enabled Spotlight integration for Django")
232
-
233
- client = SpotlightClient(url)
234
- logger.info("Enabled Spotlight using sidecar at %s", url)
235
-
236
- return client
File without changes
File without changes
File without changes