Skip to content

Latest commit

 

History

History
80 lines (58 loc) · 3.59 KB

File metadata and controls

80 lines (58 loc) · 3.59 KB

Pydantic Logfire is an observability platform built on OpenTelemetry. This repository contains the Python SDK for Logfire and documentation. The server application for recording and displaying data is closed source.

Key aspects:

  • Opinionated wrapper around OpenTelemetry (traces, metrics, logs)
  • Extensive integrations with popular Python packages
  • SQL-based querying of telemetry data

Code Quality

Pre-commit automatically runs ruff and pyright, but you can also run make format/lint/typecheck to run them explicitly, particularly to check files that haven't been changed.

Documentation

uv run mkdocs build --no-strict to build docs, just to check for errors. Expect lots of warnings, only worry about a non-zero exit code.

Core Structure

logfire/
├── __init__.py              # Public API via DEFAULT_LOGFIRE_INSTANCE
├── _internal/               # Internal implementation
│   ├── main.py              # Logfire and LogfireSpan classes
│   ├── config.py            # LogfireConfig, configuration setup
│   ├── config_params.py     # Environment variable and config file handling
│   ├── tracer.py            # ProxyTracerProvider, tracer wrapping
│   ├── metrics.py           # ProxyMeterProvider, metrics handling
│   ├── exporters/           # OTLP, console, test exporters and processors
│   ├── integrations/        # Framework-specific instrumentation
│   ├── auto_trace/          # AST rewriting for auto-instrumentation
│   └── ...
├── integrations/            # Public integration APIs
└── experimental/            # Experimental features

logfire-api/                 # No-op shim package for libraries
tests/                       # Test suite
docs/                        # MkDocs documentation

Testing

Tests that create spans should follow this pattern:

from inline_snapshot import snapshot
from logfire.testing import TestExporter
import logfire

def test_my_thing(exporter: TestExporter):
    # create spans, e.g:
    with logfire.span("a span"):
        ...

    assert exporter.exported_spans_as_dict(parse_json_attributes=True) == snapshot()

Then run uv run pytest -k test_my_thing --inline-snapshot=fix to automatically fill in snapshot() with a list of dicts and check that the results are sane. If the output changes, running again will automatically update the snapshot in the code. TestExporter normalizes common things. If some remaining fields are non-deterministic (e.g., IDs, timestamps), use dirty_equals matchers, e.g:

from dirty_equals import IsStr
from inline_snapshot import snapshot

assert ... == snapshot({
    'name': 'foo',
    'random_id': IsStr(),
})

Use @pytest.mark.anyio for async tests.

Some tests are decorated with @pytest.mark.vcr() and use pytest-recording to record HTTP interactions. Existing VCR cassette files should suffice. When creating a new test like this, run uv run pytest -k test_my_thing --inline-snapshot=fix --record-mode=rewrite.

logfire-api

The logfire-api package is a no-op shim that libraries can depend on to avoid hard dependencies on Logfire itself. It provides minimal 'implementations' in logfire-api/logfire_api/__init__.py, which needs to be kept up to date with the public API of the logfire module, especially if test_logfire_api.py starts failing. The rest is just .pyi stubs which should be ignored and are autogenerated when needed during release.

Misc

Use git push origin HEAD to push, not just git push, so that it pushes to the current branch without needing to set upstream explicitly.