Skip to content

Instantly share code, notes, and snippets.

@taikedz
Created February 16, 2022 12:38
Show Gist options
  • Save taikedz/cf3f2e5e4132926a44cfedb021045a33 to your computer and use it in GitHub Desktop.
Save taikedz/cf3f2e5e4132926a44cfedb021045a33 to your computer and use it in GitHub Desktop.

Easy Custom Logger

The default setup for the logging utility is a little unwieldy to set up for every project - though once done, it is likely to seldom change.

This snippet provides a pre-configured global logging utility allowing for a log level to be set via environment variable, as well as a pretty-print dump() log function that writes when level is set to DEBUG.

By default, logging goes to stdout, but can be redirected to a file.

""" Convenience package to get a pre-configured logging object.
In your code, import this package then simply use the logging functions:
logger.debug(message)
logger.info(message)
logger.warning(message)
logger.error(message)
There is also a debug-level function for dumping data
logger.dump(data)
The default log level is INFO
This can be adjusted by providing an environment variable
CUSTOM_LOG_LEVEL
or in-code by calling logger.setLevel()
!! Logging To A File:
Upon importing fcilog , immediately use logger.setLogFile(filename)
This can only be done once, subsequent attempts will raise a
logger.LoggerConfigException
+++
Copyright: (C) Tai Kedzierski
License: MIT License (see https://mit-license.org/)
You are free to include, adapt and distribute your changes,
provided you retain this copyright notice.
"""
import os
import logging
import pprint
DEBUG = logging.DEBUG
INFO = logging.INFO
WARNING = logging.WARNING
ERROR = logging.ERROR
__custom_logger = None
__custom_logger_handler = None
__pretty = pprint.PrettyPrinter(indent=2)
__log_file_name = None
def setLogFile(filename):
# TODO
# Using logging.basicConfig() in its base form, only
# one attempt at setting the file will have sane effects.
# This code prvents multiple calls to reconfigure file,
# but ideally should just switch file
global __log_file_name
if __custom_logger is None:
__log_file_name = filename
__createLogger(filename)
return
if __log_file_name:
raise LoggerConfigException("Logging is already being written to '{fname}'.".format(fname=__log_file_name) )
else:
raise LoggerConfigException("Logging has already started and can no longer be directed to a file.")
def setLevel(level):
""" Activate a new logging level
"""
_ = __getLogger()
__custom_logger.setLevel(level)
__custom_logger_handler.setLevel(level)
def dump(data):
logger = __getLogger()
logger.debug(__pretty.pformat(data))
def debug(message):
__getLogger().debug(message)
def info(message):
__getLogger().info(message)
def warning(message):
__getLogger().warning(message)
def error(message):
__getLogger().error(message)
def __getLogger():
if __custom_logger == None:
__createLogger()
return __custom_logger
def __createLogger(filename=None):
global __custom_logger
global __custom_logger_handler
format_string = '%(asctime)s | %(message)s'
if filename:
logging.basicConfig(filename=filename, format=format_string)
level = __get_string_log_level(os.getenv("CUSTOM_LOG_LEVEL", "INFO"))
__custom_logger = logging.getLogger("custom_log")
__custom_logger_handler = logging.StreamHandler()
setLevel(level) # MUST be called after setting the __custom_logger* variables, else infinite recursion!
formatter = logging.Formatter(format_string)
__custom_logger_handler.setFormatter(formatter)
__custom_logger.addHandler(__custom_logger_handler)
def __get_string_log_level(level):
if level == "DEBUG":
return DEBUG
elif level == "INFO":
return INFO
elif level == "WARNING":
return WARNING
elif level == "ERROR":
return ERROR
else:
raise ValueError("'{level}' is not a recognised log level".format(level=level))
class LoggerConfigException(Exception):
def __init__(self, message):
Exception.__init__(self, message)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment