New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for colorized logging output #197

Closed
derks opened this Issue Jun 11, 2013 · 8 comments

Comments

Projects
None yet
2 participants
@derks
Member

derks commented Jun 11, 2013

In apps that heavily rely on logging to the console, having colorized output is very useful. For example:

  • INFO => No Color
  • WARN => Orange
  • ERROR => Red
  • Critical => Magenta or maybe just Bold Red
@derks

This comment has been minimized.

Show comment
Hide comment
@derks
Member

derks commented Jun 11, 2013

@derks

This comment has been minimized.

Show comment
Hide comment

@ghost ghost assigned derks Oct 22, 2013

@derks

This comment has been minimized.

Show comment
Hide comment
@derks

derks Apr 23, 2014

Member

An example (slightly hackish) alternative logger with color:

import logging
from colorlog import ColoredFormatter
from cement.core import handler
from cement.utils.misc import is_true
from cement.ext.ext_logging import LoggingLogHandler, NullHandler
from cement.core.controller import expose, CementBaseController

class ColorLogController(CementBaseController):
    class Meta:
        label = 'color_log'
        arguments = [
            (['--no-color'],
             dict(help="disable colorized output", action='store_true')),
        ]

class ColorLogHandler(LoggingLogHandler):
    class Meta:
        label = "color_log"

        #: The logging format for the consoler logger.
        console_format = "%(log_color)s%(levelname)s: %(message)s"

        #: The logging format for both file and console if ``debug==True``.
        debug_format = "%(log_color)s%(asctime)s (%(levelname)s) %(namespace)s : " + \
                       "%(message)s"

    def _setup_console_log(self):
        # Otherwise
        to_console = self.app.config.get(self._meta.config_section,
                                         'to_console')
        if is_true(to_console):
            console_handler = logging.StreamHandler()
            if self.get_level() == logging.getLevelName(logging.DEBUG):
                the_format = self._meta.debug_format
            else:
                the_format = self._meta.console_format

            formatter = ColoredFormatter(the_format,
                            log_colors={
                                'DEBUG':    'white',
                                'INFO':     'green',
                                'WARNING':  'yellow',
                                'ERROR':    'red',
                                'CRITICAL': 'red',
                                })
            console_handler.setFormatter(formatter)
            console_handler.setLevel(getattr(logging, self.get_level()))
        else:
            console_handler = NullHandler()

        self.backend.addHandler(console_handler)

def load():
    handler.register(ColorLogHandler)
    handler.register(ColorLogController)
Member

derks commented Apr 23, 2014

An example (slightly hackish) alternative logger with color:

import logging
from colorlog import ColoredFormatter
from cement.core import handler
from cement.utils.misc import is_true
from cement.ext.ext_logging import LoggingLogHandler, NullHandler
from cement.core.controller import expose, CementBaseController

class ColorLogController(CementBaseController):
    class Meta:
        label = 'color_log'
        arguments = [
            (['--no-color'],
             dict(help="disable colorized output", action='store_true')),
        ]

class ColorLogHandler(LoggingLogHandler):
    class Meta:
        label = "color_log"

        #: The logging format for the consoler logger.
        console_format = "%(log_color)s%(levelname)s: %(message)s"

        #: The logging format for both file and console if ``debug==True``.
        debug_format = "%(log_color)s%(asctime)s (%(levelname)s) %(namespace)s : " + \
                       "%(message)s"

    def _setup_console_log(self):
        # Otherwise
        to_console = self.app.config.get(self._meta.config_section,
                                         'to_console')
        if is_true(to_console):
            console_handler = logging.StreamHandler()
            if self.get_level() == logging.getLevelName(logging.DEBUG):
                the_format = self._meta.debug_format
            else:
                the_format = self._meta.console_format

            formatter = ColoredFormatter(the_format,
                            log_colors={
                                'DEBUG':    'white',
                                'INFO':     'green',
                                'WARNING':  'yellow',
                                'ERROR':    'red',
                                'CRITICAL': 'red',
                                })
            console_handler.setFormatter(formatter)
            console_handler.setLevel(getattr(logging, self.get_level()))
        else:
            console_handler = NullHandler()

        self.backend.addHandler(console_handler)

def load():
    handler.register(ColorLogHandler)
    handler.register(ColorLogController)
@spinus

This comment has been minimized.

Show comment
Hide comment
@spinus

spinus Aug 12, 2014

Contributor
  1. What is the point of turning colors on colorlog, it's not simpler to use standard logger instead?
  2. You can detect that output stream is console/tty or not. If not you can use non-color logging (some applications do that, like ls, grep, this feature gives you ability to pipe/chain applications)
Contributor

spinus commented Aug 12, 2014

  1. What is the point of turning colors on colorlog, it's not simpler to use standard logger instead?
  2. You can detect that output stream is console/tty or not. If not you can use non-color logging (some applications do that, like ls, grep, this feature gives you ability to pipe/chain applications)
@derks

This comment has been minimized.

Show comment
Hide comment
@derks

derks Aug 12, 2014

Member

@spinus are you suggested in 1 to just add the color functionality to LoggingLogHandler rather than sub-classing and having a separate handler?

And in 2 I think that is a good idea to disable coloring if we don't have a tty, that makes sense.

Thanks.

Member

derks commented Aug 12, 2014

@spinus are you suggested in 1 to just add the color functionality to LoggingLogHandler rather than sub-classing and having a separate handler?

And in 2 I think that is a good idea to disable coloring if we don't have a tty, that makes sense.

Thanks.

@spinus

This comment has been minimized.

Show comment
Hide comment
@spinus

spinus Aug 12, 2014

Contributor
  1. No at all. I think there can be two handlers, one standard and one fancy.
    Btw, during the development maybe you would like to watch on this: https://pypi.python.org/pypi/rainbow_logging_handler/2.2.2
Contributor

spinus commented Aug 12, 2014

  1. No at all. I think there can be two handlers, one standard and one fancy.
    Btw, during the development maybe you would like to watch on this: https://pypi.python.org/pypi/rainbow_logging_handler/2.2.2
@derks

This comment has been minimized.

Show comment
Hide comment
@derks

derks Aug 12, 2014

Member

Yeah, that Rainbow Logging Handler looks pretty much perfect, and seems to have been around for a while. I'll look at doing both (the above doesn't require additional dependencies so it can go in core).

Member

derks commented Aug 12, 2014

Yeah, that Rainbow Logging Handler looks pretty much perfect, and seems to have been around for a while. I'll look at doing both (the above doesn't require additional dependencies so it can go in core).

@derks derks removed the stable/2.2.x label Aug 21, 2014

@derks derks self-assigned this Aug 21, 2014

derks added a commit that referenced this issue May 6, 2015

@derks

This comment has been minimized.

Show comment
Hide comment
@derks

derks May 6, 2015

Member

This was committed to cement/master based on colorlog:

from cement.core.foundation import CementApp

class MyApp(CementApp):
    class Meta:
        label = 'myapp'
        extensions = ['colorlog']
        log_handler = 'colorlog'

with MyApp() as app:
    app.run()
    app.log.info('My Info Test')
    app.log.error('My Error Test')
    app.log.fatal('My Fatal Test')
    app.log.warn('My Warn Test')
    app.log.debug('My Debug Test')
Member

derks commented May 6, 2015

This was committed to cement/master based on colorlog:

from cement.core.foundation import CementApp

class MyApp(CementApp):
    class Meta:
        label = 'myapp'
        extensions = ['colorlog']
        log_handler = 'colorlog'

with MyApp() as app:
    app.run()
    app.log.info('My Info Test')
    app.log.error('My Error Test')
    app.log.fatal('My Fatal Test')
    app.log.warn('My Warn Test')
    app.log.debug('My Debug Test')

@derks derks closed this May 6, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment