Skip to content

Pydantic plugin: docs say third-party modules are not instrumented by default, but empty include instruments everything #2053

Description

@mecampbellsoup

Description

The logfire.instrument_pydantic docstring for the include parameter states:

By default, third party modules are not instrumented. This option allows you to include specific modules.

But in the installed implementation (v4.34.0), _include_model in logfire/integrations/pydantic.py contains no third-party detection at all. The decision is:

  1. a hardcoded ignore list of exactly three modules (fastapi, logfire_backend, fastui),
  2. user exclude patterns,
  3. user include patterns — and if include is empty, it returns True for every model.

So logfire.instrument_pydantic(record="failure") with no include instruments every pydantic model in the process. In our Django app that was 2,221 model classes at startup (verified by adding a print inside _include_model at runtime), the overwhelming majority third-party (openai SDK, opik, mem0, ...).

Why it matters

With record="failure", this records third-party libraries' internal, by-design validation fallbacks as warnings:

  • Opik's OpenAI usage parser deliberately tries a Completions-shaped schema first, catches the ValidationError, and falls back to a Responses-shaped one — one recorded "Validation on OpenAICompletionsUsage failed" per LLM call.
  • The OpenAI SDK's construct_type tries strict validation of its stream-event union before falling back to lenient construction — each mismatch records "Validation on union failed" with all ~101 enumerated union-member errors as attributes, per event.

None of these are actionable failures — they're libraries' internal try/except control flow — but they generate warning-level noise and span/attribute volume (quota) on every LLM call.

Expected

Either the documented default (don't instrument third-party modules unless included) is implemented, or the docstring/docs are corrected to say the default is instrument-everything, so users know they must pass include themselves. We worked around it with include={r"^apps\..*", ...} — note also that since _include_model matches with re.search(f'{pattern}$', ...) (end-anchored only), users must remember the leading ^ or patterns like apps\..* unexpectedly match third-party modules such as django.apps.config mid-path — worth a docs example if the current behavior is kept.

Python, Logfire & OS Versions

logfire 4.34.0
pydantic 2.13.4
python 3.14.0
platform: linux (Docker, Django app)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions