enrich 💸

Sam Foreman

2024-02-06

rich 🤝 logging

enrich provides a generalized RichHandler that allows for rich style highlights without line breaks

💡 Tip

This document is best viewed online at enrich

Figure 1: dark
Figure 2: light

🧩 Install

python3 -m pip install "git+https://github.com/saforem2/enrich"
test_logger.py
from enrich import get_logger
log = get_logger(name='test', level='DEBUG')
log.debug('debug')
log.info('info')
log.warning('warning')
log.error('error')
log.critical('critical')
Output:
[2024-01-28 11:13:30][DEBUG][test_logger:24] - debug  
[2024-01-28 11:13:30][INFO][test_logger:25] - info  
[2024-01-28 11:13:30][WARNING][test_logger:26] - warning  
[2024-01-28 11:13:30][ERROR][test_logger:27] - error  
[2024-01-28 11:13:30][CRITICAL][test_logger:28] - critical

📸 Screenshots

🤷🏻‍♂️ Ambivalent

ambivalent

ambivalent

ambivalent-transparent

ambivalent-transparent
😻 Catpuccin Latte

catpuccin-latte catpuccin-latte-transparent

😈 Doom One

doom-one doom-one-transparent

💅 Styles

Dark Styles
Figure 3: dark-styles
Light Styles
Figure 4: light-styles

⚙️ Setup

from enrich import get_logger
log = get_logger(name='enrich', level='DEBUG')
Output
log.debug('debug')
log.info('info')
log.warning('warning')
log.error('error')
log.critical('critical')
[2024-01-28 11:04:50][DEBUG][ipython:1] - debug
[2024-01-28 11:04:50][INFO][ipython:2] - info
[2024-01-28 11:04:50][WARNING][ipython:3] - warning
[2024-01-28 11:04:50][ERROR][ipython:4] - error
[2024-01-28 11:04:50][CRITICAL][ipython:5] - critical
Alternative Setup
  • logging.config.dictConfig(...):

    import yaml
    with Path('logconf.yaml').open('r') as stream:
        config = yaml.load(stream, Loader=yaml.FullLoader)
    log_config = logging.config.dictConfig(config)
    log = logging.getLogger(__name__)
    log.setLevel('INFO')
  • Where logconf.yaml:

    ---
    # logconf.yaml
    handlers:
      term:
        class: enrich.handler.RichHandler
        show_time: true
        show_level: true
        enable_link_path: false
        level: DEBUG
    root:
      handlers: [term]
    disable_existing_loggers: false
    ...

📚 Details

↪️ Redirect support

Our Console class adds one additional option to rich.Console in order to redirect sys.stdout and sys.stderr streams using a FileProxy.

from enrich.console import Console
import sys

console = Console(
    redirect=True,  # <-- not supported by rich.console.Console
    record=True)
sys.write("foo")

# this assert would have passed without redirect=True
assert console.export_text() == "foo"

🌯 Soft wrapping

If you want to produce fluid terminal output, one where the client terminal decides where to wrap the text instead of the application, you can now tell the Console constructor the soft_wrap preference.

from enrich.console import Console
import sys

console = Console(soft_wrap=True)
console.print(...)  # no longer need to pass soft_wrap to each print

Rich logger assumes that you always have a fixed width console and it does wrap logged output according to it. Our alternative logger does exactly the opposite: it ignores the columns of the current console and prints output using a Console with soft wrapping enabled.

The result are logged lines that can be displayed on any terminal or web page as they will allow the client to decide when to perform the wrapping.

import logging
from enrich.logging import RichHandler

FORMAT = "%(message)s"
logging.basicConfig(
    level="NOTSET", format=FORMAT, datefmt="[%X]", handlers=[RichHandler()]
)

log = logging.getLogger("rich")
log.info("Text that we do not want pre-wrapped by logger: %s", 100 * "x")

💾 ANSI Escapes

Extends Rich Console to detect if original text already had ANSI escapes and decodes it before processing it. This solves the case where printing output captured from other processes that contained ANSI escapes would brake. upstream-404

❤️‍🩹 Status

Last Updated: 02/06/2024 @ 11:11:20