Skip to content

Commit

Permalink
Release v2.8.0 (#691)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmojaki authored Dec 18, 2024
1 parent 9e629da commit 93db21e
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 24 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Release Notes

## [v2.8.0] (2024-12-18)

* 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
* Fix patching of ProcessPoolExecutor by @alexmojaki in [#690](https://github.com/pydantic/logfire/pull/690)
* Rearrange span processors to avoid repeating scrubbing and other tweaking by @alexmojaki in [#658](https://github.com/pydantic/logfire/pull/658)
* Remove end-on-exit stuff by @dmontagu in [#676](https://github.com/pydantic/logfire/pull/676)

## [v2.7.1] (2024-12-13)

* Fix erroneous `<circular reference>` when object is repeated in list by @alexmojaki in [#664](https://github.com/pydantic/logfire/pull/664)
Expand Down Expand Up @@ -472,3 +479,4 @@ First release from new repo!
[v2.6.2]: https://github.com/pydantic/logfire/compare/v2.6.1...v2.6.2
[v2.7.0]: https://github.com/pydantic/logfire/compare/v2.6.2...v2.7.0
[v2.7.1]: https://github.com/pydantic/logfire/compare/v2.7.0...v2.7.1
[v2.8.0]: https://github.com/pydantic/logfire/compare/v2.7.1...v2.8.0
2 changes: 1 addition & 1 deletion logfire-api/logfire_api/_internal/config.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ from .exporters.console import ConsoleColorsValues as ConsoleColorsValues, Inden
from .exporters.fallback import FallbackSpanExporter as FallbackSpanExporter
from .exporters.file import FileSpanExporter as FileSpanExporter
from .exporters.otlp import OTLPExporterHttpSession as OTLPExporterHttpSession, RetryFewerSpansSpanExporter as RetryFewerSpansSpanExporter
from .exporters.processor_wrapper import MainSpanProcessorWrapper as MainSpanProcessorWrapper
from .exporters.processor_wrapper import CheckSuppressInstrumentationProcessorWrapper as CheckSuppressInstrumentationProcessorWrapper, MainSpanProcessorWrapper as MainSpanProcessorWrapper
from .exporters.quiet_metrics import QuietMetricExporter as QuietMetricExporter
from .exporters.remove_pending import RemovePendingSpansExporter as RemovePendingSpansExporter
from .exporters.test import TestExporter as TestExporter
Expand Down
16 changes: 12 additions & 4 deletions logfire-api/logfire_api/_internal/exporters/processor_wrapper.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@ from ..db_statement_summary import message_from_db_statement as message_from_db_
from ..scrubbing import BaseScrubber as BaseScrubber
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
from .wrapper import WrapperSpanProcessor as WrapperSpanProcessor
from _typeshed import Incomplete
from dataclasses import dataclass
from opentelemetry import context
from opentelemetry.sdk.trace import ReadableSpan, Span, SpanProcessor
from opentelemetry.sdk.trace import ReadableSpan, Span

class CheckSuppressInstrumentationProcessorWrapper(WrapperSpanProcessor):
"""Checks if instrumentation is suppressed, then suppresses instrumentation itself.
Placed at the root of the tree of processors.
"""
def on_start(self, span: Span, parent_context: context.Context | None = None) -> None: ...
def on_end(self, span: ReadableSpan) -> None: ...

@dataclass
class MainSpanProcessorWrapper(WrapperSpanProcessor):
"""Wrapper around other processors to intercept starting and ending spans with our own global logic.
Suppresses starting/ending if the current context has a `suppress_instrumentation` value.
Tweaks the send/receive span names generated by the ASGI middleware.
"""
scrubber: Incomplete
def __init__(self, processor: SpanProcessor, scrubber: BaseScrubber) -> None: ...
scrubber: BaseScrubber
def on_start(self, span: Span, parent_context: context.Context | None = None) -> None: ...
def on_end(self, span: ReadableSpan) -> None: ...
5 changes: 3 additions & 2 deletions logfire-api/logfire_api/_internal/exporters/wrapper.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from _typeshed import Incomplete
from dataclasses import dataclass
from opentelemetry import context
from opentelemetry.sdk.metrics.export import AggregationTemporality as AggregationTemporality, MetricExportResult, MetricExporter, MetricsData
from opentelemetry.sdk.metrics.view import Aggregation as Aggregation
Expand All @@ -22,10 +23,10 @@ class WrapperMetricExporter(MetricExporter):
def force_flush(self, timeout_millis: float = 10000) -> bool: ...
def shutdown(self, timeout_millis: float = 30000, **kwargs: Any) -> None: ...

@dataclass
class WrapperSpanProcessor(SpanProcessor):
"""A base class for SpanProcessors that wrap another processor."""
processor: Incomplete
def __init__(self, processor: SpanProcessor) -> None: ...
processor: SpanProcessor
def on_start(self, span: Span, parent_context: context.Context | None = None) -> None: ...
def on_end(self, span: ReadableSpan) -> None: ...
def shutdown(self) -> None: ...
Expand Down
21 changes: 13 additions & 8 deletions logfire-api/logfire_api/_internal/integrations/httpx.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import httpx
from logfire import Logfire as Logfire
from logfire._internal.main import set_user_attributes_on_raw_span as set_user_attributes_on_raw_span
from logfire._internal.utils import handle_internal_errors as handle_internal_errors
from opentelemetry.instrumentation.httpx import AsyncRequestHook, AsyncResponseHook, RequestHook, RequestInfo, ResponseHook, ResponseInfo
from opentelemetry.trace import Span
from typing import Any, Callable, Literal, ParamSpec, TypeVar, TypedDict, Unpack, overload
Expand Down Expand Up @@ -27,17 +29,20 @@ AsyncHook = TypeVar('AsyncHook', AsyncRequestHook, AsyncResponseHook)
P = ParamSpec('P')

@overload
def instrument_httpx(logfire_instance: Logfire, client: httpx.Client, capture_request_headers: bool, capture_response_headers: bool, **kwargs: Unpack[ClientKwargs]) -> None: ...
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: ...
@overload
def instrument_httpx(logfire_instance: Logfire, client: httpx.AsyncClient, capture_request_headers: bool, capture_response_headers: bool, **kwargs: Unpack[AsyncClientKwargs]) -> None: ...
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: ...
@overload
def instrument_httpx(logfire_instance: Logfire, client: None, capture_request_headers: bool, capture_response_headers: bool, **kwargs: Unpack[HTTPXInstrumentKwargs]) -> None: ...
def make_capture_response_headers_hook(hook: ResponseHook | None) -> ResponseHook: ...
def make_capture_async_response_headers_hook(hook: AsyncResponseHook | None) -> AsyncResponseHook: ...
def make_capture_request_headers_hook(hook: RequestHook | None) -> RequestHook: ...
def make_capture_async_request_headers_hook(hook: AsyncRequestHook | None) -> AsyncRequestHook: ...
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: ...
def make_request_hook(hook: RequestHook | None, should_capture_headers: bool, should_capture_json: bool) -> RequestHook | None: ...
def make_async_request_hook(hook: AsyncRequestHook | RequestHook | None, should_capture_headers: bool, should_capture_json: bool) -> AsyncRequestHook | None: ...
def make_response_hook(hook: ResponseHook | None, should_capture_headers: bool) -> ResponseHook | None: ...
def make_async_response_hook(hook: ResponseHook | AsyncResponseHook | None, should_capture_headers: bool) -> AsyncResponseHook | None: ...
async def run_async_hook(hook: Callable[P, Any] | None, *args: P.args, **kwargs: P.kwargs) -> None: ...
def run_hook(hook: Callable[P, Any] | None, *args: P.args, **kwargs: P.kwargs) -> None: ...
def capture_response_headers(span: Span, request: RequestInfo, response: ResponseInfo) -> None: ...
def capture_response_headers(span: Span, response: ResponseInfo) -> None: ...
def capture_request_headers(span: Span, request: RequestInfo) -> None: ...
def capture_headers(span: Span, headers: httpx.Headers, request_or_response: Literal['request', 'response']) -> None: ...
def get_charset(content_type: str) -> str: ...
def decode_body(body: bytes, content_type: str): ...
def capture_request_body(span: Span, request: RequestInfo) -> None: ...
6 changes: 3 additions & 3 deletions logfire-api/logfire_api/_internal/main.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -551,11 +551,11 @@ class Logfire:
def instrument_asyncpg(self, **kwargs: Unpack[AsyncPGInstrumentKwargs]) -> None:
"""Instrument the `asyncpg` module so that spans are automatically created for each query."""
@overload
def instrument_httpx(self, client: httpx.Client, capture_request_headers: bool = False, capture_response_headers: bool = False, **kwargs: Unpack[ClientKwargs]) -> None: ...
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: ...
@overload
def instrument_httpx(self, client: httpx.AsyncClient, capture_request_headers: bool = False, capture_response_headers: bool = False, **kwargs: Unpack[AsyncClientKwargs]) -> None: ...
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: ...
@overload
def instrument_httpx(self, client: None = None, capture_request_headers: bool = False, capture_response_headers: bool = False, **kwargs: Unpack[HTTPXInstrumentKwargs]) -> None: ...
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: ...
def instrument_celery(self, **kwargs: Any) -> None:
"""Instrument `celery` so that spans are automatically created for each task.
Expand Down
7 changes: 5 additions & 2 deletions logfire-api/logfire_api/_internal/tracer.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,13 @@ class SuppressedTracer(Tracer):
class PendingSpanProcessor(SpanProcessor):
"""Span processor that emits an extra pending span for each span as it starts.
The pending span is emitted by calling `on_end` on all other processors.
The pending span is emitted by calling `on_end` on the inner `processor`.
This is intentionally not a `WrapperSpanProcessor` to avoid the default implementations of `on_end`
and `shutdown`. This processor is expected to contain processors which are already included
elsewhere in the pipeline where `on_end` and `shutdown` are called normally.
"""
id_generator: IdGenerator
other_processors: tuple[SpanProcessor, ...]
processor: SpanProcessor
def on_start(self, span: Span, parent_context: context_api.Context | None = None) -> None: ...

def should_sample(span_context: SpanContext, attributes: Mapping[str, otel_types.AttributeValue]) -> bool:
Expand Down
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 = "2.7.1"
version = "2.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 = "2.7.1"
version = "2.8.0"
description = "The best Python observability tool! 🪵🔥"
requires-python = ">=3.8"
authors = [
Expand Down
4 changes: 2 additions & 2 deletions uv.lock

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

0 comments on commit 93db21e

Please sign in to comment.