Skip to content

Commit 93db21e

Browse files
authored
Release v2.8.0 (#691)
1 parent 9e629da commit 93db21e

File tree

10 files changed

+49
-24
lines changed

10 files changed

+49
-24
lines changed

CHANGELOG.md

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

3+
## [v2.8.0] (2024-12-18)
4+
5+
* Add `capture_(request|response)_headers` ([#671](https://github.com/pydantic/logfire/pull/671)) and `capture_request_json_body` ([#682](https://github.com/pydantic/logfire/pull/682)) to `instrument_httpx` by @Kludex
6+
* Fix patching of ProcessPoolExecutor by @alexmojaki in [#690](https://github.com/pydantic/logfire/pull/690)
7+
* Rearrange span processors to avoid repeating scrubbing and other tweaking by @alexmojaki in [#658](https://github.com/pydantic/logfire/pull/658)
8+
* Remove end-on-exit stuff by @dmontagu in [#676](https://github.com/pydantic/logfire/pull/676)
9+
310
## [v2.7.1] (2024-12-13)
411

512
* Fix erroneous `<circular reference>` when object is repeated in list by @alexmojaki in [#664](https://github.com/pydantic/logfire/pull/664)
@@ -472,3 +479,4 @@ First release from new repo!
472479
[v2.6.2]: https://github.com/pydantic/logfire/compare/v2.6.1...v2.6.2
473480
[v2.7.0]: https://github.com/pydantic/logfire/compare/v2.6.2...v2.7.0
474481
[v2.7.1]: https://github.com/pydantic/logfire/compare/v2.7.0...v2.7.1
482+
[v2.8.0]: https://github.com/pydantic/logfire/compare/v2.7.1...v2.8.0

logfire-api/logfire_api/_internal/config.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ from .exporters.console import ConsoleColorsValues as ConsoleColorsValues, Inden
77
from .exporters.fallback import FallbackSpanExporter as FallbackSpanExporter
88
from .exporters.file import FileSpanExporter as FileSpanExporter
99
from .exporters.otlp import OTLPExporterHttpSession as OTLPExporterHttpSession, RetryFewerSpansSpanExporter as RetryFewerSpansSpanExporter
10-
from .exporters.processor_wrapper import MainSpanProcessorWrapper as MainSpanProcessorWrapper
10+
from .exporters.processor_wrapper import CheckSuppressInstrumentationProcessorWrapper as CheckSuppressInstrumentationProcessorWrapper, MainSpanProcessorWrapper as MainSpanProcessorWrapper
1111
from .exporters.quiet_metrics import QuietMetricExporter as QuietMetricExporter
1212
from .exporters.remove_pending import RemovePendingSpansExporter as RemovePendingSpansExporter
1313
from .exporters.test import TestExporter as TestExporter

logfire-api/logfire_api/_internal/exporters/processor_wrapper.pyi

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@ from ..db_statement_summary import message_from_db_statement as message_from_db_
33
from ..scrubbing import BaseScrubber as BaseScrubber
44
from ..utils import ReadableSpanDict as ReadableSpanDict, 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
55
from .wrapper import WrapperSpanProcessor as WrapperSpanProcessor
6-
from _typeshed import Incomplete
6+
from dataclasses import dataclass
77
from opentelemetry import context
8-
from opentelemetry.sdk.trace import ReadableSpan, Span, SpanProcessor
8+
from opentelemetry.sdk.trace import ReadableSpan, Span
99

10+
class CheckSuppressInstrumentationProcessorWrapper(WrapperSpanProcessor):
11+
"""Checks if instrumentation is suppressed, then suppresses instrumentation itself.
12+
13+
Placed at the root of the tree of processors.
14+
"""
15+
def on_start(self, span: Span, parent_context: context.Context | None = None) -> None: ...
16+
def on_end(self, span: ReadableSpan) -> None: ...
17+
18+
@dataclass
1019
class MainSpanProcessorWrapper(WrapperSpanProcessor):
1120
"""Wrapper around other processors to intercept starting and ending spans with our own global logic.
1221
1322
Suppresses starting/ending if the current context has a `suppress_instrumentation` value.
1423
Tweaks the send/receive span names generated by the ASGI middleware.
1524
"""
16-
scrubber: Incomplete
17-
def __init__(self, processor: SpanProcessor, scrubber: BaseScrubber) -> None: ...
25+
scrubber: BaseScrubber
1826
def on_start(self, span: Span, parent_context: context.Context | None = None) -> None: ...
1927
def on_end(self, span: ReadableSpan) -> None: ...

logfire-api/logfire_api/_internal/exporters/wrapper.pyi

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from _typeshed import Incomplete
2+
from dataclasses import dataclass
23
from opentelemetry import context
34
from opentelemetry.sdk.metrics.export import AggregationTemporality as AggregationTemporality, MetricExportResult, MetricExporter, MetricsData
45
from opentelemetry.sdk.metrics.view import Aggregation as Aggregation
@@ -22,10 +23,10 @@ class WrapperMetricExporter(MetricExporter):
2223
def force_flush(self, timeout_millis: float = 10000) -> bool: ...
2324
def shutdown(self, timeout_millis: float = 30000, **kwargs: Any) -> None: ...
2425

26+
@dataclass
2527
class WrapperSpanProcessor(SpanProcessor):
2628
"""A base class for SpanProcessors that wrap another processor."""
27-
processor: Incomplete
28-
def __init__(self, processor: SpanProcessor) -> None: ...
29+
processor: SpanProcessor
2930
def on_start(self, span: Span, parent_context: context.Context | None = None) -> None: ...
3031
def on_end(self, span: ReadableSpan) -> None: ...
3132
def shutdown(self) -> None: ...

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import httpx
22
from logfire import Logfire as Logfire
3+
from logfire._internal.main import set_user_attributes_on_raw_span as set_user_attributes_on_raw_span
4+
from logfire._internal.utils import handle_internal_errors as handle_internal_errors
35
from opentelemetry.instrumentation.httpx import AsyncRequestHook, AsyncResponseHook, RequestHook, RequestInfo, ResponseHook, ResponseInfo
46
from opentelemetry.trace import Span
57
from typing import Any, Callable, Literal, ParamSpec, TypeVar, TypedDict, Unpack, overload
@@ -27,17 +29,20 @@ AsyncHook = TypeVar('AsyncHook', AsyncRequestHook, AsyncResponseHook)
2729
P = ParamSpec('P')
2830

2931
@overload
30-
def instrument_httpx(logfire_instance: Logfire, client: httpx.Client, capture_request_headers: bool, capture_response_headers: bool, **kwargs: Unpack[ClientKwargs]) -> None: ...
32+
def instrument_httpx(logfire_instance: Logfire, client: httpx.Client, capture_request_headers: bool, capture_response_headers: bool, capture_request_json_body: bool, **kwargs: Unpack[ClientKwargs]) -> None: ...
3133
@overload
32-
def instrument_httpx(logfire_instance: Logfire, client: httpx.AsyncClient, capture_request_headers: bool, capture_response_headers: bool, **kwargs: Unpack[AsyncClientKwargs]) -> None: ...
34+
def instrument_httpx(logfire_instance: Logfire, client: httpx.AsyncClient, capture_request_headers: bool, capture_response_headers: bool, capture_request_json_body: bool, **kwargs: Unpack[AsyncClientKwargs]) -> None: ...
3335
@overload
34-
def instrument_httpx(logfire_instance: Logfire, client: None, capture_request_headers: bool, capture_response_headers: bool, **kwargs: Unpack[HTTPXInstrumentKwargs]) -> None: ...
35-
def make_capture_response_headers_hook(hook: ResponseHook | None) -> ResponseHook: ...
36-
def make_capture_async_response_headers_hook(hook: AsyncResponseHook | None) -> AsyncResponseHook: ...
37-
def make_capture_request_headers_hook(hook: RequestHook | None) -> RequestHook: ...
38-
def make_capture_async_request_headers_hook(hook: AsyncRequestHook | None) -> AsyncRequestHook: ...
36+
def instrument_httpx(logfire_instance: Logfire, client: None, capture_request_headers: bool, capture_response_headers: bool, capture_request_json_body: bool, **kwargs: Unpack[HTTPXInstrumentKwargs]) -> None: ...
37+
def make_request_hook(hook: RequestHook | None, should_capture_headers: bool, should_capture_json: bool) -> RequestHook | None: ...
38+
def make_async_request_hook(hook: AsyncRequestHook | RequestHook | None, should_capture_headers: bool, should_capture_json: bool) -> AsyncRequestHook | None: ...
39+
def make_response_hook(hook: ResponseHook | None, should_capture_headers: bool) -> ResponseHook | None: ...
40+
def make_async_response_hook(hook: ResponseHook | AsyncResponseHook | None, should_capture_headers: bool) -> AsyncResponseHook | None: ...
3941
async def run_async_hook(hook: Callable[P, Any] | None, *args: P.args, **kwargs: P.kwargs) -> None: ...
4042
def run_hook(hook: Callable[P, Any] | None, *args: P.args, **kwargs: P.kwargs) -> None: ...
41-
def capture_response_headers(span: Span, request: RequestInfo, response: ResponseInfo) -> None: ...
43+
def capture_response_headers(span: Span, response: ResponseInfo) -> None: ...
4244
def capture_request_headers(span: Span, request: RequestInfo) -> None: ...
4345
def capture_headers(span: Span, headers: httpx.Headers, request_or_response: Literal['request', 'response']) -> None: ...
46+
def get_charset(content_type: str) -> str: ...
47+
def decode_body(body: bytes, content_type: str): ...
48+
def capture_request_body(span: Span, request: RequestInfo) -> None: ...

logfire-api/logfire_api/_internal/main.pyi

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -551,11 +551,11 @@ class Logfire:
551551
def instrument_asyncpg(self, **kwargs: Unpack[AsyncPGInstrumentKwargs]) -> None:
552552
"""Instrument the `asyncpg` module so that spans are automatically created for each query."""
553553
@overload
554-
def instrument_httpx(self, client: httpx.Client, capture_request_headers: bool = False, capture_response_headers: bool = False, **kwargs: Unpack[ClientKwargs]) -> None: ...
554+
def instrument_httpx(self, client: httpx.Client, capture_request_headers: bool = False, capture_response_headers: bool = False, capture_request_json_body: bool = False, **kwargs: Unpack[ClientKwargs]) -> None: ...
555555
@overload
556-
def instrument_httpx(self, client: httpx.AsyncClient, capture_request_headers: bool = False, capture_response_headers: bool = False, **kwargs: Unpack[AsyncClientKwargs]) -> None: ...
556+
def instrument_httpx(self, client: httpx.AsyncClient, capture_request_headers: bool = False, capture_response_headers: bool = False, capture_request_json_body: bool = False, **kwargs: Unpack[AsyncClientKwargs]) -> None: ...
557557
@overload
558-
def instrument_httpx(self, client: None = None, capture_request_headers: bool = False, capture_response_headers: bool = False, **kwargs: Unpack[HTTPXInstrumentKwargs]) -> None: ...
558+
def instrument_httpx(self, client: None = None, capture_request_headers: bool = False, capture_response_headers: bool = False, capture_request_json_body: bool = False, **kwargs: Unpack[HTTPXInstrumentKwargs]) -> None: ...
559559
def instrument_celery(self, **kwargs: Any) -> None:
560560
"""Instrument `celery` so that spans are automatically created for each task.
561561

logfire-api/logfire_api/_internal/tracer.pyi

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,13 @@ class SuppressedTracer(Tracer):
7070
class PendingSpanProcessor(SpanProcessor):
7171
"""Span processor that emits an extra pending span for each span as it starts.
7272
73-
The pending span is emitted by calling `on_end` on all other processors.
73+
The pending span is emitted by calling `on_end` on the inner `processor`.
74+
This is intentionally not a `WrapperSpanProcessor` to avoid the default implementations of `on_end`
75+
and `shutdown`. This processor is expected to contain processors which are already included
76+
elsewhere in the pipeline where `on_end` and `shutdown` are called normally.
7477
"""
7578
id_generator: IdGenerator
76-
other_processors: tuple[SpanProcessor, ...]
79+
processor: SpanProcessor
7780
def on_start(self, span: Span, parent_context: context_api.Context | None = None) -> None: ...
7881

7982
def should_sample(span_context: SpanContext, attributes: Mapping[str, otel_types.AttributeValue]) -> bool:

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.7.1"
7+
version = "2.8.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.7.1"
7+
version = "2.8.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)