Skip to content

Commit ede767f

Browse files
authored
Release v4.19.0 (#1631)
1 parent 7a3e157 commit ede767f

File tree

10 files changed

+42
-17
lines changed

10 files changed

+42
-17
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+
## [v4.19.0] (2026-01-16)
4+
5+
* Add DSPy integration to logfire by @bdsaglam in [#1625](https://github.com/pydantic/logfire/pull/1625)
6+
* Set log level based on HTTP status code, create issues for handled exceptions in FastAPI when the status code is 5xx by @alexmojaki in [#1628](https://github.com/pydantic/logfire/pull/1628)
7+
* Add OTel GenAI semantic convention attributes to LLM instrumentations by @jimilp7 in [#1619](https://github.com/pydantic/logfire/pull/1619)
8+
* Minor optimization: move tweaking of ASGI send/receive span level by @alexmojaki in [#1629](https://github.com/pydantic/logfire/pull/1629)
9+
310
## [v4.18.0] (2026-01-12)
411

512
* Adds `aiohttp` request body capture. by @adtyavrdhn in [#1595](https://github.com/pydantic/logfire/pull/1595)
@@ -1000,3 +1007,4 @@ First release from new repo!
10001007
[v4.16.0]: https://github.com/pydantic/logfire/compare/v4.15.1...v4.16.0
10011008
[v4.17.0]: https://github.com/pydantic/logfire/compare/v4.16.0...v4.17.0
10021009
[v4.18.0]: https://github.com/pydantic/logfire/compare/v4.17.0...v4.18.0
1010+
[v4.19.0]: https://github.com/pydantic/logfire/compare/v4.18.0...v4.19.0

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
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_TAGS_KEY as ATTRIBUTES_TAGS_KEY, LEVEL_NUMBERS as LEVEL_NUMBERS, log_level_attributes as log_level_attributes
1+
from ..constants import ATTRIBUTES_EXCEPTION_FINGERPRINT_KEY as ATTRIBUTES_EXCEPTION_FINGERPRINT_KEY, 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_TAGS_KEY as ATTRIBUTES_TAGS_KEY, LEVEL_NUMBERS as LEVEL_NUMBERS, log_level_attributes as log_level_attributes
22
from ..db_statement_summary import message_from_db_statement as message_from_db_statement
33
from ..json_schema import JsonSchemaProperties as JsonSchemaProperties, attributes_json_schema as attributes_json_schema
44
from ..scrubbing import BaseScrubber as BaseScrubber
@@ -24,7 +24,6 @@ class MainSpanProcessorWrapper(WrapperSpanProcessor):
2424
Tweaks the send/receive span names generated by the ASGI middleware.
2525
"""
2626
scrubber: BaseScrubber
27-
def on_start(self, span: Span, parent_context: context.Context | None = None) -> None: ...
2827
def on_end(self, span: ReadableSpan) -> None: ...
2928

3029
def guess_system(model: str, default: str = ''): ...

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from collections.abc import Awaitable
22
from dataclasses import dataclass
33
from logfire import Logfire as Logfire
4+
from logfire._internal.constants import log_level_attributes as log_level_attributes
45
from logfire._internal.utils import is_asgi_send_receive_span_name as is_asgi_send_receive_span_name, maybe_capture_server_headers as maybe_capture_server_headers
56
from opentelemetry.context import Context
6-
from opentelemetry.trace import Span, Tracer, TracerProvider
7+
from opentelemetry.trace import Span, SpanKind, Tracer, TracerProvider
8+
from opentelemetry.util import types as otel_types
79
from typing import Any, Callable, Protocol, TypedDict
810
from typing_extensions import Unpack
911

@@ -26,17 +28,23 @@ class ASGIInstrumentKwargs(TypedDict, total=False):
2628
http_capture_headers_sanitize_fields: list[str] | None
2729

2830
def tweak_asgi_spans_tracer_provider(logfire_instance: Logfire, record_send_receive: bool) -> TracerProvider:
29-
"""If record_send_receive is False, return a TracerProvider that skips spans for ASGI send and receive events."""
31+
"""Return a TracerProvider that customizes ASGI send/receive spans.
32+
33+
If record_send_receive is False, spans are filtered out.
34+
If record_send_receive is True, spans are created with debug log level.
35+
"""
3036

3137
@dataclass
3238
class TweakAsgiTracerProvider(TracerProvider):
3339
tracer_provider: TracerProvider
40+
record_send_receive: bool
3441
def get_tracer(self, *args: Any, **kwargs: Any) -> Tracer: ...
3542

3643
@dataclass
3744
class TweakAsgiSpansTracer(Tracer):
3845
tracer: Tracer
39-
def start_span(self, name: str, context: Context | None = None, *args: Any, **kwargs: Any) -> Span: ...
46+
record_send_receive: bool
47+
def start_span(self, name: str, context: Context | None = None, kind: SpanKind = ..., attributes: otel_types.Attributes = None, *args: Any, **kwargs: Any) -> Span: ...
4048
start_as_current_span = ...
4149

4250
def instrument_asgi(logfire_instance: Logfire, app: ASGIApp, *, record_send_receive: bool = False, capture_headers: bool = False, **kwargs: Unpack[ASGIInstrumentKwargs]) -> ASGIApp:
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import logfire
2+
from typing import Any
3+
4+
def instrument_dspy(logfire_instance: logfire.Logfire, **kwargs: Any): ...

logfire-api/logfire_api/_internal/main.pyi

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ from opentelemetry.context import Context as Context
4141
from opentelemetry.instrumentation.asgi.types import ClientRequestHook, ClientResponseHook, ServerRequestHook
4242
from opentelemetry.metrics import CallbackT as CallbackT, Counter, Histogram, UpDownCounter, _Gauge as Gauge
4343
from opentelemetry.sdk.trace import ReadableSpan, Span
44-
from opentelemetry.trace import SpanContext
44+
from opentelemetry.trace import SpanContext, SpanKind
4545
from opentelemetry.util import types as otel_types
4646
from pymongo.monitoring import CommandFailedEvent as CommandFailedEvent, CommandStartedEvent as CommandStartedEvent, CommandSucceededEvent as CommandSucceededEvent
4747
from sqlalchemy import Engine
@@ -218,7 +218,7 @@ class Logfire:
218218
_exc_info: Set to an exception or a tuple as returned by [`sys.exc_info()`][sys.exc_info]
219219
to record a traceback with the log message.
220220
"""
221-
def span(self, msg_template: str, /, *, _tags: Sequence[str] | None = None, _span_name: str | None = None, _level: LevelName | None = None, _links: Sequence[tuple[SpanContext, otel_types.Attributes]] = (), **attributes: Any) -> LogfireSpan:
221+
def span(self, msg_template: str, /, *, _tags: Sequence[str] | None = None, _span_name: str | None = None, _level: LevelName | None = None, _links: Sequence[tuple[SpanContext, otel_types.Attributes]] = (), _span_kind: SpanKind = ..., **attributes: Any) -> LogfireSpan:
222222
"""Context manager for creating a span.
223223
224224
```py
@@ -236,6 +236,10 @@ class Logfire:
236236
_tags: An optional sequence of tags to include in the span.
237237
_level: An optional log level name.
238238
_links: An optional sequence of links to other spans. Each link is a tuple of a span context and attributes.
239+
_span_kind: The [OpenTelemetry span kind](https://opentelemetry.io/docs/concepts/signals/traces/#span-kind).
240+
If not provided, defaults to `INTERNAL`.
241+
Users don't typically need to set this.
242+
Not related to the `kind` column of the `records` table in Logfire.
239243
attributes: The arguments to include in the span and format the message template with.
240244
Attributes starting with an underscore are not allowed.
241245
"""
@@ -616,6 +620,13 @@ class Logfire:
616620
[`openinference-instrumentation-litellm`](https://pypi.org/project/openinference-instrumentation-litellm/)
617621
package, to which it passes `**kwargs`.
618622
"""
623+
def instrument_dspy(self, **kwargs: Any):
624+
"""Instrument [DSPy](https://dspy.ai/).
625+
626+
Uses the `DSPyInstrumentor().instrument()` method of the
627+
[`openinference-instrumentation-dspy`](https://pypi.org/project/openinference-instrumentation-dspy/)
628+
package, to which it passes `**kwargs`.
629+
"""
619630
def instrument_print(self) -> AbstractContextManager[None]:
620631
"""Instrument the built-in `print` function so that calls to it are logged.
621632
@@ -1136,7 +1147,7 @@ class FastLogfireSpan:
11361147
def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: Any) -> None: ...
11371148

11381149
class LogfireSpan(ReadableSpan):
1139-
def __init__(self, span_name: str, otlp_attributes: dict[str, otel_types.AttributeValue], tracer: _ProxyTracer, json_schema_properties: JsonSchemaProperties, links: Sequence[tuple[SpanContext, otel_types.Attributes]]) -> None: ...
1150+
def __init__(self, span_name: str, otlp_attributes: dict[str, otel_types.AttributeValue], tracer: _ProxyTracer, json_schema_properties: JsonSchemaProperties, links: Sequence[tuple[SpanContext, otel_types.Attributes]], span_kind: SpanKind = ...) -> None: ...
11401151
def __getattr__(self, name: str) -> Any: ...
11411152
def __enter__(self) -> LogfireSpan: ...
11421153
@handle_internal_errors

logfire-api/logfire_api/_internal/tracer.pyi

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ from opentelemetry.sdk.trace.id_generator import IdGenerator
1414
from opentelemetry.trace import Link as Link, Span, SpanContext, SpanKind, Tracer, TracerProvider
1515
from opentelemetry.trace.status import Status, StatusCode
1616
from opentelemetry.util import types as otel_types
17-
from starlette.exceptions import HTTPException
1817
from threading import Lock
1918
from typing import Any, Callable
20-
from typing_extensions import TypeIs
2119
from weakref import WeakKeyDictionary, WeakValueDictionary
2220

2321
OPEN_SPANS: WeakValueDictionary[tuple[int, int], _LogfireWrappedSpan]
@@ -116,4 +114,3 @@ def get_sample_rate_from_attributes(attributes: otel_types.Attributes) -> float
116114
def record_exception(span: trace_api.Span, exception: BaseException, *, attributes: otel_types.Attributes = None, timestamp: int | None = None, escaped: bool = False, callback: ExceptionCallback | None = None) -> None:
117115
"""Similar to the OTEL SDK Span.record_exception method, with our own additions."""
118116
def set_exception_status(span: trace_api.Span, exception: BaseException): ...
119-
def is_starlette_http_exception(exception: BaseException) -> TypeIs[HTTPException]: ...

logfire-api/logfire_api/types.pyi

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ class ExceptionCallbackHelper:
4949
- Spans created directly by an OpenTelemetry tracer (e.g. from any `logfire.instrument_*()` method)
5050
typically don't have a level set, so this will return the default of `info`,
5151
but `level_is_unset` will be `True`.
52-
- FastAPI/Starlette 4xx HTTPExceptions are warnings.
5352
- Will be a different level if this is created by e.g. `logfire.info(..., _exc_info=True)`.
5453
"""
5554
@level.setter
@@ -117,7 +116,6 @@ class ExceptionCallbackHelper:
117116
118117
- The level is \'error\' or higher or is unset (see `level_is_unset` for details),
119118
- No parent span exists in the current process,
120-
- The exception isn\'t handled by FastAPI, except if it\'s a 5xx HTTPException.
121119
122120
Example:
123121
if helper.create_issue:

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 = "4.18.0"
7+
version = "4.19.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 = "4.18.0"
7+
version = "4.19.0"
88
description = "The best Python observability tool! 🪵🔥"
99
requires-python = ">=3.9"
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)