9

Let's simplify this. My goal is to make color output in terminal using logging module in Python. I want info has a green prefix, warnings have a yellow prefix and errors have a red prefix. To make it simple let's use *** as the prefix i.e.

*** log text
*** another message with another prefix color

What I have done so far

# declaration of function (global scope)
log = None
warn = None
error = None 
def build_log_funcs():
    # why I initialize it inside the function ?
    # because script doesnt have to know about logging method
    # the function just provide log  functions
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)

    sh = logging.StreamHandler()
    # LOG_FORMAT just global variable with pattern including %(levelmarks)s
    # it will be replaced with ** with proper color 
    formatter = logging.Formatter(LOG_FORMAT)
    sh.setFormatter(formatter)
    logger.addHandler(sh)

    def make_log_func(func, color, is_exit = False):
        color_string = "\x1b[{};1m***\x1b[0m".format(color)
        def newfunc(*args, **kwargs):
            func(*args, extra={'levelmarks':color_string}, **kwargs)
            if is_exit:
                sys.exit(-1)

        return newfunc
    # 32, 33, 31 are color codes
    log = make_log_func(logger.info, 32)
    warn = make_log_func(logger.warning, 33)
    error = make_log_func(logger.error, 31, is_exit = True)

    return log, warn, error

And use it as

log, warn, error = build_log_funcs()

It works but what I don't like: (from small to big problems)

  1. I hide the capabilities of logging module. For example enabling/disabling debug messages
  2. I should use global declaration of functions before their initialization because I can't call a function before its declaration.
  3. It's too difficult to read and maintain the code. I believe that everything should be as simple as possible.

Why don't I just make simple log, warn, simple function? I don't know. logging is the very comprehensive module so may be I will need its features in the future.

My question is how would you solve this problem? May be there is a simple obvious way which I don't know.

2
  • 1
    It will be nicer to do this with decorators. See this excellent answer here Commented Dec 20, 2013 at 15:00
  • 2
    Have you seen this? Commented Dec 20, 2013 at 15:03

1 Answer 1

10

Thanks Dominic Kexel for this link. I saw this but did not pay attention to the answer. The following code is more or less suitable for me

def setup_logger(logger):
    logger.setLevel(logging.DEBUG)

    sh = logging.StreamHandler()
    formatter = logging.Formatter(LOG_FORMAT)
    sh.setFormatter(formatter)

    def decorate_emit(fn):
    # add methods we need to the class
        def new(*args):
            levelno = args[0].levelno
            if(levelno >= logging.CRITICAL):
                color = '\x1b[31;1m'
            elif(levelno >= logging.ERROR):
                color = '\x1b[31;1m'
            elif(levelno >= logging.WARNING):
                color = '\x1b[33;1m'
            elif(levelno >= logging.INFO):
                color = '\x1b[32;1m'
            elif(levelno >= logging.DEBUG):
                color = '\x1b[35;1m'
            else:
                color = '\x1b[0m'
            # add colored *** in the beginning of the message
            args[0].msg = "{0}***\x1b[0m {1}".format(color, args[0].msg)

            # new feature i like: bolder each args of message 
            args[0].args = tuple('\x1b[1m' + arg + '\x1b[0m' for arg in args[0].args)
            return fn(*args)
        return new
    sh.emit = decorate_emit(sh.emit)
    logger.addHandler(sh)

There is one flaw in this: I can't control the position of *** in the pattern but as I said it's suitable.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.