Delgan / loguru

Python logging made (stupidly) simple
MIT License
19.73k stars 695 forks source link

How to ignore certain type of Error? #790

Open AlexFoxalt opened 1 year ago

AlexFoxalt commented 1 year ago

Hello guys, now i'm working on telegram bot, and there is one periodic traceback, that ruins my logging and makes it really hard to read and ugly. It happens because of some internal telegram update processes, and it doesn't shut down the whole app.

Here is my error: raise NetworkError(f"httpx HTTPError: {err}") from err tg_app | telegram.error.NetworkError: httpx HTTPError:

I want somehow to ignore it in my logger.

Logger setup:


def _setup_default_logger(context_logger: Logger) -> None:
    context_logger.add(
        sink=sys.stdout,
        colorize=True,
        format=DEFAULT_MESSAGE_FORMAT,
        backtrace=True,
    )

def _setup_logger(name: str) -> Logger:
    """
    Return configured logger.
    """
    logger.remove()
    context_logger = logger.bind(name=name)
    _setup_default_logger(context_logger)
    return context_logger

@lru_cache(maxsize=None)
def get_logger(name: str = DEFAULT_LOGGER_NAME) -> Logger:
    """
    Initialize logger for project.
    """
    return _setup_logger(name)
Delgan commented 1 year ago

You can use a custom filter function:

def ignore_error(record):
    if record["exception"] is not None:
        exc, _, _ = record["exception"]
        if isinstance(exc, telegram.error.NetworkError):
            return False
    return True

logger.add("file.log", filter=ignore_error)
AlexFoxalt commented 1 year ago

@Delgan Unfortunately such approach doesn't work. Error trackbacks are still in terminal window 😢

Delgan commented 1 year ago

@AlexFoxalt Sorry, there was a typo in the code I shared.

The record["execption"] is a tuple containing (exc_type, exc_value, exc_traceback). We have to check isinstance(exc_value, telegram.error.NetworkError) instead of using the exc_type (which made the isinstance() check fail, thus no discarding the logged message).

Here is the updated version:

def ignore_error(record):
    if record["exception"] is not None:
        _, exc, _ = record["exception"]
        if isinstance(exc, telegram.error.NetworkError):
            return False
    return True

logger.add("file.log", filter=ignore_error)
AlexFoxalt commented 1 year ago

@Delgan The problem here, that filter executed only 1 time on app start. For ex. i add simple output = EXC = in filter func.

def ignore_error(record):
    print("= EXC =")
    if record["exception"] is not None:
        _, exc, _ = record["exception"]
        if isinstance(exc, telegram.error.NetworkError):
            return False
    return True

And here is my output when i run my app, and trigger simple error of zero div.

python3 main.py
= EXC =
[__main__] | 2023-01-30 at 12:27:20 | INFO | <module> | Bot starting
No error handlers are registered, logging exception.
Traceback (most recent call last):
  File "/home/alexfoxalt/PycharmProjects/PETS/PowerStatusTelegramBot/.ve/lib/python3.9/site-packages/telegram/ext/_application.py", line 1063, in process_update
    await coroutine
  File "/home/alexfoxalt/PycharmProjects/PETS/PowerStatusTelegramBot/.ve/lib/python3.9/site-packages/telegram/ext/_conversationhandler.py", line 824, in handle_update
    new_state: object = await handler.handle_update(
  File "/home/alexfoxalt/PycharmProjects/PETS/PowerStatusTelegramBot/.ve/lib/python3.9/site-packages/telegram/ext/_handler.py", line 141, in handle_update
    return await self.callback(update, context)
  File "/home/alexfoxalt/PycharmProjects/PETS/PowerStatusTelegramBot/app/handlers.py", line 184, in callback_handler
    return await possibles.get(query.data)(update, context)
  File "/home/alexfoxalt/PycharmProjects/PETS/PowerStatusTelegramBot/app/handlers.py", line 188, in light_info
    1 / 0
ZeroDivisionError: division by zero

If i understood correctly, filter function should be executed on every log iteration. so "= EXC =" must be written before every log output. But in my case, when it's time to write exception log, logger didn't go to filter func.

async def light_info(update, context):
    1 / 0
    logger.info(
        f"{update.effective_chat.username}({update.effective_chat.id})"
    )
    . . .
Delgan commented 1 year ago

Are you able to provide a fully reproducible example? The filter function should be called before every logged message except if you somehow called logger.disable().