Skip to content

Commit 0187237

Browse files
committed
refactor: migrate from Sentry to Logfire for error tracking and logging
1 parent 6c2f4b6 commit 0187237

File tree

31 files changed

+434
-168
lines changed

31 files changed

+434
-168
lines changed

docs/source/privacy.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@ All collected data is made available by the Telegram API in a public way, note t
3131
- **Type**: The type of the group (`supergroup` or `group`).
3232
- **Registration Date**: The date when the _PyKorone_ bot saw the group for the first time.
3333

34-
### Crashlytics
34+
### Observability
3535

36-
_PyKorone_ uses [Sentry](https://sentry.io/) to collect crash reports and improve the stability of the software. Crashlytics collects the same data as _PyKorone_, plus extra details of the crash itself. By using _PyKorone_ you agree to the [Sentry's privacy policy](https://sentry.io/privacy) as well.
36+
_PyKorone_ uses [Pydantic Logfire](https://logfire.pydantic.dev/) to collect crash reports and improve the stability of the software. Logfire collects the same data as _PyKorone_, plus extra details of the crash itself to help diagnose issues. By using _PyKorone_ you agree to the [Logfire privacy policy](https://pydantic.dev/legal/privacy-policy) as well.
3737

3838
#### Crash Data
3939

4040
The data displayed below is collected by crashlytics and is not stored permanently. It is used exclusively for debugging purposes.
4141

4242
- Crash [traceback](https://en.wikipedia.org/wiki/Stack_trace).
4343
- [Telegram update](https://core.telegram.org/api/updates) that caused the crash.
44+
- Logfire trace identifier used to correlate the incident.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ dependencies = [
2323
"yt-dlp>=2025.2.19",
2424
"magic-filter>=1.0.12",
2525
"tomlkit>=0.13.2",
26-
"sentry-sdk>=2.22.0",
2726
"pydantic>=2.10.6",
2827
"orjson>=3.10.15",
2928
"aiocron>=2.1",
3029
"m3u8>=6.0.0",
3130
"aiofiles>=24.1.0",
31+
"logfire[httpx]>=4.11.0",
3232
]
3333
readme = "README.md"
3434
license = { file = "LICENSE" }

src/korone/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# SPDX-License-Identifier: BSD-3-Clause
22
# Copyright (c) 2025 Hitalo M. <https://github.com/HitaloM>
33

4-
__version__ = "2025.10.03"
4+
__version__ = "2025.10.05"

src/korone/__main__.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from contextlib import suppress
88
from pathlib import Path
99

10-
import sentry_sdk
10+
import logfire
1111
import uvloop
1212
from cashews.exceptions import CacheBackendInteractionError
1313
from hydrogram import idle
@@ -16,7 +16,6 @@
1616
from .client import AppParameters, Korone
1717
from .config import ConfigManager
1818
from .database.sqlite.connection import SQLite3Connection
19-
from .modules.errors.utils import IGNORED_EXCEPTIONS
2019
from .utils.caching import cache
2120
from .utils.logging import logger
2221

@@ -38,13 +37,20 @@ async def pre_process() -> ConfigManager:
3837

3938
config = ConfigManager()
4039

41-
if sentry_dsn := config.get("korone", "SENTRY_DSN"):
42-
await logger.ainfo("Initializing Sentry integration")
43-
sentry_sdk.init(
44-
dsn=sentry_dsn,
45-
release=__version__,
46-
ignore_errors=IGNORED_EXCEPTIONS,
47-
)
40+
await logger.ainfo("Configuring Logfire integration")
41+
logfire_token = (config.get("korone", "LOGFIRE_TOKEN") or "").strip() or None
42+
logfire_environment = (
43+
config.get("korone", "LOGFIRE_ENVIRONMENT", "production") or "production"
44+
).strip()
45+
46+
logfire.configure(
47+
service_name="korone-bot",
48+
service_version=__version__,
49+
token=logfire_token,
50+
send_to_logfire="if-token-present",
51+
environment=logfire_environment,
52+
)
53+
logfire.instrument_httpx()
4854

4955
async with SQLite3Connection() as conn:
5056
await conn.execute(constants.SQLITE3_TABLES, script=True)

src/korone/constants.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"SUDOERS": ["918317361"],
2525
"LOGS_CHAT": "-100123456789",
2626
"BACKUPS_CHAT": "-100123456789",
27-
"SENTRY_DSN": "",
27+
"LOGFIRE_TOKEN": "",
28+
"LOGFIRE_ENVIRONMENT": "production",
2829
"DEEPL_KEY": "",
2930
"LASTFM_KEY": "",
3031
"CORS_BYPASS": "",

src/korone/database/sqlite/connection.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from korone import constants
1313
from korone.database.connection import Connection
14-
from korone.utils.logging import logger
14+
from korone.utils.logging import get_logger
1515

1616
from .table import SQLite3Table
1717

@@ -20,6 +20,8 @@
2020

2121
from korone.database.table import Table
2222

23+
logger = get_logger(__name__)
24+
2325

2426
class SQLite3Connection(Connection):
2527
"""SQLite3 implementation of the database connection protocol.

src/korone/filters/sudo.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
from hydrogram.types import CallbackQuery, Message
1010

1111
from korone.config import ConfigManager
12-
from korone.utils.logging import logger
12+
from korone.utils.logging import get_logger
13+
14+
logger = get_logger(__name__)
1315

1416

1517
def load_sudoers() -> set[int]:

src/korone/modules/core.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from korone.database.query import Query
1414
from korone.database.sqlite import SQLite3Connection
15-
from korone.utils.logging import logger
15+
from korone.utils.logging import get_logger
1616

1717
if TYPE_CHECKING:
1818
from types import ModuleType
@@ -22,6 +22,8 @@
2222

2323
from korone.database.table import Documents
2424

25+
logger = get_logger(__name__)
26+
2527
MODULES: dict[str, dict[str, list[str]]] = {}
2628
COMMANDS: dict[str, dict[str, Any]] = {}
2729

src/korone/modules/errors/handlers/catcher.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sys
55
from traceback import format_exception
66

7+
import logfire
78
from hydrogram import Client
89
from hydrogram.errors import ChatWriteForbidden
910
from hydrogram.types import (
@@ -14,13 +15,15 @@
1415
Message,
1516
Update,
1617
)
17-
from sentry_sdk import capture_exception
18+
from opentelemetry.trace import format_trace_id
1819

1920
from korone import constants
2021
from korone.decorators import router
2122
from korone.modules.errors.utils import IGNORED_EXCEPTIONS
2223
from korone.utils.i18n import gettext as _
23-
from korone.utils.logging import logger
24+
from korone.utils.logging import get_logger
25+
26+
logger = get_logger(__name__)
2427

2528

2629
@router.error()
@@ -38,15 +41,28 @@ async def handle_error(client: Client, update: Update, exception: Exception) ->
3841
await logger.aerror("[ErrorHandler] Missing exception info", exception=exception)
3942
return
4043

41-
sentry_event_id = capture_exception(exception)
4244
formatted_exception = format_exception(etype, value, tb)
43-
await log_exception_details(formatted_exception, sentry_event_id)
45+
trace_reference: str | None = None
46+
47+
with logfire.span(
48+
"Unhandled update exception",
49+
update_type=type(update).__name__,
50+
chat_id=chat.id if chat else None,
51+
) as span:
52+
span.record_exception(exception)
53+
if chat:
54+
span.set_attribute("telegram.chat_type", chat.type)
55+
span_context = span.get_span_context()
56+
if span_context:
57+
trace_reference = format_trace_id(span_context.trace_id)
58+
59+
await log_exception_details(formatted_exception, trace_reference)
4460

4561
if not chat:
4662
await logger.aerror("[ErrorHandler] No chat for update", update=update)
4763
return
4864

49-
await send_error_message(client, chat, sentry_event_id)
65+
await send_error_message(client, chat, trace_reference)
5066

5167

5268
def get_chat_from_update(update: Update) -> Chat | None:
@@ -71,16 +87,16 @@ async def handle_ignored_exceptions(
7187

7288

7389
async def log_exception_details(
74-
formatted_exception: list[str], sentry_event_id: str | None
90+
formatted_exception: list[str], trace_reference: str | None
7591
) -> None:
7692
await logger.aerror("".join(formatted_exception))
77-
await logger.aerror("[ErrorHandler] Additional error data", sentry_event_id=sentry_event_id)
93+
await logger.aerror("[ErrorHandler] Additional error data", trace_reference=trace_reference)
7894

7995

80-
async def send_error_message(client: Client, chat: Chat, sentry_event_id: str | None) -> None:
96+
async def send_error_message(client: Client, chat: Chat, trace_reference: str | None) -> None:
8197
text = _("An unexpected error occurred while processing this update! :/")
82-
if sentry_event_id:
83-
text += _("\nReference ID: {id}").format(id=sentry_event_id)
98+
if trace_reference:
99+
text += _("\nTrace ID: {id}").format(id=trace_reference)
84100

85101
keyboard = InlineKeyboardMarkup([
86102
[

src/korone/modules/gsm_arena/handlers/get.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
from korone.modules.gsm_arena.callback_data import GetDeviceCallback
1313
from korone.modules.gsm_arena.utils.scraper import check_phone_details, format_phone
1414
from korone.utils.i18n import gettext as _
15-
from korone.utils.logging import logger
15+
from korone.utils.logging import get_logger
16+
17+
logger = get_logger(__name__)
1618

1719

1820
@router.callback_query(GetDeviceCallback.filter())

0 commit comments

Comments
 (0)