logfire-api 5.2.0__tar.gz → 5.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. {logfire_api-5.2.0 → logfire_api-5.4.0}/PKG-INFO +1 -1
  2. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/__init__.py +6 -0
  3. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/__init__.pyi +2 -1
  4. logfire_api-5.4.0/logfire_api/_internal/agent_sandboxes.pyi +10 -0
  5. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/cli/auth.pyi +5 -1
  6. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/config.pyi +2 -0
  7. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/config_params.pyi +1 -0
  8. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/db_statement_summary.pyi +5 -0
  9. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/formatter.pyi +1 -1
  10. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/claude_agent_sdk.pyi +7 -1
  11. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/fastapi.pyi +26 -3
  12. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/flask.pyi +2 -1
  13. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/openai_agents.pyi +2 -1
  14. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/starlette.pyi +1 -1
  15. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/json_encoder.pyi +4 -0
  16. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/main.pyi +67 -5
  17. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/tracer.pyi +1 -1
  18. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/utils.pyi +13 -0
  19. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/logging.pyi +1 -1
  20. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/structlog.pyi +1 -1
  21. {logfire_api-5.2.0 → logfire_api-5.4.0}/pyproject.toml +1 -1
  22. {logfire_api-5.2.0 → logfire_api-5.4.0}/.gitignore +0 -0
  23. {logfire_api-5.2.0 → logfire_api-5.4.0}/README.md +0 -0
  24. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/__init__.pyi +0 -0
  25. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/ast_utils.pyi +0 -0
  26. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/async_.pyi +0 -0
  27. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/auth.pyi +0 -0
  28. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/auto_trace/__init__.pyi +0 -0
  29. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/auto_trace/import_hook.pyi +0 -0
  30. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/auto_trace/rewrite_ast.pyi +0 -0
  31. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/auto_trace/types.pyi +0 -0
  32. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/baggage.pyi +0 -0
  33. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/cli/__init__.pyi +0 -0
  34. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/cli/ai_tools.pyi +0 -0
  35. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/cli/gateway.pyi +0 -0
  36. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/cli/gateway_auth.pyi +0 -0
  37. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/cli/prompt.pyi +0 -0
  38. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/cli/run.pyi +0 -0
  39. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/cli.pyi +0 -0
  40. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/client.pyi +0 -0
  41. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/collect_system_info.pyi +0 -0
  42. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/constants.pyi +0 -0
  43. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/__init__.pyi +0 -0
  44. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/console.pyi +0 -0
  45. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/dynamic_batch.pyi +0 -0
  46. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/logs.pyi +0 -0
  47. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/otlp.pyi +0 -0
  48. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/processor_wrapper.pyi +0 -0
  49. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/quiet_metrics.pyi +0 -0
  50. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/remove_pending.pyi +0 -0
  51. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/tail_sampling.pyi +0 -0
  52. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/exporters/wrapper.pyi +0 -0
  53. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/forwarding.pyi +0 -0
  54. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/http_transport.pyi +0 -0
  55. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/instrument.pyi +0 -0
  56. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/__init__.pyi +0 -0
  57. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/aiohttp_client.pyi +0 -0
  58. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/aiohttp_server.pyi +0 -0
  59. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/asgi.pyi +0 -0
  60. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/asyncpg.pyi +0 -0
  61. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/aws_lambda.pyi +0 -0
  62. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/celery.pyi +0 -0
  63. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/django.pyi +0 -0
  64. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/dspy.pyi +0 -0
  65. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/executors.pyi +0 -0
  66. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/google_genai.pyi +0 -0
  67. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/httpx.pyi +0 -0
  68. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/litellm.pyi +0 -0
  69. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/litestar.pyi +0 -0
  70. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/mcp.pyi +0 -0
  71. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/monty.pyi +0 -0
  72. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/mysql.pyi +0 -0
  73. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/print.pyi +0 -0
  74. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/psycopg.pyi +0 -0
  75. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/pydantic_ai.pyi +0 -0
  76. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/pymongo.pyi +0 -0
  77. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/pytest.pyi +0 -0
  78. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/redis.pyi +0 -0
  79. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/requests.pyi +0 -0
  80. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/snowflake.pyi +0 -0
  81. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/sqlalchemy.pyi +0 -0
  82. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/sqlite3.pyi +0 -0
  83. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/surrealdb.pyi +0 -0
  84. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/system_metrics.pyi +0 -0
  85. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/integrations/wsgi.pyi +0 -0
  86. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/interactive.pyi +0 -0
  87. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/json_formatter.pyi +0 -0
  88. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/json_schema.pyi +0 -0
  89. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/json_types.pyi +0 -0
  90. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/logs.pyi +0 -0
  91. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/metrics.pyi +0 -0
  92. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/scrubbing.pyi +0 -0
  93. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/server_response.pyi +0 -0
  94. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/stack_info.pyi +0 -0
  95. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/_internal/ulid.pyi +0 -0
  96. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/cli.pyi +0 -0
  97. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/db_api.pyi +0 -0
  98. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/exceptions.pyi +0 -0
  99. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/experimental/__init__.pyi +0 -0
  100. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/experimental/annotations.pyi +0 -0
  101. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/experimental/api_client.pyi +0 -0
  102. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/experimental/datasets/__init__.pyi +0 -0
  103. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/experimental/query_client.pyi +0 -0
  104. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/__init__.pyi +0 -0
  105. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/aiohttp_client.pyi +0 -0
  106. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/flask.pyi +0 -0
  107. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/httpx.pyi +0 -0
  108. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/loguru.pyi +0 -0
  109. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/psycopg.pyi +0 -0
  110. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/pydantic.pyi +0 -0
  111. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/redis.pyi +0 -0
  112. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/sqlalchemy.pyi +0 -0
  113. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/integrations/wsgi.pyi +0 -0
  114. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/propagate.pyi +0 -0
  115. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/py.typed +0 -0
  116. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/query_client.pyi +0 -0
  117. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/sampling/__init__.pyi +0 -0
  118. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/sampling/_tail_sampling.pyi +0 -0
  119. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/types.pyi +0 -0
  120. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/variables/__init__.pyi +0 -0
  121. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/variables/_handlebars.pyi +0 -0
  122. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/variables/abstract.pyi +0 -0
  123. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/variables/composition.pyi +0 -0
  124. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/variables/config.pyi +0 -0
  125. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/variables/local.pyi +0 -0
  126. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/variables/remote.pyi +0 -0
  127. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/variables/template_validation.pyi +0 -0
  128. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/variables/variable.pyi +0 -0
  129. {logfire_api-5.2.0 → logfire_api-5.4.0}/logfire_api/version.pyi +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: logfire-api
3
- Version: 5.2.0
3
+ Version: 5.4.0
4
4
  Summary: Shim for the Logfire SDK which does nothing unless Logfire is installed
5
5
  Author-email: Pydantic Team <engineering@pydantic.dev>, Samuel Colvin <samuel@pydantic.dev>, Hasan Ramezani <hasan@pydantic.dev>, Adrian Garcia Badaracco <adrian@pydantic.dev>, David Montague <david@pydantic.dev>, Marcelo Trylesinski <marcelo@pydantic.dev>, David Hewitt <david.hewitt@pydantic.dev>, Alex Hall <alex@pydantic.dev>
6
6
  License-Expression: MIT
@@ -155,6 +155,11 @@ except ImportError:
155
155
 
156
156
  def instrument_monty(self, *args, **kwargs) -> None: ...
157
157
 
158
+ def agent_sandboxes(self, *args, **kwargs) -> Any:
159
+ raise RuntimeError(
160
+ "`logfire.agent_sandboxes()` requires the `logfire` package, install it with `pip install 'logfire[agent-sandboxes]'`"
161
+ )
162
+
158
163
  def instrument_pymongo(self, *args, **kwargs) -> None: ...
159
164
 
160
165
  def instrument_sqlalchemy(self, *args, **kwargs) -> None: ...
@@ -247,6 +252,7 @@ except ImportError:
247
252
  instrument_pydantic = DEFAULT_LOGFIRE_INSTANCE.instrument_pydantic
248
253
  instrument_pydantic_ai = DEFAULT_LOGFIRE_INSTANCE.instrument_pydantic_ai
249
254
  instrument_monty = DEFAULT_LOGFIRE_INSTANCE.instrument_monty
255
+ agent_sandboxes = DEFAULT_LOGFIRE_INSTANCE.agent_sandboxes
250
256
  instrument_fastapi = DEFAULT_LOGFIRE_INSTANCE.instrument_fastapi
251
257
  instrument_openai = DEFAULT_LOGFIRE_INSTANCE.instrument_openai
252
258
  instrument_openai_agents = DEFAULT_LOGFIRE_INSTANCE.instrument_openai_agents
@@ -16,7 +16,7 @@ from logfire.propagate import attach_context as attach_context, get_context as g
16
16
  from logfire.sampling import SamplingOptions as SamplingOptions
17
17
  from typing import Any
18
18
 
19
- __all__ = ['Logfire', 'LogfireSpan', 'LevelName', 'AdvancedOptions', 'ConsoleOptions', 'CodeSource', 'PydanticPlugin', 'configure', 'span', 'instrument', 'log', 'trace', 'debug', 'notice', 'info', 'warn', 'warning', 'error', 'exception', 'fatal', 'force_flush', 'log_slow_async_callbacks', 'install_auto_tracing', 'instrument_asgi', 'instrument_wsgi', 'instrument_pydantic', 'instrument_pydantic_ai', 'instrument_monty', 'instrument_fastapi', 'instrument_openai', 'instrument_openai_agents', 'instrument_anthropic', 'instrument_google_genai', 'instrument_litellm', 'instrument_dspy', 'instrument_print', 'instrument_asyncpg', 'instrument_httpx', 'instrument_celery', 'instrument_requests', 'instrument_psycopg', 'instrument_django', 'instrument_flask', 'instrument_starlette', 'instrument_litestar', 'instrument_aiohttp_client', 'instrument_aiohttp_server', 'instrument_sqlalchemy', 'instrument_sqlite3', 'instrument_aws_lambda', 'instrument_redis', 'instrument_pymongo', 'instrument_mysql', 'instrument_surrealdb', 'instrument_snowflake', 'instrument_system_metrics', 'instrument_mcp', 'instrument_claude_agent_sdk', 'AutoTraceModule', 'with_tags', 'with_settings', 'suppress_scopes', 'shutdown', 'no_auto_trace', 'ScrubMatch', 'ScrubbingOptions', 'VERSION', 'add_non_user_code_prefix', 'suppress_instrumentation', 'StructlogProcessor', 'LogfireLoggingHandler', 'loguru_handler', 'SamplingOptions', 'MetricsOptions', 'VariablesOptions', 'LocalVariablesOptions', 'variables', 'var', 'template_var', 'variables_get', 'variables_push', 'variables_push_types', 'variables_validate', 'variables_push_config', 'variables_pull_config', 'variables_build_config', 'logfire_info', 'get_baggage', 'set_baggage', 'get_context', 'attach_context', 'url_from_eval', 'forward_export_request', 'forward_export_request_starlette']
19
+ __all__ = ['Logfire', 'LogfireSpan', 'LevelName', 'AdvancedOptions', 'ConsoleOptions', 'CodeSource', 'PydanticPlugin', 'configure', 'span', 'instrument', 'log', 'trace', 'debug', 'notice', 'info', 'warn', 'warning', 'error', 'exception', 'fatal', 'force_flush', 'log_slow_async_callbacks', 'install_auto_tracing', 'instrument_asgi', 'instrument_wsgi', 'instrument_pydantic', 'instrument_pydantic_ai', 'instrument_monty', 'agent_sandboxes', 'instrument_fastapi', 'instrument_openai', 'instrument_openai_agents', 'instrument_anthropic', 'instrument_google_genai', 'instrument_litellm', 'instrument_dspy', 'instrument_print', 'instrument_asyncpg', 'instrument_httpx', 'instrument_celery', 'instrument_requests', 'instrument_psycopg', 'instrument_django', 'instrument_flask', 'instrument_starlette', 'instrument_litestar', 'instrument_aiohttp_client', 'instrument_aiohttp_server', 'instrument_sqlalchemy', 'instrument_sqlite3', 'instrument_aws_lambda', 'instrument_redis', 'instrument_pymongo', 'instrument_mysql', 'instrument_surrealdb', 'instrument_snowflake', 'instrument_system_metrics', 'instrument_mcp', 'instrument_claude_agent_sdk', 'AutoTraceModule', 'with_tags', 'with_settings', 'suppress_scopes', 'shutdown', 'no_auto_trace', 'ScrubMatch', 'ScrubbingOptions', 'VERSION', 'add_non_user_code_prefix', 'suppress_instrumentation', 'StructlogProcessor', 'LogfireLoggingHandler', 'loguru_handler', 'SamplingOptions', 'MetricsOptions', 'VariablesOptions', 'LocalVariablesOptions', 'variables', 'var', 'template_var', 'variables_get', 'variables_push', 'variables_push_types', 'variables_validate', 'variables_push_config', 'variables_pull_config', 'variables_build_config', 'logfire_info', 'get_baggage', 'set_baggage', 'get_context', 'attach_context', 'url_from_eval', 'forward_export_request', 'forward_export_request_starlette']
20
20
 
21
21
  DEFAULT_LOGFIRE_INSTANCE = Logfire()
22
22
  span = DEFAULT_LOGFIRE_INSTANCE.span
@@ -27,6 +27,7 @@ install_auto_tracing = DEFAULT_LOGFIRE_INSTANCE.install_auto_tracing
27
27
  instrument_pydantic = DEFAULT_LOGFIRE_INSTANCE.instrument_pydantic
28
28
  instrument_pydantic_ai = DEFAULT_LOGFIRE_INSTANCE.instrument_pydantic_ai
29
29
  instrument_monty = DEFAULT_LOGFIRE_INSTANCE.instrument_monty
30
+ agent_sandboxes = DEFAULT_LOGFIRE_INSTANCE.agent_sandboxes
30
31
  instrument_asgi = DEFAULT_LOGFIRE_INSTANCE.instrument_asgi
31
32
  instrument_wsgi = DEFAULT_LOGFIRE_INSTANCE.instrument_wsgi
32
33
  instrument_fastapi = DEFAULT_LOGFIRE_INSTANCE.instrument_fastapi
@@ -0,0 +1,10 @@
1
+ from collections.abc import Callable, Mapping as Mapping
2
+ from logfire import Logfire as Logfire
3
+ from logfire.exceptions import LogfireConfigError as LogfireConfigError
4
+ from logfire.propagate import get_context as get_context
5
+ from pydantic_monty import AsyncMontyWebsocket
6
+ from typing import Any
7
+
8
+ def agent_sandboxes_url(base_url: str) -> str:
9
+ """Convert a Logfire HTTP(S) base URL into the agent sandboxes WebSocket URL."""
10
+ def create_agent_sandboxes(logfire_instance: Logfire, *, api_key: str | None, url: str | None, connect_headers: Callable[[], Mapping[str, str]] | None = None, **kwargs: Any) -> AsyncMontyWebsocket: ...
@@ -10,4 +10,8 @@ def parse_auth(args: argparse.Namespace) -> None:
10
10
  This will authenticate your machine with Logfire and store the credentials.
11
11
  """
12
12
  def parse_logout(args: argparse.Namespace) -> None:
13
- """Log out from Logfire."""
13
+ """Log out from Logfire.
14
+
15
+ Remove stored user tokens for --region, --base-url, or a non-empty LOGFIRE_BASE_URL.
16
+ With no target configured, remove all stored user tokens.
17
+ """
@@ -45,6 +45,7 @@ from opentelemetry.sdk.metrics.export import MetricReader as MetricReader
45
45
  from opentelemetry.sdk.metrics.view import View
46
46
  from opentelemetry.sdk.resources import ResourceDetector
47
47
  from opentelemetry.sdk.trace import SpanProcessor
48
+ from opentelemetry.sdk.trace.export import SpanExporter as SpanExporter
48
49
  from opentelemetry.sdk.trace.id_generator import IdGenerator
49
50
  from pathlib import Path
50
51
  from typing import Any, ClassVar, Literal, TextIO
@@ -80,6 +81,7 @@ class AdvancedOptions:
80
81
  server_response_hook: ServerResponseCallback | None = ...
81
82
  resource_detectors: Sequence[ResourceDetector | str] | None = ...
82
83
  compression: CompressionValues | None = ...
84
+ pending_spans: bool | None = ...
83
85
  def generate_base_url(self, token: str, warn_unknown_region: bool = True) -> str:
84
86
  """Resolve the base API URL for `token`, honouring an explicitly configured `base_url`.
85
87
 
@@ -58,6 +58,7 @@ IGNORE_NO_CONFIG: Incomplete
58
58
  BASE_URL: Incomplete
59
59
  DISTRIBUTED_TRACING: Incomplete
60
60
  EMIT_CONFIGURATION_SPAN: Incomplete
61
+ PENDING_SPANS: Incomplete
61
62
  COMPRESSION: Incomplete
62
63
  HTTPX_CAPTURE_ALL: Incomplete
63
64
  AIOHTTP_CLIENT_CAPTURE_ALL: Incomplete
@@ -26,6 +26,11 @@ def summarize_query(db_statement: str) -> str | None:
26
26
 
27
27
  """
28
28
  def select(expr: str, table: str, *, match_end: int, db_statement: str, ctes: str | None = None, sub_query: str | None = None) -> str: ...
29
+ def outside_parentheses(s: str) -> str:
30
+ """Remove everything inside parentheses, including the parentheses themselves.
31
+
32
+ Parentheses inside quoted strings or identifiers don't change the nesting depth.
33
+ """
29
34
  def truncate(s: str, length: int) -> str: ...
30
35
 
31
36
  FALLBACK_HALF: Incomplete
@@ -28,7 +28,7 @@ class ChunksFormatter(Formatter):
28
28
  chunks_formatter: Incomplete
29
29
 
30
30
  def logfire_format(format_string: str, kwargs: dict[str, Any], scrubber: BaseScrubber) -> str: ...
31
- def logfire_format_with_magic(format_string: str, kwargs: dict[str, Any], scrubber: BaseScrubber, fstring_frame: types.FrameType | None = None) -> tuple[str, dict[str, Any], str]: ...
31
+ def logfire_format_with_magic(format_string: Any, kwargs: dict[str, Any], scrubber: BaseScrubber, fstring_frame: types.FrameType | None = None) -> tuple[str, dict[str, Any], str]: ...
32
32
  @lru_cache
33
33
  def compile_formatted_value(node: ast.FormattedValue, ex_source: executing.Source) -> tuple[str, CodeType, CodeType]:
34
34
  """Returns three things that can be expensive to compute.
@@ -2,7 +2,7 @@ from _typeshed import Incomplete
2
2
  from claude_agent_sdk import AssistantMessage
3
3
  from claude_agent_sdk.types import HookContext, SyncHookJSONOutput
4
4
  from contextlib import AbstractContextManager
5
- from logfire._internal.integrations.llm_providers.semconv import CONVERSATION_ID as CONVERSATION_ID, ChatMessage as ChatMessage, ERROR_TYPE as ERROR_TYPE, INPUT_MESSAGES as INPUT_MESSAGES, MessagePart as MessagePart, OPERATION_NAME as OPERATION_NAME, OUTPUT_MESSAGES as OUTPUT_MESSAGES, OutputMessage as OutputMessage, PROVIDER_NAME as PROVIDER_NAME, REQUEST_MODEL as REQUEST_MODEL, RESPONSE_MODEL as RESPONSE_MODEL, ReasoningPart as ReasoningPart, SYSTEM as SYSTEM, SYSTEM_INSTRUCTIONS as SYSTEM_INSTRUCTIONS, TOOL_CALL_ARGUMENTS as TOOL_CALL_ARGUMENTS, TOOL_CALL_ID as TOOL_CALL_ID, TOOL_CALL_RESULT as TOOL_CALL_RESULT, TOOL_NAME as TOOL_NAME, TextPart as TextPart, ToolCallPart as ToolCallPart, ToolCallResponsePart as ToolCallResponsePart
5
+ from logfire._internal.integrations.llm_providers.semconv import CONVERSATION_ID as CONVERSATION_ID, ChatMessage as ChatMessage, ERROR_TYPE as ERROR_TYPE, INPUT_MESSAGES as INPUT_MESSAGES, MessagePart as MessagePart, OPERATION_NAME as OPERATION_NAME, OUTPUT_MESSAGES as OUTPUT_MESSAGES, OutputMessage as OutputMessage, PROVIDER_NAME as PROVIDER_NAME, REQUEST_MODEL as REQUEST_MODEL, RESPONSE_FINISH_REASONS as RESPONSE_FINISH_REASONS, RESPONSE_ID as RESPONSE_ID, RESPONSE_MODEL as RESPONSE_MODEL, ReasoningPart as ReasoningPart, SYSTEM as SYSTEM, SYSTEM_INSTRUCTIONS as SYSTEM_INSTRUCTIONS, TOOL_CALL_ARGUMENTS as TOOL_CALL_ARGUMENTS, TOOL_CALL_ID as TOOL_CALL_ID, TOOL_CALL_RESULT as TOOL_CALL_RESULT, TOOL_NAME as TOOL_NAME, TextPart as TextPart, ToolCallPart as ToolCallPart, ToolCallResponsePart as ToolCallResponsePart
6
6
  from logfire._internal.main import Logfire as Logfire, LogfireSpan as LogfireSpan
7
7
  from logfire._internal.stack_info import get_user_stack_info as get_user_stack_info
8
8
  from logfire._internal.utils import handle_internal_errors as handle_internal_errors
@@ -63,5 +63,11 @@ class _ConversationState:
63
63
  """Handle UserMessage: open a new chat span for the next LLM call."""
64
64
  def handle_assistant_message(self, message: AssistantMessage) -> None:
65
65
  """Handle AssistantMessage: add output and usage to the current chat span."""
66
+ def set_finish_reason(self, stop_reason: str | None) -> None:
67
+ """Record the stop reason on the current chat span.
68
+
69
+ The CLI streams assistant messages with a null `stop_reason`;
70
+ the final one is only reported on the ResultMessage.
71
+ """
66
72
  def close(self) -> None:
67
73
  """Close chat span and end any orphaned tool spans."""
@@ -1,3 +1,4 @@
1
+ import dataclasses
1
2
  from ..constants import ONE_SECOND_IN_NANOSECONDS as ONE_SECOND_IN_NANOSECONDS
2
3
  from ..main import Logfire as Logfire, NoopSpan as NoopSpan, set_user_attributes_on_raw_span as set_user_attributes_on_raw_span
3
4
  from ..stack_info import StackInfo as StackInfo, get_code_object_info as get_code_object_info
@@ -8,21 +9,43 @@ from collections.abc import Awaitable, Callable, Iterable
8
9
  from contextlib import AbstractContextManager, contextmanager
9
10
  from fastapi import FastAPI
10
11
  from functools import lru_cache
12
+ from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
11
13
  from opentelemetry.trace import Span
12
14
  from starlette.requests import Request
15
+ from starlette.types import Receive, Scope, Send
13
16
  from starlette.websockets import WebSocket
14
17
  from typing import Any
18
+ from weakref import WeakKeyDictionary
15
19
 
16
20
  def find_mounted_apps(app: FastAPI) -> list[FastAPI]:
17
21
  """Fetch all sub-apps mounted to a FastAPI app, including nested sub-apps."""
18
- def instrument_fastapi(logfire_instance: Logfire, app: FastAPI, *, capture_headers: bool = False, request_attributes_mapper: Callable[[Request | WebSocket, dict[str, Any]], dict[str, Any] | None] | None = None, excluded_urls: str | Iterable[str] | None = None, record_send_receive: bool = False, extra_spans: bool = False, **opentelemetry_kwargs: Any) -> AbstractContextManager[None]:
22
+ def instrument_fastapi(logfire_instance: Logfire, app: FastAPI | None = None, *, capture_headers: bool = False, request_attributes_mapper: Callable[[Request | WebSocket, dict[str, Any]], dict[str, Any] | None] | None = None, excluded_urls: str | Iterable[str] | None = None, record_send_receive: bool = False, extra_spans: bool = False, **opentelemetry_kwargs: Any) -> AbstractContextManager[None]:
19
23
  """Instrument a FastAPI app so that spans and logs are automatically created for each request.
20
24
 
21
25
  See `Logfire.instrument_fastapi` for more details.
22
26
  """
27
+
28
+ class OncePerRequest:
29
+ """Run only the outermost FastAPI OpenTelemetry middleware for each ASGI request.
30
+
31
+ This way mounted apps don't start duplicate spans for the same request,
32
+ and they don't trace requests that were excluded by their outer app.
33
+ """
34
+ app: Incomplete
35
+ def __init__(self, app: OpenTelemetryMiddleware) -> None: ...
36
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: ...
37
+
38
+ @dataclasses.dataclass
39
+ class _FastAPIRegistry:
40
+ """Track Logfire instrumentation settings for FastAPI apps."""
41
+ global_instrumentation: FastAPIInstrumentation | None = ...
42
+ per_app: WeakKeyDictionary[FastAPI, FastAPIInstrumentation] = dataclasses.field(default_factory=Incomplete)
43
+ def get_instrumentation(self, app: FastAPI) -> FastAPIInstrumentation | None:
44
+ """Get the instrumentation for a specific app, or the global instrumentation if none is set."""
45
+
23
46
  @lru_cache
24
- def patch_fastapi():
25
- """Globally monkeypatch fastapi functions and return a dictionary for recording instrumentation config per app."""
47
+ def patch_fastapi() -> _FastAPIRegistry:
48
+ """Globally monkeypatch fastapi functions and return their instrumentation registry."""
26
49
 
27
50
  class FastAPIInstrumentation:
28
51
  logfire_instance: Incomplete
@@ -1,9 +1,10 @@
1
1
  from flask.app import Flask
2
+ from logfire import Logfire as Logfire
2
3
  from logfire._internal.utils import maybe_capture_server_headers as maybe_capture_server_headers
3
4
  from logfire.integrations.flask import CommenterOptions as CommenterOptions, RequestHook as RequestHook, ResponseHook as ResponseHook
4
5
  from typing import Any
5
6
 
6
- def instrument_flask(app: Flask, *, capture_headers: bool, enable_commenter: bool, commenter_options: CommenterOptions | None, excluded_urls: str | None = None, request_hook: RequestHook | None = None, response_hook: ResponseHook | None = None, **kwargs: Any):
7
+ def instrument_flask(logfire_instance: Logfire, app: Flask | None = None, *, capture_headers: bool = False, enable_commenter: bool = True, commenter_options: CommenterOptions | None = None, excluded_urls: str | None = None, request_hook: RequestHook | None = None, response_hook: ResponseHook | None = None, **kwargs: Any) -> None:
7
8
  """Instrument `app` so that spans are automatically created for each request.
8
9
 
9
10
  See the `Logfire.instrument_flask` method for details.
@@ -7,7 +7,8 @@ from agents.tracing.spans import SpanError, TSpanData
7
7
  from dataclasses import dataclass
8
8
  from logfire import Logfire as Logfire, LogfireSpan as LogfireSpan
9
9
  from logfire._internal.formatter import logfire_format as logfire_format
10
- from logfire._internal.integrations.llm_providers.openai import get_openai_usage_attributes as get_openai_usage_attributes, inputs_to_events as inputs_to_events, responses_output_events as responses_output_events
10
+ from logfire._internal.integrations.llm_providers.openai import get_openai_usage_attributes as get_openai_usage_attributes, inputs_to_events as inputs_to_events, responses_finish_reasons as responses_finish_reasons, responses_output_events as responses_output_events
11
+ from logfire._internal.integrations.llm_providers.semconv import RESPONSE_FINISH_REASONS as RESPONSE_FINISH_REASONS, RESPONSE_ID as RESPONSE_ID
11
12
  from logfire._internal.scrubbing import NOOP_SCRUBBER as NOOP_SCRUBBER
12
13
  from logfire._internal.utils import handle_internal_errors as handle_internal_errors, log_internal_error as log_internal_error, truncate_string as truncate_string
13
14
  from openai.types.responses import Response
@@ -5,7 +5,7 @@ from opentelemetry.instrumentation.asgi.types import ClientRequestHook, ClientRe
5
5
  from starlette.applications import Starlette
6
6
  from typing import Any
7
7
 
8
- def instrument_starlette(logfire_instance: Logfire, app: Starlette, *, record_send_receive: bool = False, capture_headers: bool = False, server_request_hook: ServerRequestHook | None = None, client_request_hook: ClientRequestHook | None = None, client_response_hook: ClientResponseHook | None = None, **kwargs: Any):
8
+ def instrument_starlette(logfire_instance: Logfire, app: Starlette | None = None, *, record_send_receive: bool = False, capture_headers: bool = False, server_request_hook: ServerRequestHook | None = None, client_request_hook: ClientRequestHook | None = None, client_response_hook: ClientResponseHook | None = None, **kwargs: Any) -> None:
9
9
  """Instrument `app` so that spans are automatically created for each request.
10
10
 
11
11
  See the `Logfire.instrument_starlette` method for details.
@@ -4,6 +4,10 @@ from functools import cache, lru_cache
4
4
  from typing import Any
5
5
 
6
6
  NUMPY_DIMENSION_MAX_SIZE: int
7
+
8
+ def pandas_display_slices(count: int, limit: int | None) -> tuple[slice, ...]:
9
+ """Return the first and last positions selected by a pandas display limit."""
10
+
7
11
  EncoderFunction: Incomplete
8
12
 
9
13
  @cache
@@ -40,6 +40,7 @@ from anthropic.lib.bedrock import AnthropicBedrock as _AnthropicBedrock, AsyncAn
40
40
  from collections.abc import Iterable, Mapping, Sequence
41
41
  from contextlib import AbstractContextManager
42
42
  from django.http import HttpRequest as HttpRequest, HttpResponse as HttpResponse
43
+ from enum import Enum
43
44
  from fastapi import FastAPI
44
45
  from flask.app import Flask
45
46
  from litestar import Litestar
@@ -50,6 +51,7 @@ from opentelemetry.sdk.trace import ReadableSpan, Span
50
51
  from opentelemetry.trace import SpanContext, SpanKind
51
52
  from opentelemetry.util import types as otel_types
52
53
  from pydantic_evals.reporting import EvaluationReport
54
+ from pydantic_monty import AsyncMontyWebsocket
53
55
  from pymongo.monitoring import CommandFailedEvent as CommandFailedEvent, CommandStartedEvent as CommandStartedEvent, CommandSucceededEvent as CommandSucceededEvent
54
56
  from snowflake.connector.connection import SnowflakeConnection
55
57
  from sqlalchemy import Engine
@@ -69,6 +71,9 @@ ExcInfo = SysExcInfo | BaseException | bool | None
69
71
  T = TypeVar('T')
70
72
  InputsT = TypeVar('InputsT')
71
73
 
74
+ class _Unset(Enum):
75
+ UNSET: str
76
+
72
77
  class Logfire:
73
78
  """The main logfire class."""
74
79
  def __init__(self, *, config: LogfireConfig = ..., sample_rate: float | None = None, tags: Sequence[str] = (), console_log: bool = True, otel_scope: str = 'logfire') -> None: ...
@@ -244,7 +249,8 @@ class Logfire:
244
249
  ```
245
250
 
246
251
  Args:
247
- msg_template: The template for the span message.
252
+ msg_template: A string template for the span message. Passing another type emits a formatting
253
+ warning and uses its `str()` representation without interpolating it.
248
254
  _span_name: The span name. If not provided, the `msg_template` will be used.
249
255
  _tags: An optional sequence of tags to include in the span.
250
256
  _level: An optional log level name.
@@ -313,7 +319,8 @@ class Logfire:
313
319
 
314
320
  Args:
315
321
  level: The level of the log.
316
- msg_template: The message to log.
322
+ msg_template: A string message or template. Passing another type emits a formatting warning
323
+ and uses its `str()` representation without interpolating it.
317
324
  attributes: The attributes to bind to the log.
318
325
  tags: An optional sequence of tags to include in the log.
319
326
  exc_info: Set to an exception or a tuple as returned by [`sys.exc_info()`][sys.exc_info]
@@ -520,6 +527,57 @@ class Logfire:
520
527
  It records Monty sessions, executed code, inputs, outputs, external calls,
521
528
  exceptions, printed text, and pool metrics. Recorded values are subject to Logfire's configured scrubbing.
522
529
  """
530
+ def agent_sandboxes(self, *, api_key: str | None = None, url: str | None = None, max_processes: int | None | _Unset = ..., checkout_timeout: float | None | _Unset = ..., request_timeout: float | None | _Unset = ..., connect_headers: Callable[[], Mapping[str, str]] | None | _Unset = ..., feed_duration_limit_grace: float | None | _Unset = ..., turn_duration_limit_grace: float | None | _Unset = ..., auto_resume: bool | _Unset = ..., **kwargs: Any) -> AsyncMontyWebsocket:
531
+ """Connect to Logfire Agent Sandboxes, remote Pydantic Monty workers hosted by Logfire.
532
+
533
+ Requires the `agent-sandboxes` extra, e.g. `pip install 'logfire[agent-sandboxes]'`.
534
+
535
+ Returns a [`pydantic_monty.AsyncMontyWebsocket`][pydantic_monty.AsyncMontyWebsocket] pool;
536
+ use it as an async context manager and check out sessions from it:
537
+
538
+ ```py
539
+ import logfire
540
+
541
+ logfire.configure()
542
+
543
+
544
+ async def main():
545
+ async with logfire.agent_sandboxes() as pool:
546
+ async with pool.checkout() as session:
547
+ result = await session.feed_run('1 + 1')
548
+ ```
549
+
550
+ No connection is made until a session is checked out.
551
+
552
+ The Logfire platform records sandbox usage itself. The current trace context is sent
553
+ with each session so those spans join the caller's trace.
554
+
555
+ Omitted pool options use the defaults of the installed `pydantic-monty-client` version.
556
+ The defaults described below are the currently assumed defaults and may change in future versions.
557
+
558
+ Args:
559
+ api_key: A Logfire API key with the `project:execute_agent_sandboxes` scope.
560
+ Defaults to the `api_key` passed to [`configure()`][logfire.configure],
561
+ then the `LOGFIRE_API_KEY` environment variable.
562
+ url: The WebSocket URL of the sandboxes server.
563
+ Defaults to the Logfire region the API key belongs to.
564
+ max_processes: Cap on concurrent sandbox connections. Defaults to `None`, which uses
565
+ the CPU count; checkouts beyond it wait.
566
+ checkout_timeout: Seconds `checkout()` waits for capacity before raising `TimeoutError`.
567
+ Defaults to `None`, which waits forever.
568
+ request_timeout: Hard per-turn deadline in seconds. A sandbox that exceeds it has its
569
+ connection closed and the call raises `MontyCrashedError`. `None` waits indefinitely.
570
+ Defaults to `10.0`. Raise this when installing dependencies in a sandbox.
571
+ connect_headers: Called once per session to produce extra headers for the WebSocket
572
+ connection. These are merged with the `Authorization` header and win on conflicts.
573
+ Defaults to `None`, which adds no extra headers beyond Logfire authentication.
574
+ feed_duration_limit_grace: Seconds to wait past a feed's `max_feed_duration_secs`
575
+ before closing the sandbox. Defaults to `1.0`; `None` disables this backstop.
576
+ turn_duration_limit_grace: The same, for `max_turn_duration_secs`. Defaults to `1.0`.
577
+ auto_resume: When the server drains a stored session, transparently resume it on
578
+ another server instead of raising `MontyShutdown`. Defaults to `True`.
579
+ kwargs: Additional keyword arguments passed to `AsyncMontyWebsocket` for future compatibility.
580
+ """
523
581
  def instrument_fastapi(self, app: FastAPI, *, capture_headers: bool = False, request_attributes_mapper: Callable[[Request | WebSocket, dict[str, Any]], dict[str, Any] | None] | None = None, excluded_urls: str | Iterable[str] | None = None, record_send_receive: bool = False, extra_spans: bool = False, **opentelemetry_kwargs: Any) -> AbstractContextManager[None]:
524
582
  """Instrument a FastAPI app so that spans and logs are automatically created for each request.
525
583
 
@@ -590,7 +648,7 @@ class Logfire:
590
648
  logfire.instrument_openai(client)
591
649
 
592
650
  response = client.chat.completions.create(
593
- model=\'gpt-4\',
651
+ model=\'gpt-5-mini\',
594
652
  messages=[
595
653
  {\'role\': \'system\', \'content\': \'You are a helpful assistant.\'},
596
654
  {\'role\': \'user\', \'content\': \'What is four plus five?\'},
@@ -641,7 +699,7 @@ class Logfire:
641
699
 
642
700
  - [`client.messages.create`](https://docs.anthropic.com/en/api/messages)
643
701
  - [`client.messages.stream`](https://docs.anthropic.com/en/api/messages-streaming)
644
- - [`client.beta.tools.messages.create`](https://docs.anthropic.com/en/docs/tool-use)
702
+ - [`client.beta.messages.create`](https://docs.anthropic.com/en/docs/tool-use)
645
703
 
646
704
  When `stream=True` a second span is created to instrument the streamed response.
647
705
 
@@ -658,7 +716,7 @@ class Logfire:
658
716
  logfire.instrument_anthropic(client)
659
717
 
660
718
  response = client.messages.create(
661
- model=\'claude-3-haiku-20240307\',
719
+ model=\'claude-haiku-5-5\',
662
720
  system=\'You are a helpful assistant.\',
663
721
  messages=[
664
722
  {\'role\': \'user\', \'content\': \'What is four plus five?\'},
@@ -938,6 +996,10 @@ class Logfire:
938
996
  [OpenTelemetry SQLAlchemy Instrumentation](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/sqlalchemy/sqlalchemy.html)
939
997
  library, specifically `SQLAlchemyInstrumentor().instrument()`, to which it passes `**kwargs`.
940
998
 
999
+ If the installed SQLAlchemy version is outside the range that instrumentation supports, this raises
1000
+ `RuntimeError` instead of returning without recording queries.
1001
+ Pass `skip_dep_check=True` to bypass this check. That may produce no spans or errors if the version really is incompatible.
1002
+
941
1003
  Args:
942
1004
  engine: The `sqlalchemy` engine to instrument.
943
1005
  engines: An iterable of `sqlalchemy` engines to instrument.
@@ -2,7 +2,7 @@ import opentelemetry.trace as trace_api
2
2
  from ..types import ExceptionCallback as ExceptionCallback
3
3
  from .config import LogfireConfig as LogfireConfig
4
4
  from .constants import ATTRIBUTES_EXCEPTION_FINGERPRINT_KEY as ATTRIBUTES_EXCEPTION_FINGERPRINT_KEY, ATTRIBUTES_MESSAGE_KEY as ATTRIBUTES_MESSAGE_KEY, ATTRIBUTES_MESSAGE_TEMPLATE_KEY as ATTRIBUTES_MESSAGE_TEMPLATE_KEY, ATTRIBUTES_PENDING_SPAN_REAL_PARENT_KEY as ATTRIBUTES_PENDING_SPAN_REAL_PARENT_KEY, ATTRIBUTES_SAMPLE_RATE_KEY as ATTRIBUTES_SAMPLE_RATE_KEY, ATTRIBUTES_SPAN_TYPE_KEY as ATTRIBUTES_SPAN_TYPE_KEY, ATTRIBUTES_VALIDATION_ERROR_KEY as ATTRIBUTES_VALIDATION_ERROR_KEY, log_level_attributes as log_level_attributes
5
- from .utils import handle_internal_errors as handle_internal_errors, sha256_string as sha256_string
5
+ from .utils import handle_internal_errors as handle_internal_errors, is_instrumentation_suppressed as is_instrumentation_suppressed, safe_str as safe_str, safe_type_name as safe_type_name, sha256_string as sha256_string
6
6
  from _typeshed import Incomplete
7
7
  from collections.abc import Callable, Mapping, Sequence
8
8
  from dataclasses import dataclass, field
@@ -32,6 +32,19 @@ def uniquify_sequence(seq: Sequence[T]) -> tuple[T, ...]:
32
32
  """Remove duplicates from a sequence preserving order."""
33
33
  def safe_repr(obj: Any) -> str:
34
34
  """Return some kind of non-empty string representation of an object, catching exceptions."""
35
+ def safe_str(obj: Any) -> str:
36
+ """Return `str(obj)`, or a placeholder if calling `str()` itself raises.
37
+
38
+ Some objects (notably exceptions that were never fully initialised) raise from `__str__`.
39
+ Callers on the telemetry path must never let that abort their own work, so the placeholder
40
+ deliberately avoids looking anything up on the object or its class.
41
+ """
42
+ def safe_type_name(obj: Any) -> str:
43
+ """Return the bare class name of `obj`, or a placeholder if that lookup raises.
44
+
45
+ A metaclass can turn `__name__` into a property that raises, so even reading the class
46
+ name is not safe on the telemetry path.
47
+ """
35
48
  Truncatable = TypeVar('Truncatable', str, bytes, 'list[Any]', 'tuple[Any, ...]')
36
49
 
37
50
  def truncate_string(s: str, *, max_length: int, middle: str = '...') -> str:
@@ -1,5 +1,5 @@
1
1
  from .. import Logfire as Logfire
2
- from .._internal.constants import ATTRIBUTES_LOGGING_ARGS_KEY as ATTRIBUTES_LOGGING_ARGS_KEY, ATTRIBUTES_LOGGING_NAME as ATTRIBUTES_LOGGING_NAME, ATTRIBUTES_MESSAGE_KEY as ATTRIBUTES_MESSAGE_KEY, ATTRIBUTES_MESSAGE_TEMPLATE_KEY as ATTRIBUTES_MESSAGE_TEMPLATE_KEY, LOGGING_TO_OTEL_LEVEL_NUMBERS as LOGGING_TO_OTEL_LEVEL_NUMBERS
2
+ from .._internal.constants import ATTRIBUTES_LOGGING_ARGS_KEY as ATTRIBUTES_LOGGING_ARGS_KEY, ATTRIBUTES_LOGGING_NAME as ATTRIBUTES_LOGGING_NAME, ATTRIBUTES_MESSAGE_KEY as ATTRIBUTES_MESSAGE_KEY, ATTRIBUTES_MESSAGE_TEMPLATE_KEY as ATTRIBUTES_MESSAGE_TEMPLATE_KEY, ATTRIBUTES_TAGS_KEY as ATTRIBUTES_TAGS_KEY, LOGGING_TO_OTEL_LEVEL_NUMBERS as LOGGING_TO_OTEL_LEVEL_NUMBERS
3
3
  from .._internal.utils import is_instrumentation_suppressed as is_instrumentation_suppressed
4
4
  from _typeshed import Incomplete
5
5
  from collections.abc import Mapping as Mapping
@@ -1,5 +1,5 @@
1
1
  from .. import Logfire as Logfire
2
- from .._internal.constants import ATTRIBUTES_MESSAGE_KEY as ATTRIBUTES_MESSAGE_KEY
2
+ from .._internal.constants import ATTRIBUTES_MESSAGE_KEY as ATTRIBUTES_MESSAGE_KEY, ATTRIBUTES_TAGS_KEY as ATTRIBUTES_TAGS_KEY
3
3
  from _typeshed import Incomplete
4
4
  from structlog.types import EventDict, WrappedLogger
5
5
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "logfire-api"
7
- version = "5.2.0"
7
+ version = "5.4.0"
8
8
  description = "Shim for the Logfire SDK which does nothing unless Logfire is installed"
9
9
  authors = [
10
10
  { name = "Pydantic Team", email = "engineering@pydantic.dev" },
File without changes
File without changes