Skip to content

Instantly share code, notes, and snippets.

@stemid
Last active June 7, 2018 11:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stemid/cbf506007a0b041ee3450c5505598bc2 to your computer and use it in GitHub Desktop.
Save stemid/cbf506007a0b041ee3450c5505598bc2 to your computer and use it in GitHub Desktop.
Boilerplate logging class I use in most my applications
# AppLogger specific config.
[logging]
log_format = %(asctime)s %(name)s[%(process)s] %(levelname)s: %(message)s
log_debug = True
log_level = INFO
# Handler can be one of file, stdout or syslog
log_handler = stdout
# Can use this to log directly to another server if need be
syslog_address = /dev/log
syslog_port = 514
# For file handler, 20MB file size limit
log_max_bytes = 20971520
log_max_copies = 5
log_file = ./restapi.log
# This has served me well now for half a dozen different microservices
# and applications so it's time to put it up on Gist so I never lose it.
# Init like this;
# al = AppLogger('my-app', config)
# log = al.logger
# log.info('hej')
# Where config is a ConfigParser instance and the config file needs a
# [logging] section that is described in the config_defaults dict below.
#
# by Stefan Midjich <swehack at gmail dot com>
import sys
from logging import StreamHandler
from logging import Formatter, getLogger, getLevelName, DEBUG, WARN, INFO
from logging.handlers import SysLogHandler, RotatingFileHandler
# Mostly for documentation purposes
config_defaults = {
'log_format': '%(asctime)s %(name)s[%(process)s] %(levelname)s: %(message)s',
'log_debug': True,
'log_level': 'INFO',
# or file, or syslog
'log_handler': 'stdout',
# Can be remote server address
'syslog_address': '/dev/log',
'syslog_port': 514,
# 20MB
'log_max_bytes': 20971520,
'log_max_copies': 5,
'log_file': './default.log'
}
class AppLogger(object):
def __init__(self, name, config):
"""This initializes with a RawConfigParser object to get most of its
default settings.
"""
formatter = Formatter(config.get('logging', 'log_format'))
self.logger = getLogger(name)
if config.get('logging', 'log_handler') == 'syslog':
syslog_address = config.get('logging', 'syslog_address')
default_facility = SysLogHandler.LOG_LOCAL0
if syslog_address.startswith('/'):
h = SysLogHandler(
address=syslog_address,
facility=default_facility
)
else:
h = SysLogHandler(
address=(
config.get('logging', 'syslog_address'),
config.get('logging', 'syslog_port')
),
facility=default_facility
)
elif config.get('logging', 'log_handler') == 'file':
h = RotatingFileHandler(
config.get('logging', 'log_file'),
maxBytes=config.getint('logging', 'log_max_bytes'),
backupCount=config.getint('logging', 'log_max_copies')
)
else:
h = StreamHandler(stream=sys.stdout)
h.setFormatter(formatter)
self.logger.addHandler(h)
try:
log_level = getLevelName(
config.get('logging', 'log_level').toupper()
)
except:
log_level = DEBUG
pass
self.handler = h
self.logger.setLevel(log_level)
def apply_handler(self, logger_name):
"""
Some frameworks init their own loggers, like tornado for example.
So use this to apply your handler to their loggers by specifying the
logger name.
"""
logger = getLogger(logger_name)
logger.addHandler(self.handler)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment