Colorizing Loggers -- A simple practice of decorator
What is this post about
Many people believe that decorator is one of the obscure concepts in Python.
Trust me, it is not. To be short, a decorator is a function that modifies other
functions via closures.
They are plenty detailed articles about what decorator it is so there is no need to write one more. If you are not familiar with it, you may want to check these:
In this article, I am going to use a simple but interesting example to show
- how to colorize the output in command line
- how to implement a switch case in Python (Python does not have built-in switch case)
- a decorator with parameters
OK, let’s rock.
colorize your text
There is a set of escape sequences used to change the color of texts. So if we want to colorize a sentence, we just need to put the sentence between the color escape sequence and reset escape sequence. For example:1
2
3
4
5
6
7>> ORANGE = '\033[33m'
>> RED = '\033[31m'
>> GREEN = '\033[32m'
>> BLUE = '\033[34m'
>> RESET = '\033[0m'
>> print ORANGE + "Chinese New Year" + RESET
>> print GREEN + "Chinese" + GREEN + "New" + BLUE + "Year" + RESET
You will see
Chinese New Yearand
Chinese New YearHow to choose the color in code
As I said, Python does not support switch case. So we cannot switch the color name and choose the corresponding escaped sequence. Fortunately, dictionary would do the work.
1 | def getColor(color): |
The trick is, the dictionary’s built in get
method. The first parameter here is key, the second optional parameter is default. As the docstring shows:
D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
Use the decorator
Suppose we have a function to implement a task. It may has three kind of return string, if task is completed successfully, it returns “SUCCESS: blah blah …”, if the task is finished but we cannot ensure it’s corretness, it returns “WARNING: blah blah …”, if task failed, returns “ERROR: blah blah …”, how do we colorize these return strings?
Raw code1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37def colorize(*args):
def getColor(color):
return {
'black' : '\033[30m',
'red' : '\033[31m',
'green' : '\033[32m',
'orange' : '\033[33m',
'blue' : '\033[34m',
'purple' : '\033[35m',
'cyan' : '\033[36m',
'light_grey' : '\033[37m'
}.get(color, "")
def _colorize():
def wrapper():
RESET = '\033[0m'
text = func()
#if not isinstance(text, basestring):
# text = str(text)
level = text.split(':', 1)[0]
color = {
'SUCCESS': args[0],
'WARNING': args[1],
'ERROR': args[2]
}.get(level, '')
return "{0}{1}{2}".format(getColor(color), text, RESET)
return wrapper
return _colorize
def do_task():
# working working ....
if (success):
return "SUCCESS: Yeah~~"
elif (warning):
return "WARNING: wait, what?"
else:
return "ERROR: something went wrong here."
As you can tell, to make the decorator with parameters, we need to put it in another decorator.
Decorator are often used as cache, profiler, logger, synchronization(acquire lock, drop lock) and so forth. One of my favourite library Click is also a wonderful example.
Happy Chinese New Year ~