logfire-api 5.4.0__tar.gz → 5.6.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 (133) hide show
  1. {logfire_api-5.4.0 → logfire_api-5.6.0}/PKG-INFO +1 -1
  2. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/__init__.py +12 -4
  3. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/__init__.pyi +5 -1
  4. logfire_api-5.6.0/logfire_api/_internal/agent_sandboxes.pyi +13 -0
  5. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/cli/run.pyi +15 -0
  6. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/config.pyi +28 -20
  7. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/config_params.pyi +1 -0
  8. logfire_api-5.6.0/logfire_api/_internal/exporters/api_key_gate.pyi +40 -0
  9. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/otlp.pyi +2 -2
  10. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/processor_wrapper.pyi +32 -2
  11. logfire_api-5.6.0/logfire_api/_internal/fleet.pyi +30 -0
  12. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/formatter.pyi +5 -1
  13. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/executors.pyi +2 -0
  14. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/snowflake.pyi +1 -1
  15. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/json_encoder.pyi +5 -0
  16. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/main.pyi +31 -15
  17. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/scrubbing.pyi +2 -1
  18. logfire_api-5.6.0/logfire_api/fleet/__init__.pyi +3 -0
  19. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/logging.pyi +4 -2
  20. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/propagate.pyi +4 -3
  21. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/sampling/_tail_sampling.pyi +2 -1
  22. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/types.pyi +3 -0
  23. {logfire_api-5.4.0 → logfire_api-5.6.0}/pyproject.toml +1 -1
  24. logfire_api-5.4.0/logfire_api/_internal/agent_sandboxes.pyi +0 -10
  25. {logfire_api-5.4.0 → logfire_api-5.6.0}/.gitignore +0 -0
  26. {logfire_api-5.4.0 → logfire_api-5.6.0}/README.md +0 -0
  27. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/__init__.pyi +0 -0
  28. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/ast_utils.pyi +0 -0
  29. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/async_.pyi +0 -0
  30. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/auth.pyi +0 -0
  31. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/auto_trace/__init__.pyi +0 -0
  32. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/auto_trace/import_hook.pyi +0 -0
  33. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/auto_trace/rewrite_ast.pyi +0 -0
  34. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/auto_trace/types.pyi +0 -0
  35. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/baggage.pyi +0 -0
  36. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/cli/__init__.pyi +0 -0
  37. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/cli/ai_tools.pyi +0 -0
  38. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/cli/auth.pyi +0 -0
  39. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/cli/gateway.pyi +0 -0
  40. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/cli/gateway_auth.pyi +0 -0
  41. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/cli/prompt.pyi +0 -0
  42. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/cli.pyi +0 -0
  43. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/client.pyi +0 -0
  44. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/collect_system_info.pyi +0 -0
  45. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/constants.pyi +0 -0
  46. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/db_statement_summary.pyi +0 -0
  47. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/__init__.pyi +0 -0
  48. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/console.pyi +0 -0
  49. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/dynamic_batch.pyi +0 -0
  50. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/logs.pyi +0 -0
  51. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/quiet_metrics.pyi +0 -0
  52. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/remove_pending.pyi +0 -0
  53. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/tail_sampling.pyi +0 -0
  54. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/exporters/wrapper.pyi +0 -0
  55. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/forwarding.pyi +0 -0
  56. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/http_transport.pyi +0 -0
  57. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/instrument.pyi +0 -0
  58. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/__init__.pyi +0 -0
  59. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/aiohttp_client.pyi +0 -0
  60. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/aiohttp_server.pyi +0 -0
  61. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/asgi.pyi +0 -0
  62. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/asyncpg.pyi +0 -0
  63. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/aws_lambda.pyi +0 -0
  64. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/celery.pyi +0 -0
  65. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/claude_agent_sdk.pyi +0 -0
  66. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/django.pyi +0 -0
  67. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/dspy.pyi +0 -0
  68. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/fastapi.pyi +0 -0
  69. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/flask.pyi +0 -0
  70. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/google_genai.pyi +0 -0
  71. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/httpx.pyi +0 -0
  72. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/litellm.pyi +0 -0
  73. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/litestar.pyi +0 -0
  74. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/mcp.pyi +0 -0
  75. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/monty.pyi +0 -0
  76. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/mysql.pyi +0 -0
  77. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/openai_agents.pyi +0 -0
  78. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/print.pyi +0 -0
  79. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/psycopg.pyi +0 -0
  80. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/pydantic_ai.pyi +0 -0
  81. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/pymongo.pyi +0 -0
  82. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/pytest.pyi +0 -0
  83. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/redis.pyi +0 -0
  84. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/requests.pyi +0 -0
  85. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/sqlalchemy.pyi +0 -0
  86. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/sqlite3.pyi +0 -0
  87. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/starlette.pyi +0 -0
  88. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/surrealdb.pyi +0 -0
  89. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/system_metrics.pyi +0 -0
  90. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/integrations/wsgi.pyi +0 -0
  91. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/interactive.pyi +0 -0
  92. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/json_formatter.pyi +0 -0
  93. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/json_schema.pyi +0 -0
  94. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/json_types.pyi +0 -0
  95. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/logs.pyi +0 -0
  96. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/metrics.pyi +0 -0
  97. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/server_response.pyi +0 -0
  98. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/stack_info.pyi +0 -0
  99. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/tracer.pyi +0 -0
  100. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/ulid.pyi +0 -0
  101. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/_internal/utils.pyi +0 -0
  102. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/cli.pyi +0 -0
  103. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/db_api.pyi +0 -0
  104. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/exceptions.pyi +0 -0
  105. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/experimental/__init__.pyi +0 -0
  106. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/experimental/annotations.pyi +0 -0
  107. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/experimental/api_client.pyi +0 -0
  108. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/experimental/datasets/__init__.pyi +0 -0
  109. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/experimental/query_client.pyi +0 -0
  110. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/__init__.pyi +0 -0
  111. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/aiohttp_client.pyi +0 -0
  112. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/flask.pyi +0 -0
  113. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/httpx.pyi +0 -0
  114. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/loguru.pyi +0 -0
  115. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/psycopg.pyi +0 -0
  116. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/pydantic.pyi +0 -0
  117. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/redis.pyi +0 -0
  118. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/sqlalchemy.pyi +0 -0
  119. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/structlog.pyi +0 -0
  120. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/integrations/wsgi.pyi +0 -0
  121. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/py.typed +0 -0
  122. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/query_client.pyi +0 -0
  123. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/sampling/__init__.pyi +0 -0
  124. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/variables/__init__.pyi +0 -0
  125. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/variables/_handlebars.pyi +0 -0
  126. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/variables/abstract.pyi +0 -0
  127. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/variables/composition.pyi +0 -0
  128. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/variables/config.pyi +0 -0
  129. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/variables/local.pyi +0 -0
  130. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/variables/remote.pyi +0 -0
  131. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/variables/template_validation.pyi +0 -0
  132. {logfire_api-5.4.0 → logfire_api-5.6.0}/logfire_api/variables/variable.pyi +0 -0
  133. {logfire_api-5.4.0 → logfire_api-5.6.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.4.0
3
+ Version: 5.6.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
@@ -17,7 +17,10 @@ except ImportError:
17
17
  VERSION = '0.0.0'
18
18
  METRICS_PREFERRED_TEMPORALITY = {}
19
19
 
20
- def configure(*args, **kwargs): ...
20
+ def configure(*args, **kwargs) -> Logfire:
21
+ if kwargs.get('local'):
22
+ return Logfire()
23
+ return DEFAULT_LOGFIRE_INSTANCE
21
24
 
22
25
  class LogfireSpan:
23
26
  def __getattr__(self, attr):
@@ -164,7 +167,11 @@ except ImportError:
164
167
 
165
168
  def instrument_sqlalchemy(self, *args, **kwargs) -> None: ...
166
169
 
167
- def instrument_sqlite3(self, *args, **kwargs) -> None: ...
170
+ def instrument_sqlite3(self, conn=None, *args, **kwargs):
171
+ return conn
172
+
173
+ def instrument_mysql(self, conn=None, *args, **kwargs):
174
+ return conn
168
175
 
169
176
  def instrument_aws_lambda(self, *args, **kwargs) -> None: ...
170
177
 
@@ -227,7 +234,8 @@ except ImportError:
227
234
  async def forward_export_request_starlette(self, *args, **kwargs) -> MagicMock:
228
235
  return MagicMock()
229
236
 
230
- def shutdown(self, *args, **kwargs) -> None: ...
237
+ def shutdown(self, *args, **kwargs) -> bool:
238
+ return True
231
239
 
232
240
  DEFAULT_LOGFIRE_INSTANCE = Logfire()
233
241
  span = DEFAULT_LOGFIRE_INSTANCE.span
@@ -289,7 +297,7 @@ except ImportError:
289
297
  forward_export_request = DEFAULT_LOGFIRE_INSTANCE.forward_export_request
290
298
  forward_export_request_starlette = DEFAULT_LOGFIRE_INSTANCE.forward_export_request_starlette
291
299
 
292
- def loguru_handler() -> dict[str, Any]:
300
+ def loguru_handler(*, console_log: bool = True) -> dict[str, Any]:
293
301
  return {}
294
302
 
295
303
  def no_auto_trace(x):
@@ -87,9 +87,13 @@ variables_push_config = DEFAULT_LOGFIRE_INSTANCE.variables_push_config
87
87
  variables_pull_config = DEFAULT_LOGFIRE_INSTANCE.variables_pull_config
88
88
  variables_build_config = DEFAULT_LOGFIRE_INSTANCE.variables_build_config
89
89
 
90
- def loguru_handler() -> Any:
90
+ def loguru_handler(*, console_log: bool = True) -> Any:
91
91
  """Create a **Logfire** handler for Loguru.
92
92
 
93
+ Args:
94
+ console_log: Whether Logfire also prints these logs to the console.
95
+ Set to `False` to keep Loguru's own console output without duplicates.
96
+
93
97
  Returns:
94
98
  A dictionary with the handler and format for Loguru.
95
99
  """
@@ -0,0 +1,13 @@
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 AsyncMontyRemote
6
+ from typing import Any
7
+
8
+ def agent_sandboxes_url(base_url: str) -> str:
9
+ """Validate and normalize a supplied or derived Logfire Agent Sandboxes URL.
10
+
11
+ The client opens its gRPC stream at the root of this URL, so the base URL must not have a path.
12
+ """
13
+ def create_agent_sandboxes(logfire_instance: Logfire, *, api_key: str | None, url: str | None, metadata: Callable[[], Mapping[str, str]] | None = None, connect_headers: Callable[[], Mapping[str, str]] | None = None, **kwargs: Any) -> AsyncMontyRemote: ...
@@ -4,6 +4,7 @@ from collections.abc import Callable, Collection, Generator, Mapping
4
4
  from contextlib import contextmanager
5
5
  from dataclasses import dataclass
6
6
  from logfire._internal.utils import get_version as get_version
7
+ from opentelemetry.instrumentation.dependencies import DependencyConflict
7
8
  from rich.console import Console
8
9
  from rich.text import Text
9
10
 
@@ -48,9 +49,23 @@ def is_uv_installed() -> bool:
48
49
  def instrument_packages(installed_otel_packages: set[str], instrument_pkg_map: dict[str, str]) -> list[str]:
49
50
  """Call every `logfire.instrument_x()` we can based on what's installed.
50
51
 
52
+ Packages without a Logfire method fall back to their own OpenTelemetry instrumentors.
53
+
51
54
  Returns a list of packages that were successfully instrumented.
52
55
  """
53
56
  def instrument_package(import_name: str, *args: str) -> None: ...
57
+ def warn_on_version_conflict(source: str, conflict: DependencyConflict) -> None:
58
+ """Warn when an instrumented library is installed at a version its instrumentation doesn't support.
59
+
60
+ A library that isn't installed at all is skipped quietly, as `opentelemetry-instrument` does.
61
+ """
62
+ def instrument_with_entry_points(otel_pkg_name: str) -> bool:
63
+ """Call the `opentelemetry_instrumentor` entry points registered by an OpenTelemetry instrumentation package.
64
+
65
+ This follows `opentelemetry-instrument`, but passes Logfire's providers and warns on every failure,
66
+ including a missing module, where `opentelemetry-instrument` raises or only logs.
67
+ Returns whether at least one instrumentor was activated.
68
+ """
54
69
  def find_recommended_instrumentations_to_install(instrument_pkg_map: dict[str, str], installed_otel_pkgs: set[str], installed_pkgs: set[str], installed_versions: Mapping[str, str] | None = None) -> set[InstrumentationRecommendation]:
55
70
  """Determine which OpenTelemetry instrumentation packages are recommended for installation.
56
71
 
@@ -6,14 +6,16 @@ from ..types import ExceptionCallback as ExceptionCallback
6
6
  from .client import InvalidProjectName as InvalidProjectName, LogfireClient as LogfireClient, ProjectAlreadyExists as ProjectAlreadyExists
7
7
  from .config_params import CompressionValues as CompressionValues, ParamManager as ParamManager, PydanticPluginRecordValues as PydanticPluginRecordValues, normalize_token as normalize_token
8
8
  from .constants import ATTRIBUTES_CONFIG as ATTRIBUTES_CONFIG, ATTRIBUTES_PACKAGE_VERSIONS as ATTRIBUTES_PACKAGE_VERSIONS, LEVEL_NUMBERS as LEVEL_NUMBERS, LevelName as LevelName, RESOURCE_ATTRIBUTES_CODE_ROOT_PATH as RESOURCE_ATTRIBUTES_CODE_ROOT_PATH, RESOURCE_ATTRIBUTES_CODE_WORK_DIR as RESOURCE_ATTRIBUTES_CODE_WORK_DIR, RESOURCE_ATTRIBUTES_DEPLOYMENT_ENVIRONMENT_NAME as RESOURCE_ATTRIBUTES_DEPLOYMENT_ENVIRONMENT_NAME, RESOURCE_ATTRIBUTES_VCS_REPOSITORY_REF_REVISION as RESOURCE_ATTRIBUTES_VCS_REPOSITORY_REF_REVISION, RESOURCE_ATTRIBUTES_VCS_REPOSITORY_URL as RESOURCE_ATTRIBUTES_VCS_REPOSITORY_URL, RESOURCE_ATTRIBUTES_VERSION as RESOURCE_ATTRIBUTES_VERSION
9
+ from .exporters.api_key_gate import ApiKeyGatedLogExporter as ApiKeyGatedLogExporter, ApiKeyGatedMetricExporter as ApiKeyGatedMetricExporter, ApiKeyGatedSpanExporter as ApiKeyGatedSpanExporter, ApiKeyWriteAccess as ApiKeyWriteAccess
9
10
  from .exporters.console import ConsoleColorsValues as ConsoleColorsValues, ConsoleLogExporter as ConsoleLogExporter, IndentedConsoleSpanExporter as IndentedConsoleSpanExporter, ShowParentsConsoleSpanExporter as ShowParentsConsoleSpanExporter, SimpleConsoleSpanExporter as SimpleConsoleSpanExporter
10
11
  from .exporters.dynamic_batch import DynamicBatchSpanProcessor as DynamicBatchSpanProcessor
11
12
  from .exporters.logs import CheckSuppressInstrumentationLogProcessorWrapper as CheckSuppressInstrumentationLogProcessorWrapper, MainLogProcessorWrapper as MainLogProcessorWrapper
12
13
  from .exporters.otlp import BodySizeCheckingOTLPSpanExporter as BodySizeCheckingOTLPSpanExporter, OTLPExporterHttpSession as OTLPExporterHttpSession, QuietLogExporter as QuietLogExporter, QuietSpanExporter as QuietSpanExporter, RetryFewerSpansSpanExporter as RetryFewerSpansSpanExporter, cleanup_disk_retryers as cleanup_disk_retryers, zstd_compress as zstd_compress
13
- from .exporters.processor_wrapper import CheckSuppressInstrumentationProcessorWrapper as CheckSuppressInstrumentationProcessorWrapper, MainSpanProcessorWrapper as MainSpanProcessorWrapper
14
+ from .exporters.processor_wrapper import BackgroundScrubbingSpanProcessor as BackgroundScrubbingSpanProcessor, CheckSuppressInstrumentationProcessorWrapper as CheckSuppressInstrumentationProcessorWrapper, MainSpanProcessorWrapper as MainSpanProcessorWrapper, ScrubbingSpanProcessor as ScrubbingSpanProcessor, SpanProcessorGroup as SpanProcessorGroup, make_scrubbing_queue as make_scrubbing_queue, scrub_span as scrub_span
14
15
  from .exporters.quiet_metrics import QuietMetricExporter as QuietMetricExporter
15
16
  from .exporters.remove_pending import RemovePendingSpansExporter as RemovePendingSpansExporter
16
17
  from .exporters.test import TestExporter as TestExporter
18
+ from .fleet import FleetOptions as FleetOptions, LogfireFleetWarning as LogfireFleetWarning, load_fleet as load_fleet
17
19
  from .forwarding import OTLPForwardingManager as OTLPForwardingManager
18
20
  from .http_transport import install_connection_policy as install_connection_policy
19
21
  from .integrations.executors import instrument_executors as instrument_executors
@@ -53,6 +55,7 @@ from typing_extensions import Self
53
55
 
54
56
  CREDENTIALS_FILENAME: str
55
57
  COMMON_REQUEST_HEADERS: Incomplete
58
+ API_KEY_CANNOT_WRITE_HINT: str
56
59
  PROJECT_NAME_PATTERN: str
57
60
  METRICS_PREFERRED_TEMPORALITY: Incomplete
58
61
 
@@ -145,7 +148,7 @@ class LocalVariablesOptions:
145
148
  instrument: bool = ...
146
149
  template_mismatch_policy: TemplateMismatchPolicy = ...
147
150
 
148
- def configure(*, local: bool = False, send_to_logfire: bool | Literal['if-token-present'] | None = None, token: str | list[str] | None = None, api_key: str | None = None, service_name: str | None = None, service_version: str | None = None, environment: str | None = None, resource_attributes: Mapping[str, Any] | None = None, console: ConsoleOptions | Literal[False] | None = None, config_dir: Path | str | None = None, data_dir: Path | str | None = None, additional_span_processors: Sequence[SpanProcessor] | None = None, metrics: MetricsOptions | Literal[False] | None = None, scrubbing: ScrubbingOptions | Literal[False] | None = None, inspect_arguments: bool | None = None, sampling: SamplingOptions | None = None, min_level: int | LevelName | None = None, add_baggage_to_attributes: bool = True, code_source: CodeSource | None = None, variables: VariablesOptions | LocalVariablesOptions | None = None, distributed_tracing: bool | None = None, advanced: AdvancedOptions | None = None) -> Logfire:
151
+ def configure(*, local: bool = False, send_to_logfire: bool | Literal['if-token-present'] | None = None, token: str | list[str] | None = None, api_key: str | None = None, service_name: str | None = None, service_version: str | None = None, environment: str | None = None, resource_attributes: Mapping[str, Any] | None = None, console: ConsoleOptions | Literal[False] | None = None, config_dir: Path | str | None = None, data_dir: Path | str | None = None, additional_span_processors: Sequence[SpanProcessor] | None = None, metrics: MetricsOptions | Literal[False] | None = None, scrubbing: ScrubbingOptions | Literal[False] | None = None, inspect_arguments: bool | None = None, sampling: SamplingOptions | None = None, min_level: int | LevelName | None = None, add_baggage_to_attributes: bool = True, code_source: CodeSource | None = None, variables: VariablesOptions | LocalVariablesOptions | None = None, distributed_tracing: bool | None = None, fleet: bool | FleetOptions | None = None, advanced: AdvancedOptions | None = None) -> Logfire:
149
152
  """Configure the logfire SDK.
150
153
 
151
154
  Args:
@@ -165,6 +168,10 @@ def configure(*, local: bool = False, send_to_logfire: bool | Literal['if-token-
165
168
 
166
169
  If not provided, will be loaded from the `LOGFIRE_API_KEY` environment variable.
167
170
 
171
+ If no write token or project credentials file is found, the API key is also used to send
172
+ telemetry, unless `send_to_logfire` is `False`. This requires a project API key with the
173
+ `project:write_otlp` scope. Otherwise Logfire warns that the key cannot send telemetry.
174
+
168
175
  service_name: Name of this service.
169
176
 
170
177
  Defaults to the `LOGFIRE_SERVICE_NAME` environment variable.
@@ -197,6 +204,8 @@ def configure(*, local: bool = False, send_to_logfire: bool | Literal['if-token-
197
204
 
198
205
  data_dir: Directory to store credentials, and logs. If `None` uses the `LOGFIRE_CREDENTIALS_DIR` environment variable, otherwise defaults to `'.logfire'`.
199
206
  additional_span_processors: Span processors to use in addition to the default processor which exports spans to Logfire's API.
207
+ Processors which have a custom `on_end` method (other than `BatchSpanProcessor`) will cause
208
+ span attribute scrubbing to happen on the calling thread, which may slow down your application.
200
209
  metrics: Set to `False` to disable sending all metrics,
201
210
  or provide a `MetricsOptions` object to configure metrics, e.g. additional metric readers.
202
211
  scrubbing: Options for scrubbing sensitive data. Set to `False` to disable.
@@ -221,12 +230,20 @@ def configure(*, local: bool = False, send_to_logfire: bool | Literal['if-token-
221
230
  See the [Baggage documentation](https://logfire.pydantic.dev/docs/reference/advanced/baggage/) for more details.
222
231
  code_source: Settings for the source code of the project.
223
232
  variables: Options related to managed variables.
224
- distributed_tracing: By default, incoming trace context is extracted, but generates a warning.
233
+ distributed_tracing: By default, incoming context is extracted, but generates a warning.
225
234
  Set to `True` to disable the warning.
226
- Set to `False` to suppress extraction of incoming trace context.
235
+ Set to `False` to suppress extraction of all incoming context, preserving local context.
227
236
  See [Unintentional Distributed Tracing](https://logfire.pydantic.dev/docs/how-to-guides/distributed-tracing/#unintentional-distributed-tracing)
228
237
  for more information.
229
238
  This setting always applies globally, and the last value set is used, including the default value.
239
+ fleet: Whether to manage this SDK from Logfire Fleet: the Fleet policy then applies to everything it sends
240
+ (sampling, which signals are sent, log levels, redaction and volume limits, the console included).
241
+ `True` takes the Fleet server from the `OTEL_OPAMP_*` environment variables; a
242
+ [`FleetOptions`][logfire.fleet.FleetOptions] gives it in code. Needs the 'fleet' extra.
243
+ It never blocks or raises: until Fleet answers, the last policy saved is in force, else the SDK's own
244
+ settings, and where Fleet can't be joined it warns and the SDK runs unmanaged.
245
+
246
+ Defaults to the `LOGFIRE_FLEET` environment variable, otherwise `False`.
230
247
  advanced: Advanced options primarily used for testing by Logfire developers.
231
248
  """
232
249
 
@@ -259,17 +276,18 @@ class _LogfireConfigData:
259
276
  code_source: CodeSource | None
260
277
  variables: VariablesOptions | LocalVariablesOptions | None
261
278
  distributed_tracing: bool | None
279
+ fleet: FleetOptions | Literal[False]
262
280
  advanced: AdvancedOptions
263
281
 
264
282
  class LogfireConfig(_LogfireConfigData):
265
- def __init__(self, send_to_logfire: bool | Literal['if-token-present'] | None = None, token: str | list[str] | None = None, api_key: str | None = None, service_name: str | None = None, service_version: str | None = None, environment: str | None = None, resource_attributes: Mapping[str, Any] | None = None, console: ConsoleOptions | Literal[False] | None = None, config_dir: Path | None = None, data_dir: Path | None = None, additional_span_processors: Sequence[SpanProcessor] | None = None, metrics: MetricsOptions | Literal[False] | None = None, scrubbing: ScrubbingOptions | Literal[False] | None = None, inspect_arguments: bool | None = None, sampling: SamplingOptions | None = None, min_level: int | LevelName | None = None, add_baggage_to_attributes: bool = True, variables: VariablesOptions | None = None, code_source: CodeSource | None = None, distributed_tracing: bool | None = None, advanced: AdvancedOptions | None = None) -> None:
283
+ def __init__(self, send_to_logfire: bool | Literal['if-token-present'] | None = None, token: str | list[str] | None = None, api_key: str | None = None, service_name: str | None = None, service_version: str | None = None, environment: str | None = None, resource_attributes: Mapping[str, Any] | None = None, console: ConsoleOptions | Literal[False] | None = None, config_dir: Path | None = None, data_dir: Path | None = None, additional_span_processors: Sequence[SpanProcessor] | None = None, metrics: MetricsOptions | Literal[False] | None = None, scrubbing: ScrubbingOptions | Literal[False] | None = None, inspect_arguments: bool | None = None, sampling: SamplingOptions | None = None, min_level: int | LevelName | None = None, add_baggage_to_attributes: bool = True, variables: VariablesOptions | None = None, code_source: CodeSource | None = None, distributed_tracing: bool | None = None, advanced: AdvancedOptions | None = None, fleet: bool | FleetOptions | None = None) -> None:
266
284
  """Create a new LogfireConfig.
267
285
 
268
286
  Users should never need to call this directly, instead use `logfire.configure`.
269
287
 
270
288
  See `_LogfireConfigData` for parameter documentation.
271
289
  """
272
- def configure(self, send_to_logfire: bool | Literal['if-token-present'] | None, token: str | list[str] | None, api_key: str | None, service_name: str | None, service_version: str | None, environment: str | None, resource_attributes: Mapping[str, Any] | None, console: ConsoleOptions | Literal[False] | None, config_dir: Path | None, data_dir: Path | None, additional_span_processors: Sequence[SpanProcessor] | None, metrics: MetricsOptions | Literal[False] | None, scrubbing: ScrubbingOptions | Literal[False] | None, inspect_arguments: bool | None, sampling: SamplingOptions | None, min_level: int | LevelName | None, add_baggage_to_attributes: bool, code_source: CodeSource | None, variables: VariablesOptions | LocalVariablesOptions | None, distributed_tracing: bool | None, advanced: AdvancedOptions | None) -> None: ...
290
+ def configure(self, send_to_logfire: bool | Literal['if-token-present'] | None, token: str | list[str] | None, api_key: str | None, service_name: str | None, service_version: str | None, environment: str | None, resource_attributes: Mapping[str, Any] | None, console: ConsoleOptions | Literal[False] | None, config_dir: Path | None, data_dir: Path | None, additional_span_processors: Sequence[SpanProcessor] | None, metrics: MetricsOptions | Literal[False] | None, scrubbing: ScrubbingOptions | Literal[False] | None, inspect_arguments: bool | None, sampling: SamplingOptions | None, min_level: int | LevelName | None, add_baggage_to_attributes: bool, code_source: CodeSource | None, variables: VariablesOptions | LocalVariablesOptions | None, distributed_tracing: bool | None, fleet: bool | FleetOptions | None, advanced: AdvancedOptions | None) -> None: ...
273
291
  def initialize(self) -> None:
274
292
  """Configure internals to start exporting traces and metrics."""
275
293
  def force_flush(self, timeout_millis: int = 30000) -> bool:
@@ -359,13 +377,16 @@ class LogfireCredentials:
359
377
  LogfireConfigError: If the credentials file exists but is invalid.
360
378
  """
361
379
  @classmethod
362
- def from_token(cls, token: str, session: requests.Session, base_url: str) -> Self | None:
380
+ def from_token(cls, token: str, session: requests.Session, base_url: str, *, rejected_hint: str | None = None, on_rejected: Callable[[], None] | None = None) -> Self | None:
363
381
  """Check that the token is valid.
364
382
 
365
383
  Issue a warning if the Logfire API is unreachable, or we get a response other than 200 or 401.
366
384
 
367
385
  We continue unless we get a 401. If something is wrong, we'll later store data locally for back-fill.
368
386
 
387
+ `rejected_hint` is appended to the warning when the API rejects the token with a 401.
388
+ `on_rejected` is called for that 401 too.
389
+
369
390
  Raises:
370
391
  LogfireConfigError: If the token is invalid.
371
392
  """
@@ -407,19 +428,6 @@ class LogfireCredentials:
407
428
  Raises:
408
429
  LogfireConfigError: If there was an error creating projects.
409
430
  """
410
- @classmethod
411
- def initialize_project(cls, *, client: LogfireClient) -> Self:
412
- """Create a new project or use an existing project on logfire.dev requesting the given project name.
413
-
414
- Args:
415
- client: The Logfire client to use when making requests.
416
-
417
- Returns:
418
- The new credentials.
419
-
420
- Raises:
421
- LogfireConfigError: If there was an error on creating/configuring the project.
422
- """
423
431
  def write_creds_file(self, creds_dir: Path) -> None:
424
432
  """Write a credentials file to the given path."""
425
433
  def print_token_summary(self) -> None:
@@ -59,6 +59,7 @@ BASE_URL: Incomplete
59
59
  DISTRIBUTED_TRACING: Incomplete
60
60
  EMIT_CONFIGURATION_SPAN: Incomplete
61
61
  PENDING_SPANS: Incomplete
62
+ FLEET: Incomplete
62
63
  COMPRESSION: Incomplete
63
64
  HTTPX_CAPTURE_ALL: Incomplete
64
65
  AIOHTTP_CLIENT_CAPTURE_ALL: Incomplete
@@ -0,0 +1,40 @@
1
+ from .wrapper import WrapperLogExporter as WrapperLogExporter, WrapperMetricExporter as WrapperMetricExporter, WrapperSpanExporter as WrapperSpanExporter
2
+ from _typeshed import Incomplete
3
+ from collections.abc import Sequence
4
+ from opentelemetry.sdk._logs import ReadableLogRecord as ReadableLogRecord
5
+ from opentelemetry.sdk._logs.export import LogRecordExportResult, LogRecordExporter
6
+ from opentelemetry.sdk.metrics.export import MetricExportResult, MetricExporter, MetricsData
7
+ from opentelemetry.sdk.trace import ReadableSpan as ReadableSpan
8
+ from opentelemetry.sdk.trace.export import SpanExportResult, SpanExporter
9
+ from typing import Any
10
+
11
+ VERDICT_TIMEOUT_SECONDS: int
12
+
13
+ class ApiKeyWriteAccess:
14
+ """The result of the token check for an API key that is used as a write token."""
15
+ def __init__(self) -> None: ...
16
+ def reject(self) -> None:
17
+ """Record that Logfire rejected the API key as a write token."""
18
+ def settle(self) -> None:
19
+ """Record that the check finished. A key that the check did not reject stays allowed."""
20
+ def allows_export(self) -> bool:
21
+ """Wait for the check, then tell if exports can use the key.
22
+
23
+ If the check does not finish in time, the export continues.
24
+ The exporters then report any failure as they do for a write token.
25
+ """
26
+
27
+ class ApiKeyGatedSpanExporter(WrapperSpanExporter):
28
+ access: Incomplete
29
+ def __init__(self, exporter: SpanExporter, access: ApiKeyWriteAccess) -> None: ...
30
+ def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult: ...
31
+
32
+ class ApiKeyGatedLogExporter(WrapperLogExporter):
33
+ access: Incomplete
34
+ def __init__(self, exporter: LogRecordExporter, access: ApiKeyWriteAccess) -> None: ...
35
+ def export(self, batch: Sequence[ReadableLogRecord]) -> LogRecordExportResult: ...
36
+
37
+ class ApiKeyGatedMetricExporter(WrapperMetricExporter):
38
+ access: Incomplete
39
+ def __init__(self, exporter: MetricExporter, access: ApiKeyWriteAccess, **kwargs: Any) -> None: ...
40
+ def export(self, metrics_data: MetricsData, timeout_millis: float = 10000, **kwargs: Any) -> MetricExportResult: ...
@@ -9,7 +9,6 @@ from .wrapper import WrapperLogExporter as WrapperLogExporter, WrapperSpanExport
9
9
  from _typeshed import Incomplete
10
10
  from collections import deque
11
11
  from collections.abc import Mapping, Sequence
12
- from functools import cached_property
13
12
  from logfire._internal.utils import handle_internal_errors as handle_internal_errors
14
13
  from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
15
14
  from opentelemetry.sdk._logs import ReadableLogRecord as ReadableLogRecord
@@ -60,7 +59,7 @@ class OTLPExporterHttpSession(Session):
60
59
  def __init__(self, *, _use_zstd: bool = False) -> None: ...
61
60
  def request(self, method: str, url: str, **kwargs: Any): ...
62
61
  def post(self, url: str, data: bytes, **kwargs: Any): ...
63
- @cached_property
62
+ @property
64
63
  def retryer(self) -> DiskRetryer: ...
65
64
  def close(self) -> None: ...
66
65
 
@@ -76,6 +75,7 @@ class DiskRetryer:
76
75
  tasks: deque[tuple[Path, dict[str, Any]]]
77
76
  total_size: int
78
77
  closed: bool
78
+ pid: Incomplete
79
79
  session: Incomplete
80
80
  dir: Incomplete
81
81
  last_log_time: Incomplete
@@ -5,9 +5,11 @@ from ..json_schema import JsonSchemaProperties as JsonSchemaProperties, attribut
5
5
  from ..scrubbing import BaseScrubber as BaseScrubber
6
6
  from ..utils import ReadableSpanDict as ReadableSpanDict, handle_internal_errors as handle_internal_errors, is_asgi_send_receive_span_name as is_asgi_send_receive_span_name, is_instrumentation_suppressed as is_instrumentation_suppressed, span_to_dict as span_to_dict, truncate_string as truncate_string
7
7
  from .wrapper import WrapperSpanProcessor as WrapperSpanProcessor
8
+ from collections.abc import Sequence
8
9
  from dataclasses import dataclass
9
10
  from opentelemetry import context
10
- from opentelemetry.sdk.trace import Event as Event, ReadableSpan, Span
11
+ from opentelemetry.sdk.trace import Event as Event, ReadableSpan, Span, SpanProcessor, SynchronousMultiSpanProcessor
12
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExportResult, SpanExporter
11
13
 
12
14
  class CheckSuppressInstrumentationProcessorWrapper(WrapperSpanProcessor):
13
15
  """Checks if instrumentation is suppressed, then suppresses instrumentation itself.
@@ -17,14 +19,42 @@ class CheckSuppressInstrumentationProcessorWrapper(WrapperSpanProcessor):
17
19
  def on_start(self, span: Span, parent_context: context.Context | None = None) -> None: ...
18
20
  def on_end(self, span: ReadableSpan) -> None: ...
19
21
 
20
- @dataclass
21
22
  class MainSpanProcessorWrapper(WrapperSpanProcessor):
22
23
  """Wrapper around other processors to intercept starting and ending spans with our own global logic.
23
24
 
24
25
  Suppresses starting/ending if the current context has a `suppress_instrumentation` value.
25
26
  Tweaks the send/receive span names generated by the ASGI middleware.
26
27
  """
28
+ def on_end(self, span: ReadableSpan) -> None: ...
29
+
30
+ def scrub_span(span: ReadableSpan, scrubber: BaseScrubber) -> ReadableSpan: ...
31
+
32
+ @dataclass
33
+ class ScrubbingSpanProcessor(WrapperSpanProcessor):
27
34
  scrubber: BaseScrubber
28
35
  def on_end(self, span: ReadableSpan) -> None: ...
29
36
 
37
+ @dataclass
38
+ class _SpanProcessorExporter(SpanExporter):
39
+ """Forward drained records to a processor's `on_end` hook.
40
+
41
+ The group that owns the destination processor flushes and shuts it down.
42
+ """
43
+ processor: SpanProcessor
44
+ def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult: ...
45
+
46
+ def make_scrubbing_queue(processor: SpanProcessor, scrubber: BaseScrubber) -> BatchSpanProcessor:
47
+ """Queue records for scrubbing before delivering them to a processor."""
48
+
49
+ class SpanProcessorGroup(SynchronousMultiSpanProcessor):
50
+ """Flush processors that may inherit a no-op force_flush returning None."""
51
+ def force_flush(self, timeout_millis: int = 30000) -> bool: ...
52
+
53
+ @dataclass
54
+ class BackgroundScrubbingSpanProcessor(WrapperSpanProcessor):
55
+ """Send completed spans to the synchronous processors and the scrubbing queue."""
56
+ synchronous_end_processor: SpanProcessor
57
+ background_end_processor: BatchSpanProcessor
58
+ def on_end(self, span: ReadableSpan) -> None: ...
59
+
30
60
  def guess_system(model: str, default: str = ''): ...
@@ -0,0 +1,30 @@
1
+ import dataclasses
2
+ from .stack_info import warn_at_user_stacklevel as warn_at_user_stacklevel
3
+ from .utils import platform_is_emscripten as platform_is_emscripten
4
+ from collections.abc import Mapping
5
+ from datetime import timedelta
6
+ from logfire_fleet_otel import LogfireFleet
7
+ from pathlib import Path
8
+
9
+ FLEET_CONTRACT: int
10
+
11
+ @dataclasses.dataclass
12
+ class FleetOptions:
13
+ """Options for joining Logfire Fleet.
14
+
15
+ Each one left as `None` comes from its environment variable, which is what the Fleet setup page
16
+ in Logfire gives you.
17
+ """
18
+ endpoint: str | None = ...
19
+ headers: Mapping[str, str] | None = ...
20
+ state_dir: str | Path | None = ...
21
+ heartbeat_interval: float | timedelta | None = ...
22
+
23
+ class LogfireFleetWarning(UserWarning):
24
+ """The SDK couldn't join Logfire Fleet, so it runs unmanaged."""
25
+
26
+ def load_fleet(options: FleetOptions) -> LogfireFleet | None:
27
+ """The Fleet client's hook for `options`, or `None` (with a warning) where it can't run.
28
+
29
+ It never raises: telemetry is sent either way, under the SDK's own settings.
30
+ """
@@ -9,7 +9,7 @@ from _typeshed import Incomplete
9
9
  from collections.abc import Iterator
10
10
  from functools import lru_cache
11
11
  from string import Formatter
12
- from types import CodeType as CodeType
12
+ from types import CodeType
13
13
  from typing import Any, Literal
14
14
  from typing_extensions import NotRequired, TypedDict
15
15
 
@@ -29,6 +29,10 @@ chunks_formatter: Incomplete
29
29
 
30
30
  def logfire_format(format_string: str, kwargs: dict[str, Any], scrubber: BaseScrubber) -> str: ...
31
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
+
33
+ LOGFIRE_PACKAGE_DIR: Incomplete
34
+
35
+ def is_logfire_code(code: CodeType) -> bool: ...
32
36
  @lru_cache
33
37
  def compile_formatted_value(node: ast.FormattedValue, ex_source: executing.Source) -> tuple[str, CodeType, CodeType]:
34
38
  """Returns three things that can be expensive to compute.
@@ -2,9 +2,11 @@ from ..stack_info import warn_at_user_stacklevel as warn_at_user_stacklevel
2
2
  from _typeshed import Incomplete
3
3
  from collections.abc import Callable
4
4
  from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
5
+ from contextvars import ContextVar as ContextVar
5
6
  from logfire.propagate import ContextCarrier as ContextCarrier, attach_context as attach_context, get_context as get_context
6
7
  from typing import Any
7
8
 
9
+ THREAD_CONTEXTVARS: list[ContextVar[Any]]
8
10
  submit_t_orig: Incomplete
9
11
  submit_p_orig: Incomplete
10
12
 
@@ -1,6 +1,6 @@
1
1
  from logfire import Logfire as Logfire
2
2
  from logfire._internal.stack_info import warn_at_user_stacklevel as warn_at_user_stacklevel
3
- from logfire._internal.utils import handle_internal_errors as handle_internal_errors
3
+ from logfire._internal.utils import get_version as get_version, handle_internal_errors as handle_internal_errors
4
4
  from snowflake.connector.connection import SnowflakeConnection
5
5
  from types import ModuleType
6
6
 
@@ -12,6 +12,11 @@ EncoderFunction: Incomplete
12
12
 
13
13
  @cache
14
14
  def encoder_by_type() -> dict[type[Any], EncoderFunction]: ...
15
+ def numpy_scalar_to_python(o: Any) -> Any:
16
+ """Convert a NumPy bool, integer or floating scalar to the equivalent Python value, and return anything else as is.
17
+
18
+ Without this, a value like `numpy.int64(42)` (e.g. from `df['col'].sum()`) would be recorded as its repr.
19
+ """
15
20
  def to_json_value(o: Any, seen: set[int]) -> JsonValue: ...
16
21
  def logfire_json_dumps(obj: Any) -> str: ...
17
22
  def is_sqlalchemy(obj: Any) -> bool: ...
@@ -19,7 +19,7 @@ from ..version import VERSION as VERSION
19
19
  from .auto_trace import AutoTraceModule as AutoTraceModule, install_auto_tracing as install_auto_tracing
20
20
  from .config import GLOBAL_CONFIG as GLOBAL_CONFIG, LogfireConfig as LogfireConfig, TemplateMismatchPolicy as TemplateMismatchPolicy
21
21
  from .config_params import PydanticPluginRecordValues as PydanticPluginRecordValues
22
- from .constants import ATTRIBUTES_JSON_SCHEMA_KEY as ATTRIBUTES_JSON_SCHEMA_KEY, ATTRIBUTES_LOG_LEVEL_NUM_KEY as ATTRIBUTES_LOG_LEVEL_NUM_KEY, ATTRIBUTES_MESSAGE_KEY as ATTRIBUTES_MESSAGE_KEY, ATTRIBUTES_MESSAGE_TEMPLATE_KEY as ATTRIBUTES_MESSAGE_TEMPLATE_KEY, ATTRIBUTES_SAMPLE_RATE_KEY as ATTRIBUTES_SAMPLE_RATE_KEY, ATTRIBUTES_SPAN_TYPE_KEY as ATTRIBUTES_SPAN_TYPE_KEY, ATTRIBUTES_TAGS_KEY as ATTRIBUTES_TAGS_KEY, DISABLE_CONSOLE_KEY as DISABLE_CONSOLE_KEY, LEVEL_NUMBERS as LEVEL_NUMBERS, LevelName as LevelName, OTLP_MAX_INT_SIZE as OTLP_MAX_INT_SIZE, log_level_attributes as log_level_attributes
22
+ from .constants import ATTRIBUTES_JSON_SCHEMA_KEY as ATTRIBUTES_JSON_SCHEMA_KEY, ATTRIBUTES_LOG_LEVEL_NUM_KEY as ATTRIBUTES_LOG_LEVEL_NUM_KEY, ATTRIBUTES_MESSAGE_KEY as ATTRIBUTES_MESSAGE_KEY, ATTRIBUTES_MESSAGE_TEMPLATE_KEY as ATTRIBUTES_MESSAGE_TEMPLATE_KEY, ATTRIBUTES_SAMPLE_RATE_KEY as ATTRIBUTES_SAMPLE_RATE_KEY, ATTRIBUTES_SPAN_TYPE_KEY as ATTRIBUTES_SPAN_TYPE_KEY, ATTRIBUTES_TAGS_KEY as ATTRIBUTES_TAGS_KEY, DISABLE_CONSOLE_KEY as DISABLE_CONSOLE_KEY, LevelName as LevelName, OTLP_MAX_INT_SIZE as OTLP_MAX_INT_SIZE, log_level_attributes as log_level_attributes
23
23
  from .formatter import logfire_format as logfire_format, logfire_format_with_magic as logfire_format_with_magic
24
24
  from .forwarding import ForwardExportRequestResponse as ForwardExportRequestResponse
25
25
  from .instrument import instrument as instrument
@@ -30,11 +30,11 @@ from .integrations.mysql import MySQLConnection as MySQLConnection
30
30
  from .integrations.psycopg import Psycopg2Connection as Psycopg2Connection, PsycopgConnection as PsycopgConnection
31
31
  from .integrations.sqlite3 import SQLite3Connection as SQLite3Connection
32
32
  from .integrations.system_metrics import Base as SystemMetricsBase, Config as SystemMetricsConfig
33
- from .json_encoder import logfire_json_dumps as logfire_json_dumps
33
+ from .json_encoder import logfire_json_dumps as logfire_json_dumps, numpy_scalar_to_python as numpy_scalar_to_python
34
34
  from .json_schema import JsonSchemaProperties as JsonSchemaProperties, attributes_json_schema as attributes_json_schema, attributes_json_schema_properties as attributes_json_schema_properties, create_json_schema as create_json_schema
35
35
  from .metrics import ProxyMeterProvider as ProxyMeterProvider
36
36
  from .stack_info import get_user_stack_info as get_user_stack_info
37
- from .tracer import ProxyTracerProvider as ProxyTracerProvider, _ProxyTracer, set_exception_status as set_exception_status
37
+ from .tracer import ProxyTracerProvider as ProxyTracerProvider, _ProxyTracer
38
38
  from .utils import SysExcInfo as SysExcInfo, get_version as get_version, handle_internal_errors as handle_internal_errors, log_internal_error as log_internal_error, uniquify_sequence as uniquify_sequence
39
39
  from anthropic.lib.bedrock import AnthropicBedrock as _AnthropicBedrock, AsyncAnthropicBedrock as _AsyncAnthropicBedrock
40
40
  from collections.abc import Iterable, Mapping, Sequence
@@ -51,7 +51,7 @@ from opentelemetry.sdk.trace import ReadableSpan, Span
51
51
  from opentelemetry.trace import SpanContext, SpanKind
52
52
  from opentelemetry.util import types as otel_types
53
53
  from pydantic_evals.reporting import EvaluationReport
54
- from pydantic_monty import AsyncMontyWebsocket
54
+ from pydantic_monty import AsyncMontyRemote
55
55
  from pymongo.monitoring import CommandFailedEvent as CommandFailedEvent, CommandStartedEvent as CommandStartedEvent, CommandSucceededEvent as CommandSucceededEvent
56
56
  from snowflake.connector.connection import SnowflakeConnection
57
57
  from sqlalchemy import Engine
@@ -527,13 +527,13 @@ class Logfire:
527
527
  It records Monty sessions, executed code, inputs, outputs, external calls,
528
528
  exceptions, printed text, and pool metrics. Recorded values are subject to Logfire's configured scrubbing.
529
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:
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 = ..., metadata: Callable[[], Mapping[str, str]] | 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) -> AsyncMontyRemote:
531
531
  """Connect to Logfire Agent Sandboxes, remote Pydantic Monty workers hosted by Logfire.
532
532
 
533
533
  Requires the `agent-sandboxes` extra, e.g. `pip install 'logfire[agent-sandboxes]'`.
534
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:
535
+ Returns a [`pydantic_monty.AsyncMontyRemote`][pydantic_monty.AsyncMontyRemote] pool that
536
+ authenticates with your Logfire API key. Use it as an async context manager and check out sessions from it:
537
537
 
538
538
  ```py
539
539
  import logfire
@@ -549,6 +549,17 @@ class Logfire:
549
549
 
550
550
  No connection is made until a session is checked out.
551
551
 
552
+ Because the pool is a plain `AsyncMontyRemote`, you can pass this method wherever a Monty pool
553
+ factory is expected, for example `CodeMode(monty_sandbox=logfire.agent_sandboxes)` in Pydantic AI.
554
+
555
+ Checkout errors from the sandboxes server are Monty's own exceptions; this method does not wrap them.
556
+ An exception raised by your `metadata` callback propagates unchanged. A refused checkout raises
557
+ `MontyRefusedError`. For `UNAUTHENTICATED` or
558
+ `PERMISSION_DENIED`, check that the key is a project API key with the
559
+ `project:execute_agent_sandboxes` scope, that its region matches the server URL, and that Agent
560
+ Sandboxes are enabled for the project. For `RESOURCE_EXHAUSTED`, lower `max_processes` or retry
561
+ after a delay.
562
+
552
563
  The Logfire platform records sandbox usage itself. The current trace context is sent
553
564
  with each session so those spans join the caller's trace.
554
565
 
@@ -556,27 +567,32 @@ class Logfire:
556
567
  The defaults described below are the currently assumed defaults and may change in future versions.
557
568
 
558
569
  Args:
559
- api_key: A Logfire API key with the `project:execute_agent_sandboxes` scope.
570
+ api_key: A Logfire project API key (not a personal key) with the
571
+ `project:execute_agent_sandboxes` scope. Agent Sandboxes must be enabled for the project.
560
572
  Defaults to the `api_key` passed to [`configure()`][logfire.configure],
561
573
  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
574
+ url: The `https://` URL of the sandboxes server.
575
+ Defaults to the Logfire region the API key belongs to. Must not contain a path,
576
+ query, or fragment. `/monty-ws/` was the old path and must be removed.
577
+ max_processes: Cap on concurrent sandbox sessions. Defaults to `None`, which uses
565
578
  the CPU count; checkouts beyond it wait.
566
579
  checkout_timeout: Seconds `checkout()` waits for capacity before raising `TimeoutError`.
567
580
  Defaults to `None`, which waits forever.
568
581
  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.
582
+ session closed and the call raises `MontyCrashedError`. Must be finite;
583
+ `None` raises `LogfireConfigError` because hosted sandboxes require a deadline.
570
584
  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.
585
+ metadata: Called once per session to produce extra request metadata for its gRPC
586
+ stream. Names are lowercased and values must be ASCII. These are merged with the
587
+ `authorization` entry and win on conflicts.
588
+ connect_headers: The deprecated name of `metadata`.
573
589
  Defaults to `None`, which adds no extra headers beyond Logfire authentication.
574
590
  feed_duration_limit_grace: Seconds to wait past a feed's `max_feed_duration_secs`
575
591
  before closing the sandbox. Defaults to `1.0`; `None` disables this backstop.
576
592
  turn_duration_limit_grace: The same, for `max_turn_duration_secs`. Defaults to `1.0`.
577
593
  auto_resume: When the server drains a stored session, transparently resume it on
578
594
  another server instead of raising `MontyShutdown`. Defaults to `True`.
579
- kwargs: Additional keyword arguments passed to `AsyncMontyWebsocket` for future compatibility.
595
+ kwargs: Additional keyword arguments passed to `AsyncMontyRemote` for future compatibility.
580
596
  """
581
597
  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]:
582
598
  """Instrument a FastAPI app so that spans and logs are automatically created for each request.
@@ -1,6 +1,7 @@
1
1
  import re
2
2
  import typing_extensions
3
3
  from .constants import ATTRIBUTES_CONFIG as ATTRIBUTES_CONFIG, ATTRIBUTES_JSON_SCHEMA_KEY as ATTRIBUTES_JSON_SCHEMA_KEY, ATTRIBUTES_LOGGING_NAME as ATTRIBUTES_LOGGING_NAME, ATTRIBUTES_LOG_LEVEL_NAME_KEY as ATTRIBUTES_LOG_LEVEL_NAME_KEY, ATTRIBUTES_LOG_LEVEL_NUM_KEY as ATTRIBUTES_LOG_LEVEL_NUM_KEY, ATTRIBUTES_MESSAGE_KEY as ATTRIBUTES_MESSAGE_KEY, ATTRIBUTES_MESSAGE_TEMPLATE_KEY as ATTRIBUTES_MESSAGE_TEMPLATE_KEY, ATTRIBUTES_PACKAGE_VERSIONS as ATTRIBUTES_PACKAGE_VERSIONS, ATTRIBUTES_PENDING_SPAN_REAL_PARENT_KEY as ATTRIBUTES_PENDING_SPAN_REAL_PARENT_KEY, ATTRIBUTES_SAMPLE_RATE_KEY as ATTRIBUTES_SAMPLE_RATE_KEY, ATTRIBUTES_SCRUBBED_KEY as ATTRIBUTES_SCRUBBED_KEY, ATTRIBUTES_SPAN_TYPE_KEY as ATTRIBUTES_SPAN_TYPE_KEY, ATTRIBUTES_TAGS_KEY as ATTRIBUTES_TAGS_KEY, MESSAGE_FORMATTED_VALUE_LENGTH_LIMIT as MESSAGE_FORMATTED_VALUE_LENGTH_LIMIT, RESOURCE_ATTRIBUTES_VERSION as RESOURCE_ATTRIBUTES_VERSION
4
+ from .json_encoder import logfire_json_dumps as logfire_json_dumps
4
5
  from .stack_info import STACK_INFO_KEYS as STACK_INFO_KEYS
5
6
  from .utils import ReadableSpanDict as ReadableSpanDict, truncate_string as truncate_string
6
7
  from _typeshed import Incomplete
@@ -62,7 +63,7 @@ class SpanScrubber:
62
63
  and hold and mutate state about the span being scrubbed, specifically the scrubbed notes.
63
64
  """
64
65
  scrubbed: list[ScrubbedNote]
65
- did_scrub: bool
66
+ scrub_count: int
66
67
  def __init__(self, parent: Scrubber) -> None: ...
67
68
  def scrub_span(self, span: ReadableSpanDict): ...
68
69
  def scrub_log(self, log: LogRecord) -> LogRecord: ...
@@ -0,0 +1,3 @@
1
+ from .._internal.fleet import FleetOptions as FleetOptions, LogfireFleetWarning as LogfireFleetWarning
2
+
3
+ __all__ = ['FleetOptions', 'LogfireFleetWarning']
@@ -2,7 +2,6 @@ from .. import Logfire as Logfire
2
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
- from collections.abc import Mapping as Mapping
6
5
  from logging import Handler as LoggingHandler, LogRecord
7
6
  from typing import Any, ClassVar
8
7
 
@@ -15,11 +14,14 @@ class LogfireLoggingHandler(LoggingHandler):
15
14
  level: The threshold level for this handler. Logging messages which are less severe than *level* will be ignored.
16
15
  fallback: A fallback handler to use when [instrumentation is suppressed](../../how-to-guides/suppress.md#suppress-instrumentation).
17
16
  logfire_instance: The Logfire instance to use when emitting logs. Defaults to the default global instance.
17
+ console_log: Whether logs from this handler are also printed to the console by Logfire.
18
+ Set to `False` if another handler already prints them, to avoid duplicates.
19
+ Defaults to the setting of `logfire_instance`.
18
20
  """
19
21
  custom_scope_suffix: ClassVar[str]
20
22
  fallback: Incomplete
21
23
  logfire_instance: Incomplete
22
- def __init__(self, level: int | str = ..., fallback: LoggingHandler = ..., logfire_instance: Logfire | None = None) -> None: ...
24
+ def __init__(self, level: int | str = ..., fallback: LoggingHandler = ..., logfire_instance: Logfire | None = None, console_log: bool | None = None) -> None: ...
23
25
  def emit(self, record: LogRecord) -> None:
24
26
  """Send the log to Logfire.
25
27
 
@@ -61,15 +61,16 @@ class WrapperPropagator(TextMapPropagator):
61
61
  def fields(self): ...
62
62
 
63
63
  class NoExtractTraceContextPropagator(WrapperPropagator):
64
- """A propagator that ignores any trace context that was extracted by the wrapped propagator.
64
+ """A propagator that ignores all incoming context and preserves local context.
65
65
 
66
- Used when `logfire.configure(distributed_tracing=False)` is called.
66
+ Used when `logfire.configure(distributed_tracing=False)` is called. Extraction returns the
67
+ supplied context, or the current context if none is supplied, without calling the wrapped propagator.
67
68
  """
68
69
  def extract(self, carrier: Any, context: otel_context.Context | None = None, *args: Any, **kwargs: Any) -> otel_context.Context: ...
69
70
 
70
71
  @dataclass
71
72
  class WarnOnExtractTraceContextPropagator(WrapperPropagator):
72
- """A propagator that warns the first time that trace context is extracted by the wrapped propagator.
73
+ """A propagator that warns the first time that incoming context is extracted by the wrapped propagator.
73
74
 
74
75
  Used when `logfire.configure(distributed_tracing=None)` is called. This is the default behavior.
75
76
  """
@@ -77,9 +77,10 @@ class TailSamplingProcessor(WrapperSpanProcessor):
77
77
  """
78
78
  get_tail_sample_rate: Incomplete
79
79
  deferred_processor: Incomplete
80
+ prepare_ended_span: Incomplete
80
81
  traces: dict[int, TraceBuffer]
81
82
  lock: Incomplete
82
- def __init__(self, processor: SpanProcessor, get_tail_sample_rate: Callable[[TailSamplingSpanInfo], float], deferred_processor: SpanProcessor | None = None) -> None: ...
83
+ def __init__(self, processor: SpanProcessor, get_tail_sample_rate: Callable[[TailSamplingSpanInfo], float], deferred_processor: SpanProcessor | None = None, *, prepare_ended_span: Callable[[ReadableSpan], ReadableSpan] | None = None) -> None: ...
83
84
  def on_start(self, span: Span, parent_context: context.Context | None = None) -> None: ...
84
85
  def on_end(self, span: ReadableSpan) -> None: ...
85
86
  def check_span(self, span_info: TailSamplingSpanInfo) -> bool:
@@ -18,6 +18,9 @@ class SpanLevel:
18
18
  `<`, `>`, `<=`, or `>=`, so e.g. `level >= 'error'` is valid.
19
19
 
20
20
  Will raise an exception if compared to a non-string or an invalid level name.
21
+
22
+ Hashing a level warns and uses its name, so `level in {'warn', 'error'}` works,
23
+ but `level in {13}` does not. Prefer `level.name in {...}`.
21
24
  """
22
25
  number: int
23
26
  @classmethod
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "logfire-api"
7
- version = "5.4.0"
7
+ version = "5.6.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" },
@@ -1,10 +0,0 @@
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: ...
File without changes
File without changes