mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2026-09-07 01:11:56 +00:00
Make logger fully configurable (#1087)
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import datetime
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
@@ -14,9 +13,6 @@ except ImportError:
|
||||
aiohttp = None
|
||||
|
||||
|
||||
__log__ = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DownloadMethods(UserMethods):
|
||||
|
||||
# region Public methods
|
||||
@@ -239,7 +235,8 @@ class DownloadMethods(UserMethods):
|
||||
# The used sender will also change if ``FileMigrateError`` occurs
|
||||
sender = self._sender
|
||||
|
||||
__log__.info('Downloading file in chunks of %d bytes', part_size)
|
||||
self._log[__name__].info('Downloading file in chunks of %d bytes',
|
||||
part_size)
|
||||
try:
|
||||
offset = 0
|
||||
while True:
|
||||
@@ -251,7 +248,7 @@ class DownloadMethods(UserMethods):
|
||||
# TODO Implement
|
||||
raise NotImplementedError
|
||||
except errors.FileMigrateError as e:
|
||||
__log__.info('File lives in another DC')
|
||||
self._log[__name__].info('File lives in another DC')
|
||||
sender = await self._borrow_exported_sender(e.new_dc)
|
||||
exported = True
|
||||
continue
|
||||
@@ -264,7 +261,8 @@ class DownloadMethods(UserMethods):
|
||||
else:
|
||||
return getattr(result, 'type', '')
|
||||
|
||||
__log__.debug('Saving %d more bytes', len(result.bytes))
|
||||
self._log[__name__].debug('Saving %d more bytes',
|
||||
len(result.bytes))
|
||||
f.write(result.bytes)
|
||||
if progress_callback:
|
||||
progress_callback(f.tell(), file_size)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import asyncio
|
||||
import itertools
|
||||
import logging
|
||||
import time
|
||||
|
||||
from async_generator import async_generator, yield_
|
||||
@@ -11,8 +10,6 @@ from .buttons import ButtonMethods
|
||||
from .. import helpers, utils, errors
|
||||
from ..tl import types, functions
|
||||
|
||||
__log__ = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from .. import version
|
||||
from .. import version, __name__ as __base_name__
|
||||
from ..crypto import rsa
|
||||
from ..extensions import markdown
|
||||
from ..network import MTProtoSender, ConnectionTcpFull
|
||||
@@ -19,7 +19,8 @@ DEFAULT_IPV4_IP = '149.154.167.51'
|
||||
DEFAULT_IPV6_IP = '[2001:67c:4e8:f002::a]'
|
||||
DEFAULT_PORT = 443
|
||||
|
||||
__log__ = logging.getLogger(__name__)
|
||||
__default_log__ = logging.getLogger(__base_name__)
|
||||
__default_log__.addHandler(logging.NullHandler())
|
||||
|
||||
|
||||
class TelegramBaseClient(abc.ABC):
|
||||
@@ -133,6 +134,15 @@ class TelegramBaseClient(abc.ABC):
|
||||
system_lang_code (`str`, optional):
|
||||
"System lang code" to be sent when creating the initial connection.
|
||||
Defaults to `lang_code`.
|
||||
|
||||
loop (`asyncio.AbstractEventLoop`, optional):
|
||||
Asyncio event loop to use. Defaults to `asyncio.get_event_loop()`
|
||||
|
||||
base_logger (`str` | `logging.Logger`, optional):
|
||||
Base logger name or instance to use.
|
||||
If a `str` is given, it'll be passed to `logging.getLogger()`. If a
|
||||
`logging.Logger` is given, it'll be used directly. If something
|
||||
else or nothing is given, the default logger will be used.
|
||||
"""
|
||||
|
||||
# Current TelegramClient version
|
||||
@@ -161,7 +171,8 @@ class TelegramBaseClient(abc.ABC):
|
||||
app_version=None,
|
||||
lang_code='en',
|
||||
system_lang_code='en',
|
||||
loop=None):
|
||||
loop=None,
|
||||
base_logger=None):
|
||||
if not api_id or not api_hash:
|
||||
raise ValueError(
|
||||
"Your API ID or Hash cannot be empty or None. "
|
||||
@@ -170,6 +181,19 @@ class TelegramBaseClient(abc.ABC):
|
||||
self._use_ipv6 = use_ipv6
|
||||
self._loop = loop or asyncio.get_event_loop()
|
||||
|
||||
if isinstance(base_logger, str):
|
||||
base_logger = logging.getLogger(base_logger)
|
||||
elif not isinstance(base_logger, logging.Logger):
|
||||
base_logger = __default_log__
|
||||
|
||||
class _Loggers(dict):
|
||||
def __missing__(self, key):
|
||||
if key.startswith("telethon."):
|
||||
key = key[len("telethon."):]
|
||||
return base_logger.getChild(key)
|
||||
|
||||
self._log = _Loggers()
|
||||
|
||||
# Determine what session object we have
|
||||
if isinstance(session, str) or session is None:
|
||||
try:
|
||||
@@ -240,6 +264,7 @@ class TelegramBaseClient(abc.ABC):
|
||||
self._connection = connection
|
||||
self._sender = MTProtoSender(
|
||||
self.session.auth_key, self._loop,
|
||||
loggers=self._log,
|
||||
retries=self._connection_retries,
|
||||
delay=self._retry_delay,
|
||||
auto_reconnect=self._auto_reconnect,
|
||||
@@ -317,7 +342,8 @@ class TelegramBaseClient(abc.ABC):
|
||||
"""
|
||||
await self._sender.connect(self._connection(
|
||||
self.session.server_address, self.session.port,
|
||||
loop=self._loop, proxy=self._proxy
|
||||
loop=self._loop, loggers=self._log,
|
||||
proxy=self._proxy
|
||||
))
|
||||
self.session.auth_key = self._sender.auth_key
|
||||
self.session.save()
|
||||
@@ -387,7 +413,7 @@ class TelegramBaseClient(abc.ABC):
|
||||
"""
|
||||
Permanently switches the current connection to the new data center.
|
||||
"""
|
||||
__log__.info('Reconnecting to new data center %s', new_dc)
|
||||
self._log[__name__].info('Reconnecting to new data center %s', new_dc)
|
||||
dc = await self._get_dc(new_dc)
|
||||
|
||||
self.session.set_dc(dc.id, dc.ip_address, dc.port)
|
||||
@@ -443,7 +469,8 @@ class TelegramBaseClient(abc.ABC):
|
||||
sender = MTProtoSender(None, self._loop)
|
||||
await sender.connect(self._connection(
|
||||
dc.ip_address, dc.port, loop=self._loop, proxy=self._proxy))
|
||||
__log__.info('Exporting authorization for data center %s', dc)
|
||||
self._log[__name__].info('Exporting authorization for data center %s',
|
||||
dc)
|
||||
auth = await self(functions.auth.ExportAuthorizationRequest(dc_id))
|
||||
req = self._init_with(functions.auth.ImportAuthorizationRequest(
|
||||
id=auth.id, bytes=auth.bytes
|
||||
@@ -486,7 +513,8 @@ class TelegramBaseClient(abc.ABC):
|
||||
n -= 1
|
||||
self._borrowed_senders[dc_id] = (n, sender)
|
||||
if not n:
|
||||
__log__.info('Disconnecting borrowed sender for DC %d', dc_id)
|
||||
self._log[__name__].info(
|
||||
'Disconnecting borrowed sender for DC %d', dc_id)
|
||||
sender.disconnect()
|
||||
|
||||
async def _get_cdn_client(self, cdn_redirect):
|
||||
|
||||
+10
-11
@@ -1,7 +1,5 @@
|
||||
import asyncio
|
||||
import inspect
|
||||
import itertools
|
||||
import logging
|
||||
import random
|
||||
import time
|
||||
|
||||
@@ -9,8 +7,6 @@ from .users import UserMethods
|
||||
from .. import events, utils, errors
|
||||
from ..tl import types, functions
|
||||
|
||||
__log__ = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UpdateMethods(UserMethods):
|
||||
|
||||
@@ -281,28 +277,31 @@ class UpdateMethods(UserMethods):
|
||||
await callback(event)
|
||||
except errors.AlreadyInConversationError:
|
||||
name = getattr(callback, '__name__', repr(callback))
|
||||
__log__.debug('Event handler "%s" already has an open '
|
||||
'conversation, ignoring new one', name)
|
||||
self._log[__name__].debug(
|
||||
'Event handler "%s" already has an open conversation, '
|
||||
'ignoring new one', name)
|
||||
except events.StopPropagation:
|
||||
name = getattr(callback, '__name__', repr(callback))
|
||||
__log__.debug(
|
||||
self._log[__name__].debug(
|
||||
'Event handler "%s" stopped chain of propagation '
|
||||
'for event %s.', name, type(event).__name__
|
||||
)
|
||||
break
|
||||
except Exception:
|
||||
name = getattr(callback, '__name__', repr(callback))
|
||||
__log__.exception('Unhandled exception on %s', name)
|
||||
self._log[__name__].exception('Unhandled exception on %s',
|
||||
name)
|
||||
|
||||
async def _handle_auto_reconnect(self):
|
||||
# Upon reconnection, we want to send getState
|
||||
# for Telegram to keep sending us updates.
|
||||
try:
|
||||
__log__.info('Asking for the current state after reconnect...')
|
||||
self._log[__name__].info(
|
||||
'Asking for the current state after reconnect...')
|
||||
state = await self(functions.updates.GetStateRequest())
|
||||
__log__.info('Got new state! %s', state)
|
||||
self._log[__name__].info('Got new state! %s', state)
|
||||
except errors.RPCError as e:
|
||||
__log__.info('Failed to get current state: %r', e)
|
||||
self._log[__name__].info('Failed to get current state: %r', e)
|
||||
|
||||
# endregion
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import hashlib
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
@@ -12,8 +11,6 @@ from .users import UserMethods
|
||||
from .. import utils, helpers
|
||||
from ..tl import types, functions, custom
|
||||
|
||||
__log__ = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class _CacheType:
|
||||
"""Like functools.partial but pretends to be the wrapped class."""
|
||||
@@ -196,8 +193,8 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
|
||||
return msg
|
||||
|
||||
async def _send_album(self, entity, files, caption='',
|
||||
progress_callback=None, reply_to=None,
|
||||
parse_mode=(), silent=None):
|
||||
progress_callback=None, reply_to=None,
|
||||
parse_mode=(), silent=None):
|
||||
"""Specialized version of .send_file for albums"""
|
||||
# We don't care if the user wants to avoid cache, we will use it
|
||||
# anyway. Why? The cached version will be exactly the same thing
|
||||
@@ -350,8 +347,8 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
|
||||
return cached
|
||||
|
||||
part_count = (file_size + part_size - 1) // part_size
|
||||
__log__.info('Uploading file of %d bytes in %d chunks of %d',
|
||||
file_size, part_count, part_size)
|
||||
self._log[__name__].info('Uploading file of %d bytes in %d chunks of %d',
|
||||
file_size, part_count, part_size)
|
||||
|
||||
with open(file, 'rb') if isinstance(file, str) else BytesIO(file)\
|
||||
as stream:
|
||||
@@ -370,8 +367,8 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
|
||||
|
||||
result = await self(request)
|
||||
if result:
|
||||
__log__.debug('Uploaded %d/%d', part_index + 1,
|
||||
part_count)
|
||||
self._log[__name__].debug('Uploaded %d/%d',
|
||||
part_index + 1, part_count)
|
||||
if progress_callback:
|
||||
progress_callback(stream.tell(), file_size)
|
||||
else:
|
||||
@@ -464,7 +461,7 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
|
||||
return file_handle, media
|
||||
|
||||
async def _cache_media(self, msg, file, file_handle,
|
||||
force_document=False):
|
||||
force_document=False):
|
||||
if file and msg and isinstance(file_handle,
|
||||
custom.InputSizedFile):
|
||||
# There was a response message and we didn't use cached
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import asyncio
|
||||
import itertools
|
||||
import logging
|
||||
import time
|
||||
|
||||
from .telegrambaseclient import TelegramBaseClient
|
||||
@@ -8,7 +7,6 @@ from .. import errors, utils
|
||||
from ..errors import MultiError, RPCError
|
||||
from ..tl import TLObject, TLRequest, types, functions
|
||||
|
||||
__log__ = logging.getLogger(__name__)
|
||||
_NOT_A_REQUEST = TypeError('You can only invoke requests, not types!')
|
||||
|
||||
|
||||
@@ -27,7 +25,8 @@ class UserMethods(TelegramBaseClient):
|
||||
if diff <= 3: # Flood waits below 3 seconds are "ignored"
|
||||
self._flood_waited_requests.pop(r.CONSTRUCTOR_ID, None)
|
||||
elif diff <= self.flood_sleep_threshold:
|
||||
__log__.info('Sleeping early for %ds on flood wait', diff)
|
||||
self._log[__name__].info(
|
||||
'Sleeping early for %ds on flood wait', diff)
|
||||
await asyncio.sleep(diff, loop=self._loop)
|
||||
self._flood_waited_requests.pop(r.CONSTRUCTOR_ID, None)
|
||||
else:
|
||||
@@ -61,8 +60,9 @@ class UserMethods(TelegramBaseClient):
|
||||
self.session.process_entities(result)
|
||||
return result
|
||||
except (errors.ServerError, errors.RpcCallFailError) as e:
|
||||
__log__.warning('Telegram is having internal issues %s: %s',
|
||||
e.__class__.__name__, e)
|
||||
self._log[__name__].warning(
|
||||
'Telegram is having internal issues %s: %s',
|
||||
e.__class__.__name__, e)
|
||||
except (errors.FloodWaitError, errors.FloodTestPhoneWaitError) as e:
|
||||
if utils.is_list_like(request):
|
||||
request = request[request_index]
|
||||
@@ -71,15 +71,16 @@ class UserMethods(TelegramBaseClient):
|
||||
[request.CONSTRUCTOR_ID] = time.time() + e.seconds
|
||||
|
||||
if e.seconds <= self.flood_sleep_threshold:
|
||||
__log__.info('Sleeping for %ds on flood wait', e.seconds)
|
||||
self._log[__name__].info('Sleeping for %ds on flood wait',
|
||||
e.seconds)
|
||||
await asyncio.sleep(e.seconds, loop=self._loop)
|
||||
else:
|
||||
raise
|
||||
except (errors.PhoneMigrateError, errors.NetworkMigrateError,
|
||||
errors.UserMigrateError) as e:
|
||||
__log__.info('Phone migrated to %d', e.new_dc)
|
||||
self._log[__name__].info('Phone migrated to %d', e.new_dc)
|
||||
should_raise = isinstance(e, (
|
||||
errors.PhoneMigrateError, errors.NetworkMigrateError
|
||||
errors.PhoneMigrateError, errors.NetworkMigrateError
|
||||
))
|
||||
if should_raise and await self.is_user_authorized():
|
||||
raise
|
||||
|
||||
Reference in New Issue
Block a user