loguru icon indicating copy to clipboard operation
loguru copied to clipboard

Monitoring and centralized logging integration strategy

Open rudyryk opened this issue 3 years ago • 15 comments

I'm trying switching to Loguru for my newer projects and I'm wondering, what is recommended approach to perform integrations with services like Sentry, etc.?

For example, Sentry has built-in standard logging library hooks. But it won't work with the standard logging intercepted by Loguru.

Should we create custom sink? That could be tricky, and actually, could introduce extra bugs, so it needs to have solid design and bunch of tests. Application broken because of bugs monitoring a is kind of "fun but not fun".

rudyryk avatar Oct 06 '20 07:10 rudyryk

For Sentry integration I came up to such code:

import sys
from loguru import logger
import logging
from sentry_sdk.integrations.logging import LoggingIntegration, EventHandler
SENTRY_DSN = '...'
logger.remove()
sentry_sdk.init(
    SENTRY_DSN,
    integrations=[LoggingIntegration(level=None, event_level=None)],
)
logger.add(sys.stderr, level='INFO')
logger.add(EventHandler(level=logging.WARNING))

# + InterceptHandler from README.md
# ...
logging.basicConfig(handlers=[InterceptHandler()], level=0)

Will test how it works out.

rudyryk avatar Oct 06 '20 09:10 rudyryk

Hi @rudyryk.

As you figured out, I think simply adding a Sentry EventHandler or BreadcrumbHandler to the Loguru logger should work fine.

Combining this with the InterceptHandler() ensure that logs emitted the standard logging library will be captured too.

Please, let me know if this does not work as expected.

Delgan avatar Oct 06 '20 20:10 Delgan

@Delgan unfortunately, I faced weird issue, I got endless messages sent to the Sentry server:

...
2020-10-08 21:34:56.524 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:56.634 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:56.704 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:56.817 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:56.870 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:56.977 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:57.028 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:57.141 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:57.193 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:57.297 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:57.363 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:57.473 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:57.539 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:57.645 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
2020-10-08 21:34:57.706 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41
^C2020-10-08 21:34:57.803 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41

An example of message received:

2020-10-08 21:42:57.985 | DEBUG    | sentry_sdk.integrations.logging:sentry_patched_callhandlers:83 - https://sentry.mysite.org:443 "POST /api/9/store/ HTTP/1.1" 200 41

Seems like some cyclic logging behaviour.

rudyryk avatar Oct 08 '20 18:10 rudyryk

Sorry, I'm not a Sentry user and consequently I'm not able to reproduce your problem. :(

Would this be possible that events emitted by the EventHandler() would somehow be captured by Sentry which would generate new logs causing EventHandler() to emit new events and so on? I have no clue about what could be causing the behavior you're experiencing. :confused:

Delgan avatar Oct 09 '20 14:10 Delgan

Would this be possible that events emitted by the EventHandler() would somehow be captured by Sentry which would generate new logs causing EventHandler() to emit new events and so on?

My guess is that's what happening exactly, but I didn't have chance to deep dive. Sentry is a major player in monitoring and crashes tracking in Python world, I think it's crucial to have solid workflow to make them play well with each other.

rudyryk avatar Oct 20 '20 22:10 rudyryk

Indeed, it is very important that loguru and sentry can work together. From what I've seen, several people use both of them without any problem, though.

If you have any idea how to create a minimum reproducible example of the issue you're facing, please let me know.

I have some doubts about the use of sentry_sdk.init() in your example. I'm not sure, but I'm thinking that it might be the one that causes conflicts with other handlers added manually.

Delgan avatar Oct 21 '20 18:10 Delgan

@Delgan Yes, it's possible that some other hooks are also involved, I'll try to provide basic reproducible example.

rudyryk avatar Oct 23 '20 15:10 rudyryk

@rudyryk Have you found a solution?

Soures888 avatar Jan 14 '21 20:01 Soures888

Hi @Soures888. Did you encounter the same issue? Are you able to create a minimal reproducible example?

Delgan avatar Mar 15 '21 21:03 Delgan

Hi guys! Just use this solution: https://github.com/getsentry/sentry-python/issues/653#issuecomment-788854865

TheZavitaev avatar Jul 29 '21 15:07 TheZavitaev

Hi,

I'm seeing some issues with using Sentry and Loguru. Here's a reproducer:

t.py
import logging
import os
import sys
from loguru import logger
import sentry_sdk


class InterceptHandler(logging.Handler):
    def emit(self, record):
        # Get corresponding Loguru level if it exists
        try:
            level = logger.level(record.levelname).name
        except (ValueError, TypeError):
            level = record.levelno

        # Find caller from where originated the logged message
        frame, depth = logging.currentframe(), 2
        while frame.f_code.co_filename == logging.__file__:
            frame = frame.f_back
            depth += 1

        logger.opt(depth=depth, exception=record.exc_info).log(
            level, record.getMessage()
        )


logging.basicConfig(handlers=[InterceptHandler()], level=0)
level_per_module = {"": "DEBUG", "sentry_sdk": "INFO"}
logger.remove()
logger.add(
    sys.stderr,
    filter=level_per_module,
    diagnose=False,
    colorize=True,
    format="{level: <8} | {name}:{line} ({module}) | <level>{message}</level>",
    level="DEBUG",
)
sentry_sdk.init(
    os.getenv("SENTRY_SDK")
)

std_logger = logging.getLogger("std_logger")
std_logger.info("Test info msg")
std_logger.debug("Test debug msg - not shown")

logger.debug("Test msg")
$ python t.py
INFO     | sentry_sdk.integrations.logging:86 (logging) | Test info msg
DEBUG    | __main__:45 (t) | Test msg

If I comment out the sentry_sdk.init statement, I'll get the expected output:

$ python t.py
INFO     | __main__:42 (t) | Test info msg
DEBUG    | __main__:43 (t) | Test debug msg - not shown
DEBUG    | __main__:45 (t) | Test msg

It looks like the sentry_sdk overwrites some of the data.

kbakk avatar Jan 16 '22 15:01 kbakk

Playing around a bit, I tried changing

         # Find caller from where originated the logged message
         frame, depth = logging.currentframe(), 2
-        while frame.f_code.co_filename == logging.__file__:
+        while (
+            frame.f_code.co_filename == logging.__file__
+            or "sentry_sdk/integrations" in frame.f_code.co_filename
+        ):
             frame = frame.f_back
             depth += 1

It seems to have the desired effect:

$ python t.py
INFO     | __main__:46 (t) | Test info msg
DEBUG    | __main__:47 (t) | Test debug msg - not shown
DEBUG    | __main__:49 (t) | Test msg

This might introduce some other problems, so not sure I can recommend this.

kbakk avatar Jan 16 '22 16:01 kbakk

The above is similar to what @fratambot writes in https://github.com/Delgan/loguru/issues/509

kbakk avatar Jan 16 '22 16:01 kbakk

The above is similar to what @fratambot writes in #509

Hey @kbakk, in the end I managed to integrate nicely loguru and sentry. You can take a look at what I've done here: https://github.com/Delgan/loguru/issues/554#issue-1081197682 I hope it can help you ! :)

fratambot avatar Jan 17 '22 13:01 fratambot

Hey @kbakk. Thanks for the reproducible example. This seems definitely related to how logging is configured by sentry_sdk.init(). I do not know what's happening under the hood, but it somehow breaks the InterceptHandler expectations.

I figured out you could configure Sentry with default_integrations=False to generate the expected logs. This has probably some side effect I'm not aware of, documentation is mentioning two handlers you may need to install manually: Logging | Sentry Documentation.

Hope it might help.

Delgan avatar Jan 19 '22 12:01 Delgan

It seems Sentry now officially supports Loguru: Learn about using Sentry with Loguru.

Consequently, I'm closing this ticket. The integration should be quite straightforward.

Delgan avatar Aug 27 '23 16:08 Delgan