# 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'
    }
)
```

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

### [Standard library logging](https://docs.sentry.io/platforms/python/logs.md#standard-library-logging)

The SDK's `LoggingIntegration` instruments standard library loggers in order to send Sentry structured logs to Sentry.

```python
import sentry_sdk
import logging

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

# Your existing logging setup
my_logger = logging.getLogger(__name__)
my_logger.setLevel(logging.INFO)

my_value = 42
my_logger.debug('In this example debug events will not be sent to Sentry logs. my_value=%s', my_value)
my_logger.info('But info events will be sent to Sentry logs. my_value=%s', my_value)
```

By default, the logging integration sends `INFO`-level logs and higher to Sentry logs. You can set a different threshold via the `LoggingIntegration`'s `sentry_logs_level` parameter. However, regardless of the `sentry_logs_level` setting, the SDK only sends logs if they are at or above the logger's level.

#### [Extra Fields as Searchable Attributes](https://docs.sentry.io/platforms/python/logs.md#extra-fields-as-searchable-attributes)

When using the standard library logging with Sentry logs, any fields provided in the `extra` dictionary are automatically promoted to top-level attributes on the log entry, making them searchable and filterable in the Sentry UI.

```python
import sentry_sdk
import logging

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

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# Extra fields become searchable attributes
logger.info(
    "User action completed",
    extra={
        "user_id": 12345,
        "action": "purchase",
        "item_count": 3,
        "total_amount": 29.97
    }
)
```

In this example, `user_id`, `action`, `item_count`, and `total_amount` will appear as separate, searchable attributes in the Sentry logs interface. You can filter logs using these attributes directly, such as `user_id:12345` or `action:purchase`.

```python
import sentry_sdk
import logging
from sentry_sdk.integrations.logging import LoggingIntegration

sentry_sdk.init(
    dsn="___PUBLIC_DSN___",
    enable_logs=True,
    integrations=[
        # Only send WARNING (and higher) logs to Sentry logs,
        # even if the logger is set to a lower level.
        LoggingIntegration(sentry_logs_level=logging.WARNING),
    ]
)

my_logger = logging.getLogger(__name__)
my_logger.setLevel(logging.INFO)

my_value = 42
my_logger.info('This will not be sent to Sentry logs, even though the logger is set to INFO. my_value=%s', my_value)
my_logger.warning('This will be sent to Sentry logs. my_value=%s', my_value)

my_logger.setLevel(logging.ERROR)
my_logger.warning('Now, this log message will not be sent to Sentry logs, since the logger is set to ERROR.')
```

The logging integration automatically monkeypatches a handler into all loggers except for the root logger. If you'd like to manually configure the handler, you can do that like so:

```python
import sentry_sdk
from sentry_sdk.integrations.logging import SentryLogsHandler
from sentry_sdk.integrations.logging import LoggingIntegration

sentry_sdk.init(
    dsn="___PUBLIC_DSN___",
    enable_logs=True,
    integrations=[
        LoggingIntegration(sentry_logs_level=None),  # Do not monkeypatch the sentry handler
    ],
}

# Instead, configure the root logger to send INFO-level logs to Sentry
logging.basicConfig(level=logging.INFO, handlers=[SentryLogsHandler(level=logging.INFO)])
```

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

Loguru logs can also be automatically captured and sent to Sentry.

```python
import sentry_sdk
from loguru import logger

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

logger.debug("In this example, debug events will not be sent to Sentry logs.")
logger.info("On the other hand, info events will be sent to Sentry logs.")
```

By default, the Loguru integration sends `INFO`-level and higher logs to Sentry logs as long as `enable_logs` is `True`. A different threshold can be set via the `LoguruIntegration`'s `sentry_logs_level` parameter.

```python
import sentry_sdk
from loguru import logger
from sentry_sdk.integrations.loguru import LoggingLevels, LoguruIntegration

sentry_sdk.init(
    dsn="___PUBLIC_DSN___",
    enable_logs=True,
    integrations=[
        # Only send WARNING (and higher) logs to Sentry logs
        LoguruIntegration(sentry_logs_level=LoggingLevels.WARNING.value),
    ],
)

logger.info("This INFO log won't be sent to Sentry logs.")
logger.warning("This WARNING log will be sent to Sentry logs.")
```

If you want other logging integrations to send logs to Sentry logs, but not Loguru, setting `sentry_logs_level` to `None` on the integration level will stop the Loguru integration for capturing Sentry logs.

```python

import sentry_sdk
from loguru import logger
from sentry_sdk.integrations.loguru import LoguruIntegration

sentry_sdk.init(
    dsn="___PUBLIC_DSN___",
    # In general, we want to capture logs as Sentry logs...
    enable_logs=True,
    integrations=[
        # ...just not from Loguru
        LoguruIntegration(sentry_logs_level=None),
    ]
)

logger.error("This won't be sent to Sentry logs.")
```

## [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.

## [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`.
