-
-
Save alvinthai/c094ef178481be8492e3774dd4ef9e91 to your computer and use it in GitHub Desktop.
Python dual-logging setup (console and log file) supporting different log levels and colorized output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
# ------------------------------------------------------------------------------- | |
# - | |
# Python dual-logging setup (console and log file), - | |
# supporting different log levels and colorized output - | |
# - | |
# Created by Fonic <https://github.com/fonic> - | |
# Date: 04/05/20 - | |
# - | |
# Based on: - | |
# https://stackoverflow.com/a/13733863/1976617 - | |
# https://uran198.github.io/en/python/2016/07/12/colorful-python-logging.html - | |
# https://en.wikipedia.org/wiki/ANSI_escape_code#Colors - | |
# - | |
# ------------------------------------------------------------------------------- | |
# Imports | |
import os | |
import sys | |
import logging | |
# Logging formatter supporting colored output | |
class LogFormatter(logging.Formatter): | |
COLOR_CODES = { | |
logging.CRITICAL: "\033[1;35m", # bright/bold magenta | |
logging.ERROR: "\033[1;31m", # bright/bold red | |
logging.WARNING: "\033[1;33m", # bright/bold yellow | |
logging.INFO: "\033[0;37m", # white / light gray | |
logging.DEBUG: "\033[1;30m" # bright/bold black / dark gray | |
} | |
RESET_CODE = "\033[0m" | |
def __init__(self, color, *args, **kwargs): | |
super(LogFormatter, self).__init__(*args, **kwargs) | |
self.color = color | |
def format(self, record, *args, **kwargs): | |
if (self.color == True and record.levelno in self.COLOR_CODES): | |
record.color_on = self.COLOR_CODES[record.levelno] | |
record.color_off = self.RESET_CODE | |
else: | |
record.color_on = "" | |
record.color_off = "" | |
return super(LogFormatter, self).format(record, *args, **kwargs) | |
# Setup logging | |
def setup_logging(console_log_output, console_log_level, console_log_color, logfile_file, logfile_log_level, logfile_log_color, log_line_template): | |
# Create logger | |
# For simplicity, we use the root logger, i.e. call 'logging.getLogger()' | |
# without name argument. This way we can simply use module methods for | |
# for logging throughout the script. An alternative would be exporting | |
# the logger, i.e. 'global logger; logger = logging.getLogger("<name>")' | |
logger = logging.getLogger() | |
# Set global log level to 'debug' (required for handler levels to work) | |
logger.setLevel(logging.DEBUG) | |
# Create console handler | |
console_log_output = console_log_output.lower() | |
if (console_log_output == "stdout"): | |
console_log_output = sys.stdout | |
elif (console_log_output == "stderr"): | |
console_log_output = sys.stderr | |
else: | |
print("Failed to set console output: invalid output: '%s'" % console_log_output) | |
return False | |
console_handler = logging.StreamHandler(console_log_output) | |
# Set console log level | |
try: | |
console_handler.setLevel(console_log_level.upper()) # only accepts uppercase level names | |
except: | |
print("Failed to set console log level: invalid level: '%s'" % console_log_level) | |
return False | |
# Create and set formatter, add console handler to logger | |
console_formatter = LogFormatter(fmt=log_line_template, color=console_log_color) | |
console_handler.setFormatter(console_formatter) | |
logger.addHandler(console_handler) | |
# Create log file handler | |
try: | |
logfile_handler = logging.FileHandler(logfile_file) | |
except Exception as exception: | |
print("Failed to set up log file: %s" % str(exception)) | |
return False | |
# Set log file log level | |
try: | |
logfile_handler.setLevel(logfile_log_level.upper()) # only accepts uppercase level names | |
except: | |
print("Failed to set log file log level: invalid level: '%s'" % logfile_log_level) | |
return False | |
# Create and set formatter, add log file handler to logger | |
logfile_formatter = LogFormatter(fmt=log_line_template, color=logfile_log_color) | |
logfile_handler.setFormatter(logfile_formatter) | |
logger.addHandler(logfile_handler) | |
# Success | |
return True | |
# Main function | |
def main(): | |
# Setup logging | |
script_name = os.path.splitext(os.path.basename(sys.argv[0]))[0] | |
if (not setup_logging(console_log_output="stdout", console_log_level="warning", console_log_color=True, | |
logfile_file=script_name + ".log", logfile_log_level="debug", logfile_log_color=False, | |
log_line_template="%(color_on)s[%(created)d] [%(threadName)s] [%(levelname)-8s] %(message)s%(color_off)s")): | |
print("Failed to setup logging, aborting.") | |
return 1 | |
# Log some messages | |
logging.debug("Debug message") | |
logging.info("Info message") | |
logging.warning("Warning message") | |
logging.error("Error message") | |
logging.critical("Critical message") | |
# Call main function | |
if (__name__ == "__main__"): | |
sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment