Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,34 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
- The UnraisableHookIntegration is now enabled by default.
- We now don't suppress chained exceptions in the ASGI and asyncio integrations by default. The related `suppress_asgi_chained_exceptions` experimental option was removed.

### Loguru

- The Loguru logging integration is not auto-enabled by default anymore if you have Loguru installed. To continue using it, add it to the `integrations` list in your `sentry_sdk.init()`:

```python
import sentry_sdk
from sentry_sdk.integrations.loguru import LoguruIntegration

sentry_sdk.init(
integrations=[
LoguruIntegration(),
]
)
```

- The `level` integration option is now called `breadcrumb_level`.
- The `sentry_logs_level` integration option is now called `level`.
- The `capture_sentry_logs` option was removed. Use `level=None` to disable log capture.
- When you enable the integration by adding `LoguruIntegration` to your `sentry_sdk.init()`, it'll start capturing Sentry logs and breadcrumbs. Creating events from logs can be enabled by providing additional integration options.

| Old name | New name | Old default | New default | Description |
| --- | --- | --- | --- | --- |
| `level` | `breadcrumb_level` | `INFO` | `INFO` | Captures logs of that level and higher as breadcrumbs. |
| `event_level` | `event_level` | `ERROR` | `None` | Captures logs of that level and higher as events. |
| `sentry_logs_level` | `level` | `INFO` | `INFO` | Captures logs of that level and higher as Sentry logs. |
| `capture_sentry_logs` | removed | `False` | n/a | Allows to opt out of instrumenting logs as Sentry logs. Use `level` (previously `sentry_logs_level`) to adjust what should be captured instead. |


## Removed

- The SDK no longer supports Python 3.6. The oldest supported version is now 3.7.
Expand Down
1 change: 0 additions & 1 deletion sentry_sdk/integrations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ def iter_default_integrations(
"sentry_sdk.integrations.langchain.LangchainIntegration",
"sentry_sdk.integrations.langgraph.LanggraphIntegration",
"sentry_sdk.integrations.litestar.LitestarIntegration",
"sentry_sdk.integrations.loguru.LoguruIntegration",
"sentry_sdk.integrations.mcp.MCPIntegration",
"sentry_sdk.integrations.openai.OpenAIIntegration",
"sentry_sdk.integrations.openai_agents.OpenAIAgentsIntegration",
Expand Down
47 changes: 16 additions & 31 deletions sentry_sdk/integrations/loguru.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

if TYPE_CHECKING:
from logging import LogRecord
from typing import Any, Optional, Union
from typing import Any, Optional

try:
import loguru
Expand All @@ -27,12 +27,6 @@
raise DidNotEnable("LOGURU is not installed or incompatible")


_SENTINEL = object()


_SENTINEL = object()


class LoggingLevels(enum.IntEnum):
TRACE = 5
DEBUG = 10
Expand Down Expand Up @@ -73,27 +67,24 @@ class LoguruIntegration(Integration):
identifier = "loguru"

level: "Optional[int]" = DEFAULT_LEVEL
event_level: "Optional[int]" = DEFAULT_EVENT_LEVEL
breadcrumb_format = DEFAULT_FORMAT
event_format = DEFAULT_FORMAT
sentry_logs_level: "Optional[int]" = DEFAULT_LEVEL
capture_sentry_logs: "Optional[Union[bool, object]]" = _SENTINEL
event_level: "Optional[int]" = None
breadcrumb_level: "Optional[int]" = DEFAULT_LEVEL
breadcrumb_format = DEFAULT_FORMAT

def __init__(
self,
level: "Optional[int]" = DEFAULT_LEVEL,
event_level: "Optional[int]" = DEFAULT_EVENT_LEVEL,
breadcrumb_format: "str | loguru.FormatFunction" = DEFAULT_FORMAT,
event_level: "Optional[int]" = None,
event_format: "str | loguru.FormatFunction" = DEFAULT_FORMAT,
sentry_logs_level: "Optional[int]" = DEFAULT_LEVEL,
capture_sentry_logs: "Optional[Union[bool, object]]" = _SENTINEL,
breadcrumb_format: "str | loguru.FormatFunction" = DEFAULT_FORMAT,
breadcrumb_level: "Optional[int]" = DEFAULT_LEVEL,
) -> None:
LoguruIntegration.level = level
LoguruIntegration.event_level = event_level
LoguruIntegration.breadcrumb_format = breadcrumb_format
LoguruIntegration.event_format = event_format
LoguruIntegration.sentry_logs_level = sentry_logs_level
LoguruIntegration.capture_sentry_logs = capture_sentry_logs
LoguruIntegration.breadcrumb_level = breadcrumb_level
LoguruIntegration.breadcrumb_format = breadcrumb_format

@staticmethod
def setup_once() -> None:
Expand All @@ -102,9 +93,8 @@ def setup_once() -> None:

if LoguruIntegration.level is not None:
logger.add(
LoguruBreadcrumbHandler(level=LoguruIntegration.level),
loguru_handler,
level=LoguruIntegration.level,
format=LoguruIntegration.breadcrumb_format,
)

if LoguruIntegration.event_level is not None:
Expand All @@ -114,10 +104,11 @@ def setup_once() -> None:
format=LoguruIntegration.event_format,
)

if LoguruIntegration.sentry_logs_level is not None:
if LoguruIntegration.breadcrumb_level is not None:
logger.add(
loguru_sentry_logs_handler,
level=LoguruIntegration.sentry_logs_level,
LoguruBreadcrumbHandler(level=LoguruIntegration.breadcrumb_level),
level=LoguruIntegration.breadcrumb_level,
format=LoguruIntegration.breadcrumb_format,
)


Expand Down Expand Up @@ -151,22 +142,16 @@ class LoguruBreadcrumbHandler(_LoguruBaseHandler, BreadcrumbHandler):
pass


def loguru_sentry_logs_handler(message: "Message") -> None:
def loguru_handler(message: "Message") -> None:
# This is intentionally a callable sink instead of a standard logging handler
# since otherwise we wouldn't get direct access to message.record
client = sentry_sdk.get_client()
if not client.is_active():
return

if LoguruIntegration.capture_sentry_logs is not True:
return

record = message.record

if (
LoguruIntegration.sentry_logs_level is None
or record["level"].no < LoguruIntegration.sentry_logs_level
):
if LoguruIntegration.level is None or record["level"].no < LoguruIntegration.level:
return

otel_severity_number, otel_severity_text = _log_level_to_otel(
Expand Down
Loading
Loading