Usage¶
Color Language¶
In order to colorize a word or words, the ColorFormatter
implements a DSL or Domain Specific Language.
Colorizing a string of text automatically can be done by using the following as a schemata: #x<text>
where x
is
the lowercase first letter of the color you want the text to appear in the terminal and text
is the string of
characters to be colored. For example, to color a string blue:
"#b<I am blue text>"
This can be done on a substring leaving the rest of the words untouched. In the following example only the word
green
would be colored, the rest of the text would appear in the terminals default color:
"This text has some #g<green> words. Okay, just one actually."
Tip
Automatic coloring of text occurs only within the context of a log message. No other string values are handled.
Here is a more complete example of a log message with colored text; in this example, the path substring would be colored green:
LOG.debug("Processing asset #g<%s>", path)
The same example but with Python3-only f-strings:
LOG.debug(f"Processing asset #g<{path}>")
In the above examples the value of the variable path would be printed as green text to the console.
Logging Tip:
Do not use f-strings in log messages. The format-pointer style with arguments passed directly to the log handler is the preferred method for logging because it will avoid formatting the strings if the log message will not be omitted.
Bad:
LOG.debug("Foo %s" % bar)
LOG.debug("Foo {}".format(bar))
``LOG.debug(f”Foo {bar}”)
Good:
LOG.debug("Foo %s", bar)
Tip
The difference between the incorrect LOG.debug("Foo %s" % bar)
and the correct LOG.debug("Foo %s", bar)
is that the good one doesn’t use the %
operator, but instead passes the format variables to the log handler
as arguments.
Supported Colors¶
Only a few colors are supported by the ColoredFormatter
, but they should be
sufficient for most purposes.
b
—#b<blue>
c
—#b<cyan>
g
—#b<green>
m
—#b<maroon>
r
—#b<red>
w
—#b<white>
y
—#b<yellow>
db
—#b<dark-blue>
dc
—#b<dark-cyan>
dg
—#b<dark-green>
dm
—#b<dark-maroon>
dr
—#b<dark-red>
dy
—#b<dark-yellow>
Color Stripping¶
If you’re using the #b<blue>
notation, you probably realize that this means that if you log to a file, you’ll end
up with text that looks more like \033[94mblue\033[0m
since it contains the color escape codes. Or, alternatively,
if you use a different formatter, you’ll have the literal #b<blue>
string in the text. Neither of these are ideal.
To that end, another formatter is provided called: ColorStripper
. The purpose of this is to remove any escape codes
and/or Color Language references from the text passing through the formatter.
This allows you to easily write plain text to files or other log handlers, while still using colored output for a console logger.
Configuration¶
Configuration is very simple. Simply import the ColorFormatter
and use it like you would any other log formatter.
Simple Example:
import logging
from log_color import ColorFormatter
handler = logging.StreamHandler()
formatter = ColorFormatter("%(levelname)s: %(message)s")
handler.setFormatter(formatter)
log = logging.getLogger('color_log')
log.setLevel(logging.INFO)
log.addHandler(handler)
log.info('Look, #b<blue> text!')
Here is a DictConfig (that also uses the ColorStripper formatter for a file handler):
from logging.config import dictConfig
from log_color import ColorFormatter, ColorStripper
BASE_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
"ConsoleFormatter": {
'()': ColorFormatter,
"format": "%(levelname)s: %(message)s",
},
"FileFormatter": {
'()': ColorStripper,
"format": ("%(levelname)-8s: %(asctime)s '%(message)s' "
"%(name)s:%(lineno)s"),
"datefmt": "%Y-%m-%d %H:%M:%S",
},
},
'handlers': {
"console": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": "ConsoleFormatter",
},
"filehandler": {
'level': "DEBUG",
'class': 'logging.handlers.RotatingFileHandler',
'filename': "/tmp/logfile",
'formatter': 'FileFormatter',
},
},
'loggers': {
'my_script': {
'handlers': ["console", "filehandler"],
'level': 'INFO',
},
}
}
dictConfig(BASE_CONFIG)
Troubleshooting¶
Output Not Colorized¶
There are a couple of things to check for:
- If you’re running on Windows, colorized output is not supported.
- If you’re in a *nix terminal and ANSI color codes are supported but you’re not
seeing colorized output, check for the
NO_COLOR
environment variable. See no-color.org for more information on this standard. If theNO_COLOR
environment variable is set, colorized output is automatically suppressed. - Something else: It could be the case that the detection scheme that
log_color
ships is failing to detect that your particular terminal supports ANSI color codes. Detection of color support could be offloaded to a third party library, but one of the goals oflog_color
is to have no dependencies. Color support detection isn’t standardized and most libraries that do color support detection employ reaching out to ncurses or including a huge array of information about very specific (and often obscure) terminals. I’m willing to include support for specific terminals if someone wishes to add them, but I’m not going to default to doing all of that work if no one is using them anyway. Color detection support can be found insrc/log_color/colors.py
in the ColorStr class. Thecolor_supported
method handles detection so feel free to add it there.