Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Release Notes

## [v4.8.0] (2025-09-18)

* Allow capturing headers and response body with `logfire.instrument_aiohttp_client()` by @adtyavrdhn in [#1405](https://github.com/pydantic/logfire/pull/1405) and [#1409](https://github.com/pydantic/logfire/pull/1409)

## [v4.7.0] (2025-09-12)

* Update to OpenTelemetry SDK 1.37.0, drop support for <1.35.0 by @alexmojaki in [#1398](https://github.com/pydantic/logfire/pull/1398)
Expand Down Expand Up @@ -901,3 +905,4 @@ First release from new repo!
[v4.5.0]: https://github.com/pydantic/logfire/compare/v4.4.0...v4.5.0
[v4.6.0]: https://github.com/pydantic/logfire/compare/v4.5.0...v4.6.0
[v4.7.0]: https://github.com/pydantic/logfire/compare/v4.6.0...v4.7.0
[v4.8.0]: https://github.com/pydantic/logfire/compare/v4.7.0...v4.8.0
43 changes: 40 additions & 3 deletions logfire-api/logfire_api/_internal/integrations/aiohttp_client.pyi
Original file line number Diff line number Diff line change
@@ -1,8 +1,45 @@
from logfire import Logfire as Logfire
from typing import Any
from aiohttp.client_reqrep import ClientResponse
from aiohttp.tracing import TraceRequestEndParams, TraceRequestExceptionParams, TraceRequestStartParams
from logfire import Logfire as Logfire, LogfireSpan as LogfireSpan
from logfire._internal.utils import handle_internal_errors as handle_internal_errors
from logfire.integrations.aiohttp_client import AioHttpRequestHeaders as AioHttpRequestHeaders, AioHttpResponseHeaders as AioHttpResponseHeaders, RequestHook as RequestHook, ResponseHook as ResponseHook
from opentelemetry.trace import Span
from typing import Any, Callable, Literal, ParamSpec
from yarl import URL

def instrument_aiohttp_client(logfire_instance: Logfire, **kwargs: Any):
P = ParamSpec('P')

def instrument_aiohttp_client(logfire_instance: Logfire, capture_response_body: bool, capture_headers: bool, request_hook: RequestHook | None, response_hook: ResponseHook | None, **kwargs: Any) -> None:
"""Instrument the `aiohttp` module so that spans are automatically created for each client request.

See the `Logfire.instrument_aiohttp_client` method for details.
"""

class LogfireClientInfoMixin:
headers: AioHttpRequestHeaders

class LogfireAioHttpRequestInfo(TraceRequestStartParams, LogfireClientInfoMixin):
span: Span
def capture_headers(self) -> None: ...

class LogfireAioHttpResponseInfo(LogfireClientInfoMixin):
span: Span
method: str
url: URL
headers: AioHttpRequestHeaders
response: ClientResponse | None
exception: BaseException | None
logfire_instance: Logfire
body_captured: bool
def capture_headers(self) -> None: ...
def capture_body_if_text(self, attr_name: str = 'http.response.body.text') -> None: ...
def capture_text_as_json(self, span: LogfireSpan, *, text: str, attr_name: str) -> None: ...
@classmethod
def create_from_trace_params(cls, span: Span, params: TraceRequestEndParams | TraceRequestExceptionParams, logfire_instance: Logfire) -> LogfireAioHttpResponseInfo: ...

def make_request_hook(hook: RequestHook | None, capture_headers: bool) -> RequestHook | None: ...
def make_response_hook(hook: ResponseHook | None, logfire_instance: Logfire, capture_headers: bool, capture_response_body: bool) -> ResponseHook | None: ...
def capture_request(span: Span, request: TraceRequestStartParams, capture_headers: bool) -> LogfireAioHttpRequestInfo: ...
def capture_response(span: Span, response: TraceRequestEndParams | TraceRequestExceptionParams, logfire_instance: Logfire, capture_headers: bool, capture_response_body: bool) -> LogfireAioHttpResponseInfo: ...
def run_hook(hook: Callable[P, Any] | None, *args: P.args, **kwargs: P.kwargs) -> None: ...
def capture_request_or_response_headers(span: Span, headers: AioHttpRequestHeaders | AioHttpResponseHeaders, request_or_response: Literal['request', 'response']) -> None: ...
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ def transform_part(part: Part) -> Part: ...
class SpanEventLoggerProvider(EventLoggerProvider):
def get_event_logger(self, *args: Any, **kwargs: Any) -> SpanEventLogger: ...

def instrument_google_genai(logfire_instance: logfire.Logfire): ...
def instrument_google_genai(logfire_instance: logfire.Logfire, **kwargs: Any): ...
23 changes: 19 additions & 4 deletions logfire-api/logfire_api/_internal/main.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import pydantic_ai
import pydantic_ai.models
import requests
from . import async_ as async_
from ..integrations.aiohttp_client import RequestHook as AiohttpClientRequestHook, ResponseHook as AiohttpClientResponseHook
from ..integrations.flask import CommenterOptions as FlaskCommenterOptions, RequestHook as FlaskRequestHook, ResponseHook as FlaskResponseHook
from ..integrations.httpx import AsyncRequestHook as HttpxAsyncRequestHook, AsyncResponseHook as HttpxAsyncResponseHook, RequestHook as HttpxRequestHook, ResponseHook as HttpxResponseHook
from ..integrations.psycopg import CommenterOptions as PsycopgCommenterOptions
Expand Down Expand Up @@ -401,10 +402,14 @@ class Logfire:
Set to `'warn'` to issue a warning instead, or `'ignore'` to skip the check.
"""
def instrument_mcp(self, *, propagate_otel_context: bool = True) -> None:
"""Instrument [MCP](https://modelcontextprotocol.io/) requests such as tool calls.
"""Instrument the [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk).

Instruments both the client and server side. If possible, calling this in both the client and server
processes is recommended for nice distributed traces.

Args:
propagate_otel_context: Whether to enable propagation of the OpenTelemetry context.
propagate_otel_context: Whether to enable propagation of the OpenTelemetry context
for distributed tracing.
Set to False to prevent setting extra fields like `traceparent` on the metadata of requests.
"""
def instrument_pydantic(self, record: PydanticPluginRecordValues = 'all', include: Iterable[str] = (), exclude: Iterable[str] = ()) -> None:
Expand Down Expand Up @@ -577,7 +582,17 @@ class Logfire:
A context manager that will revert the instrumentation when exited.
Use of this context manager is optional.
"""
def instrument_google_genai(self) -> None: ...
def instrument_google_genai(self, **kwargs: Any):
"""Instrument the [Google Gen AI SDK (`google-genai`)](https://googleapis.github.io/python-genai/).

!!! note
To capture message contents (i.e. prompts and completions), set the environment variable
`OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` to `true`.

Uses the `GoogleGenAiSdkInstrumentor().instrument()` method of the
[`opentelemetry-instrumentation-google-genai`](https://pypi.org/project/opentelemetry-instrumentation-google-genai/)
package, to which it passes `**kwargs`.
"""
def instrument_litellm(self, **kwargs: Any): ...
def instrument_print(self) -> AbstractContextManager[None]:
"""Instrument the built-in `print` function so that calls to it are logged.
Expand Down Expand Up @@ -738,7 +753,7 @@ class Logfire:
Returns:
The instrumented WSGI application.
"""
def instrument_aiohttp_client(self, **kwargs: Any) -> None:
def instrument_aiohttp_client(self, *, capture_headers: bool = False, capture_response_body: bool = False, request_hook: AiohttpClientRequestHook | None = None, response_hook: AiohttpClientResponseHook | None = None, **kwargs: Any) -> None:
"""Instrument the `aiohttp` module so that spans are automatically created for each client request.

Uses the
Expand Down
9 changes: 9 additions & 0 deletions logfire-api/logfire_api/integrations/aiohttp_client.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from aiohttp.tracing import TraceRequestEndParams, TraceRequestExceptionParams, TraceRequestStartParams
from collections.abc import Callable
from multidict import CIMultiDict, CIMultiDictProxy
from opentelemetry.trace import Span

AioHttpRequestHeaders = CIMultiDict[str]
AioHttpResponseHeaders = CIMultiDictProxy[str]
RequestHook = Callable[[Span, TraceRequestStartParams], None]
ResponseHook = Callable[[Span, TraceRequestEndParams | TraceRequestExceptionParams], None]
2 changes: 1 addition & 1 deletion logfire-api/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "logfire-api"
version = "4.7.0"
version = "4.8.0"
description = "Shim for the Logfire SDK which does nothing unless Logfire is installed"
authors = [
{ name = "Pydantic Team", email = "engineering@pydantic.dev" },
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "logfire"
version = "4.7.0"
version = "4.8.0"
description = "The best Python observability tool! 🪵🔥"
requires-python = ">=3.9"
authors = [
Expand Down
10 changes: 7 additions & 3 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading