Delgan / loguru

Python logging made (stupidly) simple

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Help designing an integration with `logot`

etianen opened this issue ยท comments

I've recently released a 0.1.0 preview of a log testing library called logot. It provides a nice fixture for testing complex log patterns, which I've found very useful when testing multithreaded and async codebases.

I'd like to provide a loguru integration. ๐Ÿค—Since I'm not hugely familiar with loguru, I was hoping you'd have some advice on what a good integration would look like.

There are a couple of sticking points that I'd like to nail before committing to a v1.0.0 API.

Log capture

Currently, stdlib logging capture is enabled with a context manager method:

from logot import Logot

with Logot().capturing() as logot:
    pass

Since the loguru integration would be an optional extra, a freestanding context manager could be provided like this:

from logot.contrib.loguru import capturing

with capturing(Logot()) as logot:
   ...

It's a bit awkward having a freestanding context manager for 3rd party integrations, so an alternative would be a capturing backend approach:

from logot.contrib.loguru import LoguruCapture

with Logot().capturing(LoguruCapture):
   pass

Any arguments given to capturing would be propagated to the LoguruCapture constructor. This would then unify capture between stdlib logging and loguru logging. The default capture backend would be the stdlib capture, and an @overload would ensure good typing. ๐Ÿ’ช

The alternative is a whole Logot subclass just for loguru, which seems heavyweight and unpleasant. ๐Ÿคฎ

Log message matching

Rather than awkward regexes, logot lets you match log messages with % placeholders. The hope here is that it's much cleaner and more intuitive to match using the syntax used for log message placeholders. (Similar to how printf and scanf pair nicely).

from logot import logged

logot.wait_for(logged.info("Hello %s"))

But loguru uses lovely .format()-style placeholders!

Maybe it's fine to just use % placeholders in loguru tests? ๐Ÿคท

But it might be nice to support .format()-style placeholders like this:

from logot.contrib.loguru import logged

logot.wait_for(logged.info("Hello {}"))

Support for matching structured data would also be possible:

logot.wait_for(
    logged.bind(foo="bar").info("Hello {}")
)

Advice appreciated! ๐Ÿ™

Thanks for reading this far!

I'm inclined to go with a LoguruCapture backend combined with .format()-style message matching. That would give first-class support for loguru without compromising or complicating the stdlib interface.

However, I'm not really familiar with the loguru community and ecosystem! Maybe this is unappealing? Maybe it's already been done! ๐Ÿ˜ฌ

Hope you have a nice weekend! โค๏ธ

Hey @etianen.

Great project, and thanks for considering integration with Loguru! ๐Ÿ‘

Somewhat related, here is documentation explaining how to capture Loguru logs during tests:

As per the above, that means you could have your default logged API directly compatible with Loguru (although a Loguru-specific handler would still need to be installed). Now, as you suggested, you could also have logged that offers a tailored API for Loguru.

To be honest, I'm unsure whether %s or {} would be preferable for parsing Loguru logs. As you mentioned, using %s would likely resonate well with C developers due to its resemblance to scanf() syntax. Additionally, it would maintain a consistent API of your library across standard logging and loguru. Conversely, opting for {} aligns better with Loguru's format. It would probably make the logged usage more straightforward, especially when dealing with parsing f-strings.

Both approaches look fine to me. Not sure I'm of great help here by saying that. ๐Ÿ˜

In any case, that certainly won't be "unappealing". I like the idea of using placeholders to replace regex patterns (whether it uses % or {} syntax).

Thanks for getting back so quickly!

I'm surprised (but pleased) you don't see the %s message match syntax as a barrier to adoption. I'll probably leave this out of the initial integration and leave it in the issue tracker as a possible enhancement depending on the popularity of the library (and the loguru integration!).

Thanks for those docs links - I'd already read them to make sure a loguru integration was actually possible, and it was nice to see that it would be easy via the already-implemented logging handler.

I'm happy to close this now, as you've answered all my questions and I'm now enthused about the integration! ๐Ÿš€ I'll post a small update here once the integration is in place to see if you have any thoughts.

It finally landed! https://logot.readthedocs.io/latest/integrations/loguru.html ๐Ÿš€

The loguru integration was far more straightforward than stdlib logging, with no footguns. I found that pretty surprising, since I've used logging for a very long time and only really dabbled with loguru. โค๏ธ

For comparison:

I'm hoping to promote logot as a way to test logs irrespective of testing framework, logging framework (or async framework!). I'm hoping logot can be a more powerful caplog / assertLogs fixture that doesn't care if you're using logging, loguru, structlog, or anything else.

Would you accept a PR linking to logot from your help and guides section? Nothing huge, and I'd obviously take your guidance on where to put it / how to phrase it ๐Ÿ™ (and I understand completely if you'd rather not!).

Congrats on the release, @etianen! I'm glad you found integration with Loguru easy!

Your library would definitely fit well in the Loguru documentation. I'd be happy to accept a PR. ;)

This could be covered in one of the two sections I linked to above, or we could create a new section in Code Snippets and Recipes for Loguru to explain how to test logging. If the latter, we should probably first give general guidance, possibly by pointing to the other sections mentioned earlier, then suggest usage of specialized and more convenient libraries such as Logot.

I have no particular preference. Choose what you think is best, I'm confident it will be great. ๐Ÿ‘