Skip to content

Commit 21c457a

Browse files
authored
Release v2.11.0 (#723)
1 parent db1f57a commit 21c457a

File tree

6 files changed

+55
-24
lines changed

6 files changed

+55
-24
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Release Notes
22

3+
## [v2.11.0] (2024-12-23)
4+
5+
* Add `capture_request_text_body` param to `instrument_httpx` by @alexmojaki in [#722](https://github.com/pydantic/logfire/pull/722)
6+
* Support for `AnthropicBedrock` client by @stephenhibbert in [#701](https://github.com/pydantic/logfire/pull/701)
7+
38
## [v2.10.0] (2024-12-23)
49

510
* Add `capture_request_form_data` param to `instrument_httpx` by @alexmojaki in [#711](https://github.com/pydantic/logfire/pull/711)
@@ -493,3 +498,4 @@ First release from new repo!
493498
[v2.8.0]: https://github.com/pydantic/logfire/compare/v2.7.1...v2.8.0
494499
[v2.9.0]: https://github.com/pydantic/logfire/compare/v2.8.0...v2.9.0
495500
[v2.10.0]: https://github.com/pydantic/logfire/compare/v2.9.0...v2.10.0
501+
[v2.11.0]: https://github.com/pydantic/logfire/compare/v2.10.0...v2.11.0

logfire-api/logfire_api/_internal/integrations/httpx.pyi

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ from logfire._internal.utils import handle_internal_errors as handle_internal_er
88
from logfire.integrations.httpx import AsyncRequestHook as AsyncRequestHook, AsyncResponseHook as AsyncResponseHook, RequestHook as RequestHook, RequestInfo as RequestInfo, ResponseHook as ResponseHook, ResponseInfo as ResponseInfo
99
from logfire.propagate import attach_context as attach_context, get_context as get_context
1010
from opentelemetry.trace import Span
11-
from typing import Any, Callable, Literal, ParamSpec, TypeVar, TypedDict
11+
from typing import Any, Callable, Literal, Mapping, ParamSpec, TypeVar, TypedDict
1212

1313
class AsyncClientKwargs(TypedDict, total=False):
1414
request_hook: RequestHook | AsyncRequestHook
@@ -32,28 +32,55 @@ Hook = TypeVar('Hook', RequestHook, ResponseHook)
3232
AsyncHook = TypeVar('AsyncHook', AsyncRequestHook, AsyncResponseHook)
3333
P = ParamSpec('P')
3434

35-
def instrument_httpx(logfire_instance: Logfire, client: httpx.Client | httpx.AsyncClient | None, capture_headers: bool, capture_request_json_body: bool, capture_response_json_body: bool, capture_request_form_data: bool, **kwargs: Any) -> None:
35+
def instrument_httpx(logfire_instance: Logfire, client: httpx.Client | httpx.AsyncClient | None, capture_headers: bool, capture_request_json_body: bool, capture_request_text_body: bool, capture_response_json_body: bool, capture_request_form_data: bool, **kwargs: Any) -> None:
3636
"""Instrument the `httpx` module so that spans are automatically created for each request.
3737
3838
See the `Logfire.instrument_httpx` method for details.
3939
"""
40-
def make_request_hook(hook: RequestHook | None, should_capture_headers: bool, should_capture_json: bool, should_capture_form_data: bool) -> RequestHook | None: ...
41-
def make_async_request_hook(hook: AsyncRequestHook | RequestHook | None, should_capture_headers: bool, should_capture_json: bool, should_capture_form_data: bool) -> AsyncRequestHook | None: ...
42-
def capture_request(request: RequestInfo, span: Span, should_capture_headers: bool, should_capture_json: bool, should_capture_form_data: bool) -> None: ...
40+
41+
class LogfireHttpxRequestInfo(RequestInfo):
42+
span: Span
43+
def capture_headers(self) -> None: ...
44+
def capture_body_if_json(self, attr_name: str = 'http.request.body.json'): ...
45+
def capture_body_if_text(self, attr_name: str = 'http.request.body.text'): ...
46+
def capture_body_if_form(self, attr_name: str = 'http.request.body.form'): ...
47+
def capture_text_as_json(self, attr_name: str = 'http.request.body.json', text: str | None = None): ...
48+
@property
49+
def body_is_streaming(self): ...
50+
@property
51+
def content_type_header_object(self) -> ContentTypeHeader: ...
52+
@property
53+
def content_type_header_string(self) -> str: ...
54+
@property
55+
def content_type_is_json(self): ...
56+
@property
57+
def content_type_is_text(self): ...
58+
@property
59+
def content_type_is_form(self): ...
60+
@property
61+
def content_type_charset(self): ...
62+
@property
63+
def content(self) -> bytes: ...
64+
@property
65+
def text(self) -> str: ...
66+
@property
67+
def form_data(self) -> Mapping[str, Any] | None: ...
68+
def set_complex_span_attributes(self, attributes: dict[str, Any]): ...
69+
70+
def make_request_hook(hook: RequestHook | None, should_capture_headers: bool, should_capture_json: bool, should_capture_text: bool, should_capture_form_data: bool) -> RequestHook | None: ...
71+
def make_async_request_hook(hook: AsyncRequestHook | RequestHook | None, should_capture_headers: bool, should_capture_json: bool, should_capture_text: bool, should_capture_form_data: bool) -> AsyncRequestHook | None: ...
72+
def capture_request(request: LogfireHttpxRequestInfo, should_capture_headers: bool, should_capture_json: bool, should_capture_text: bool, should_capture_form_data: bool) -> None: ...
4373
def make_response_hook(hook: ResponseHook | None, should_capture_headers: bool, should_capture_json: bool, logfire_instance: Logfire) -> ResponseHook | None: ...
4474
def make_async_response_hook(hook: ResponseHook | AsyncResponseHook | None, should_capture_headers: bool, should_capture_json: bool, logfire_instance: Logfire) -> AsyncResponseHook | None: ...
4575
def capture_response_json(logfire_instance: Logfire, response_info: ResponseInfo, is_async: bool) -> None: ...
4676
async def run_async_hook(hook: Callable[P, Any] | None, *args: P.args, **kwargs: P.kwargs) -> None: ...
4777
def run_hook(hook: Callable[P, Any] | None, *args: P.args, **kwargs: P.kwargs) -> None: ...
4878
def capture_response_headers(span: Span, response: ResponseInfo) -> None: ...
49-
def capture_request_headers(span: Span, request: RequestInfo) -> None: ...
5079
def capture_headers(span: Span, headers: httpx.Headers, request_or_response: Literal['request', 'response']) -> None: ...
5180
def decode_body(body: bytes, charset: str): ...
52-
def capture_request_body(span: Span, request: RequestInfo) -> None: ...
5381

5482
CODES_FOR_METHODS_WITH_DATA_PARAM: Incomplete
5583

56-
def capture_request_form_data(span: Span, request: RequestInfo) -> None: ...
5784
def content_type_header_from_string(content_type: str) -> ContentTypeHeader: ...
5885
def content_type_subtypes(subtype: str) -> set[str]: ...
5986
def is_json_type(content_type: str) -> bool: ...

logfire-api/logfire_api/_internal/main.pyi

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -501,10 +501,10 @@ class Logfire:
501501
A context manager that will revert the instrumentation when exited.
502502
Use of this context manager is optional.
503503
"""
504-
def instrument_anthropic(self, anthropic_client: anthropic.Anthropic | anthropic.AsyncAnthropic | type[anthropic.Anthropic] | type[anthropic.AsyncAnthropic] | None = None, *, suppress_other_instrumentation: bool = True) -> ContextManager[None]:
504+
def instrument_anthropic(self, anthropic_client: anthropic.Anthropic | anthropic.AsyncAnthropic | anthropic.AnthropicBedrock | anthropic.AsyncAnthropicBedrock | type[anthropic.Anthropic] | type[anthropic.AsyncAnthropic] | type[anthropic.AnthropicBedrock] | type[anthropic.AsyncAnthropicBedrock] | None = None, *, suppress_other_instrumentation: bool = True) -> ContextManager[None]:
505505
"""Instrument an Anthropic client so that spans are automatically created for each request.
506506
507-
The following methods are instrumented for both the sync and the async clients:
507+
The following methods are instrumented for both the sync and async clients:
508508
509509
- [`client.messages.create`](https://docs.anthropic.com/en/api/messages)
510510
- [`client.messages.stream`](https://docs.anthropic.com/en/api/messages-streaming)
@@ -519,6 +519,7 @@ class Logfire:
519519
import anthropic
520520
521521
client = anthropic.Anthropic()
522+
522523
logfire.configure()
523524
logfire.instrument_anthropic(client)
524525
@@ -534,13 +535,10 @@ class Logfire:
534535
535536
Args:
536537
anthropic_client: The Anthropic client or class to instrument:
537-
538-
- `None` (the default) to instrument both the
539-
`anthropic.Anthropic` and `anthropic.AsyncAnthropic` classes.
540-
- The `anthropic.Anthropic` class or a subclass
541-
- The `anthropic.AsyncAnthropic` class or a subclass
542-
- An instance of `anthropic.Anthropic`
543-
- An instance of `anthropic.AsyncAnthropic`
538+
- `None` (the default) to instrument all Anthropic client types
539+
- The `anthropic.Anthropic` or `anthropic.AnthropicBedrock` class or subclass
540+
- The `anthropic.AsyncAnthropic` or `anthropic.AsyncAnthropicBedrock` class or subclass
541+
- An instance of any of the above classes
544542
545543
suppress_other_instrumentation: If True, suppress any other OTEL instrumentation that may be otherwise
546544
enabled. In reality, this means the HTTPX instrumentation, which could otherwise be called since
@@ -553,11 +551,11 @@ class Logfire:
553551
def instrument_asyncpg(self, **kwargs: Unpack[AsyncPGInstrumentKwargs]) -> None:
554552
"""Instrument the `asyncpg` module so that spans are automatically created for each query."""
555553
@overload
556-
def instrument_httpx(self, client: httpx.Client, *, capture_headers: bool = False, capture_request_json_body: bool = False, capture_response_json_body: bool = False, capture_request_form_data: bool = False, **kwargs: Unpack[ClientKwargs]) -> None: ...
554+
def instrument_httpx(self, client: httpx.Client, *, capture_headers: bool = False, capture_request_text_body: bool = False, capture_request_json_body: bool = False, capture_response_json_body: bool = False, capture_request_form_data: bool = False, **kwargs: Unpack[ClientKwargs]) -> None: ...
557555
@overload
558-
def instrument_httpx(self, client: httpx.AsyncClient, *, capture_headers: bool = False, capture_request_json_body: bool = False, capture_response_json_body: bool = False, capture_request_form_data: bool = False, **kwargs: Unpack[AsyncClientKwargs]) -> None: ...
556+
def instrument_httpx(self, client: httpx.AsyncClient, *, capture_headers: bool = False, capture_request_json_body: bool = False, capture_request_text_body: bool = False, capture_response_json_body: bool = False, capture_request_form_data: bool = False, **kwargs: Unpack[AsyncClientKwargs]) -> None: ...
559557
@overload
560-
def instrument_httpx(self, client: None = None, *, capture_headers: bool = False, capture_request_json_body: bool = False, capture_response_json_body: bool = False, capture_request_form_data: bool = False, **kwargs: Unpack[HTTPXInstrumentKwargs]) -> None: ...
558+
def instrument_httpx(self, client: None = None, *, capture_headers: bool = False, capture_request_json_body: bool = False, capture_request_text_body: bool = False, capture_response_json_body: bool = False, capture_request_form_data: bool = False, **kwargs: Unpack[HTTPXInstrumentKwargs]) -> None: ...
561559
def instrument_celery(self, **kwargs: Any) -> None:
562560
"""Instrument `celery` so that spans are automatically created for each task.
563561

logfire-api/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "logfire-api"
7-
version = "2.10.0"
7+
version = "2.11.0"
88
description = "Shim for the Logfire SDK which does nothing unless Logfire is installed"
99
authors = [
1010
{ name = "Pydantic Team", email = "[email protected]" },

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "logfire"
7-
version = "2.10.0"
7+
version = "2.11.0"
88
description = "The best Python observability tool! 🪵🔥"
99
requires-python = ">=3.8"
1010
authors = [

uv.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)