---
title: "Logs"
description: "Structured logs allow you to send, view and query logs sent from your applications within Sentry."
url: https://docs.sentry.io/platforms/python/logs/
---

# Set Up Logs | Sentry for Python

With Sentry Structured Logs, you can send text-based log information from your applications to Sentry. Once in Sentry, these logs can be viewed alongside relevant errors, searched by text-string, or searched using their individual attributes.

## [Requirements](https://docs.sentry.io/platforms/python/logs.md#requirements)

Logs for Python are supported in Sentry Python SDK version `2.35.0` and above.

```bash
pip install "sentry-sdk"
```

## [Setup](https://docs.sentry.io/platforms/python/logs.md#setup)

To enable logging, you need to initialize the SDK with the `enable_logs` option set to `True`.

```python
sentry_sdk.init(
    dsn="___PUBLIC_DSN___",
    enable_logs=True,
)
```

## [Usage](https://docs.sentry.io/platforms/python/logs.md#usage)

Once the feature is enabled on the SDK and the SDK is initialized, you can send logs using the `sentry_sdk.logger` APIs.

The `logger` namespace exposes six methods that you can use to log messages at different log levels: `trace`, `debug`, `info`, `warning`, `error`, and `fatal`.

You can send structured messages by using the `{attribute_name}` placeholder syntax. The properties of this message will be sent to Sentry, and can be searched from within the Logs UI, and even added to the Logs views as a dedicated column.

```python
from sentry_sdk import logger as sentry_logger

sentry_logger.trace('Starting database connection {database}', database="users")
sentry_logger.debug('Cache miss for user {user_id}', user_id=123)
sentry_logger.info('Updated global cache')
sentry_logger.warning('Rate limit reached for endpoint {endpoint}', endpoint='/api/results/')
sentry_logger.error('Failed to process payment. Order: {order_id}. Amount: {amount}', order_id="or_2342", amount=99.99)
sentry_logger.fatal('Database {database} connection pool exhausted', database="users")
```

You can also pass additional attributes directly to the logging functions via the `attributes` kwarg.

```python
from sentry_sdk import logger as sentry_logger

sentry_logger.error(
    'Payment processing failed',
    attributes={
        'payment.provider': 'stripe',
        'payment.method': 'credit_card',
        'payment.currency': 'USD',
        'user.subscription_tier': 'premium'
    }
)
```

## [Options](https://docs.sentry.io/platforms/python/logs.md#options)

#### [before\_send\_log](https://docs.sentry.io/platforms/python/logs.md#before_send_log)

To filter logs, or update them before they are sent to Sentry, you can use the `before_send_log` option.

```python
import sentry_sdk
from sentry_sdk.types import Log, Hint
from typing import Optional

def before_log(log: Log, _hint: Hint) -> Optional[Log]:
    # Filter out all info level logs
    if log["severity_text"] == "info":
        return None
    return log

sentry_sdk.init(
    dsn="___PUBLIC_DSN___",
    enable_logs=True,
    before_send_log=before_log,
)
```

The `before_send_log` function receives a log object, and should return the log object if you want it to be sent to Sentry, or `None` if you want to discard it.

The log dict has the following keys:

* `severity_text`: (`str` - one of `trace`, `debug`, `info`, `warning`, `error`, `fatal`) The log level.
* `severity_number`: (`int`) The log level as a number ranging from 1 to 24, as per the OpenTelemetry specification of [`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber).
* `body`: (`str`) The log message.
* `attributes`: (`dict[str, str | bool | float | int]`) Additional attributes to be sent with the log.
* `time_unix_nano`: (`int`) The timestamp of the log in nanoseconds since the Unix epoch.
* `trace_id`: (`Optional[str]`) The trace ID of the trace this log belongs to.

## [Best Practices](https://docs.sentry.io/platforms/python/logs.md#best-practices)

### [Wide Events Over Scattered Logs](https://docs.sentry.io/platforms/python/logs.md#wide-events-over-scattered-logs)

Instead of many thin logs that are hard to correlate, emit one comprehensive log per operation with all relevant context.

This makes debugging dramatically faster — one query returns everything about a specific order, user, or request.

```python
# ❌ Scattered thin logs
sentry_logger.info("Starting checkout")
sentry_logger.info("Validating cart")
sentry_logger.info("Processing payment")
sentry_logger.info("Checkout complete")

# ✅ One wide event with full context
sentry_logger.info(
    "Checkout completed",
    attributes={
        "order_id": order.id,
        "user_id": user.id,
        "user_tier": user.subscription,
        "cart_value": cart.total,
        "item_count": len(cart.items),
        "payment_method": "stripe",
        "duration_ms": (time.time() - start_time) * 1000,
    }
)
```

### [Include Business Context](https://docs.sentry.io/platforms/python/logs.md#include-business-context)

Add attributes that help you prioritize and debug:

* **User context** — tier, account age, lifetime value
* **Transaction data** — order value, item count
* **Feature state** — active feature flags
* **Request metadata** — endpoint, method, duration

This lets you filter logs by high-value customers or specific features.

```python
sentry_logger.info(
    "API request completed",
    attributes={
        # User context
        "user_id": user.id,
        "user_tier": user.plan,  # "free" | "pro" | "enterprise"
        "account_age_days": user.age_days,

        # Request data
        "endpoint": "/api/orders",
        "method": "POST",
        "duration_ms": 234,

        # Business context
        "order_value": 149.99,
        "feature_flags": ["new-checkout", "discount-v2"],
    }
)
```

### [Consistent Attribute Naming](https://docs.sentry.io/platforms/python/logs.md#consistent-attribute-naming)

Pick a naming convention and stick with it across your codebase. Inconsistent names make queries impossible.

**Recommended:** Use `snake_case` for custom attributes to match Python conventions.

```python
# ❌ Inconsistent naming
{"user": "123"}
{"userId": "123"}
{"user_id": "123"}
{"UserID": "123"}

# ✅ Consistent snake_case
{
    "user_id": "123",
    "order_id": "456",
    "cart_value": 99.99,
    "item_count": 3,
}
```

## [Default Attributes](https://docs.sentry.io/platforms/python/logs.md#default-attributes)

The Python SDK automatically sets several default attributes on all log entries to provide context and improve debugging:

### [Core Attributes](https://docs.sentry.io/platforms/python/logs.md#core-attributes)

* `environment`: The environment set in the SDK if defined. This is sent from the SDK as `sentry.environment`.
* `release`: The release set in the SDK if defined. This is sent from the SDK as `sentry.release`.
* `sdk.name`: The name of the SDK that sent the log. This is sent from the SDK as `sentry.sdk.name`.
* `sdk.version`: The version of the SDK that sent the log. This is sent from the SDK as `sentry.sdk.version`.

### [Message Template Attributes](https://docs.sentry.io/platforms/python/logs.md#message-template-attributes)

If the log was parameterized, Sentry adds the message template and parameters as log attributes.

* `message.template`: The parameterized template string. This is sent from the SDK as `sentry.message.template`.
* `message.parameter.X`: The parameters to fill the template string. X can either be the number that represent the parameter's position in the template string (`sentry.message.parameter.0`, `sentry.message.parameter.1`, etc) or the parameter's name (`sentry.message.parameter.item_id`, `sentry.message.parameter.user_id`, etc). This is sent from the SDK as `sentry.message.parameter.X`.

### [Server Attributes](https://docs.sentry.io/platforms/python/logs.md#server-attributes)

* `server.address`: The address of the server that sent the log. Equivalent to `server_name` that gets attached to Sentry errors.

### [User Attributes](https://docs.sentry.io/platforms/python/logs.md#user-attributes)

If user information is available in the current scope, the following attributes are added to the log:

* `user.id`: The user ID.
* `user.name`: The username.
* `user.email`: The email address.

### [Integration Attributes](https://docs.sentry.io/platforms/python/logs.md#integration-attributes)

If a log is generated by an SDK integration, the SDK will set additional attributes to help you identify the source of the log.

* `origin`: The origin of the log. This is sent from the SDK as `sentry.origin`.

## [Other Logging Integrations](https://docs.sentry.io/platforms/python/logs.md#other-logging-integrations)

Available integrations:

* [Standard library logging](https://docs.sentry.io/platforms/python/integrations/logging.md)
* [Loguru](https://docs.sentry.io/platforms/python/integrations/loguru.md)

If there's an integration you would like to see, open a [new issue on GitHub](https://github.com/getsentry/sentry-python/issues/new/choose).
