docs: add logfire to Logging intro

The intro did not mention a README entry added after it was written, so readers got no advice on it.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Vinta Chen
2026-11-08 22:35:51 +08:00
co-authored by Claude
parent 990411a90f
commit 9d93aae82b
+3
View File
@@ -7,6 +7,7 @@ How to choose:
- An app already on logging that needs structured output: structlog, which wraps it
- A script you want logging in with no setup: Loguru
- Log files that rotate, expire, and compress: Loguru
- Logs next to traces and metrics, on a hosted platform: Logfire
Every Python module [can take part in the standard library's logging](https://docs.python.org/3/library/logging.html), so your app's log holds messages from third-party packages next to your own. In each module, create a logger with [`logging.getLogger(__name__)`](https://docs.python.org/3/howto/logging.html#advanced-logging-tutorial), so logger names follow your package layout. Use `basicConfig()` for a quick setup, and move to [`dictConfig()`](https://docs.python.org/3/howto/logging.html#configuring-logging), which the docs recommend for new applications. In a library, [add no handler other than `NullHandler`](https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library) and don't log to the root logger: handlers are for the app developer to pick.
@@ -14,4 +15,6 @@ structlog logs [events in a context of key-value pairs](https://www.structlog.or
Loguru has [one logger, ready to use](https://loguru.readthedocs.io/en/latest/overview.html#ready-to-use-out-of-the-box-without-boilerplate) after `from loguru import logger`, and it writes to stderr out of the box. Instead of handlers, formatters, and filters, you configure it with [one function, `add()`](https://loguru.readthedocs.io/en/latest/overview.html#no-handler-no-formatter-no-filter-one-function-to-rule-them-all). In an app, [call `remove()` first](https://loguru.readthedocs.io/en/latest/resources/troubleshooting.html#how-do-i-create-and-configure-a-logger) to drop the default handler, then `add()` where your logs should go. Given a file path, `add()` handles [rotation, retention, and compression](https://loguru.readthedocs.io/en/latest/overview.html#easier-file-logging-with-rotation-retention-compression), and [`serialize=True`](https://loguru.readthedocs.io/en/latest/overview.html#structured-logging-as-needed) turns each message into JSON. In a library, [call `disable()` instead of `add()`](https://loguru.readthedocs.io/en/latest/overview.html#suitable-for-scripts-and-libraries), and the app using it can `enable()` your logs again.
Logfire is an [observability platform built on OpenTelemetry](https://pydantic.dev/docs/logfire/get-started/why/), so your logs show up next to the traces and metrics from the rest of your code. Unlike the standard library, structlog, and Loguru, it's a [hosted service with paid plans](https://pydantic.dev/pricing): the SDK [sends your data to Logfire, where it's stored](https://pydantic.dev/docs/logfire/get-started/first-trace/#before-you-start). You can also [export to any backend that supports OpenTelemetry](https://pydantic.dev/docs/logfire/guides/alternative-backends/). [Call `logfire.configure()`, then log with `logfire.info()` inside a `logfire.span()`](https://pydantic.dev/docs/logfire/get-started/first-trace/#or-do-it-by-hand): the span records one operation, and together they make a trace. To send the logs you already write, add [`LogfireLoggingHandler`](https://pydantic.dev/docs/logfire/integrations/logging/logging/) to the standard library's logging, [`StructlogProcessor`](https://pydantic.dev/docs/logfire/integrations/logging/structlog/) to structlog's processors before the renderer, or [`loguru_handler()`](https://pydantic.dev/docs/logfire/integrations/logging/loguru/) as a Loguru sink.
Whichever you pick, configure logging once, where your app starts, and have each module only get its logger. With the standard library, usually [only the root logger needs configuring](https://docs.python.org/3/library/logging.html), since module loggers pass their messages up to it. structlog wants [`structlog.configure()` on app initialization](https://www.structlog.org/en/latest/configuration.html), and with Loguru, [your other modules inherit the configuration](https://loguru.readthedocs.io/en/latest/resources/troubleshooting.html#how-do-i-create-and-configure-a-logger) from your entry point. Third-party packages that use the standard library's logging keep logging there. Send their messages to your output too: structlog [formats them with `ProcessorFormatter`](https://www.structlog.org/en/latest/standard-library.html#processor-formatter), and Loguru [intercepts them with a handler](https://loguru.readthedocs.io/en/latest/overview.html#entirely-compatible-with-standard-logging).