1
0
mirror of https://github.com/JoelBender/bacpypes synced 2025-09-28 22:15:23 +08:00
bacpypes/py25/bacpypes/consolelogging.py

243 lines
7.6 KiB
Python
Executable File

#!/usr/bin/python
"""
Console Logging
"""
import os
import sys
import logging
import logging.handlers
try:
from argparse import ArgumentParser as _ArgumentParser
_argparse_success = True
except:
class _ArgumentParser: pass
_argparse_success = False
from .debugging import bacpypes_debugging, LoggingFormatter, ModuleLogger
from ConfigParser import ConfigParser as _ConfigParser
# some debugging
_debug = 0
_log = ModuleLogger(globals())
# configuration
BACPYPES_INI = os.getenv('BACPYPES_INI', 'BACpypes.ini')
BACPYPES_DEBUG = os.getenv('BACPYPES_DEBUG', '')
BACPYPES_COLOR = os.getenv('BACPYPES_COLOR', None)
BACPYPES_MAXBYTES = int(os.getenv('BACPYPES_MAXBYTES', 1048576))
BACPYPES_BACKUPCOUNT = int(os.getenv('BACPYPES_BACKUPCOUNT', 5))
#
# ConsoleLogHandler
#
def ConsoleLogHandler(loggerRef='', handler=None, level=logging.DEBUG, color=None):
"""Add a handler to stderr with our custom formatter to a logger."""
if isinstance(loggerRef, logging.Logger):
pass
elif isinstance(loggerRef, str):
# check for root
if not loggerRef:
loggerRef = _log
# check for a valid logger name
elif loggerRef not in logging.Logger.manager.loggerDict:
raise RuntimeError("not a valid logger name: %r" % (loggerRef,))
# get the logger
loggerRef = logging.getLogger(loggerRef)
else:
raise RuntimeError("not a valid logger reference: %r" % (loggerRef,))
# see if this (or its parent) is a module level logger
if hasattr(loggerRef, 'globs'):
loggerRef.globs['_debug'] += 1
elif hasattr(loggerRef.parent, 'globs'):
loggerRef.parent.globs['_debug'] += 1
# make a handler if one wasn't provided
if not handler:
handler = logging.StreamHandler()
handler.setLevel(level)
# use our formatter
handler.setFormatter(LoggingFormatter(color))
# add it to the logger
loggerRef.addHandler(handler)
# make sure the logger has at least this level
loggerRef.setLevel(level)
#
# ArgumentParser
#
class ArgumentParser(_ArgumentParser):
"""
ArgumentParser extends the one with the same name from the argparse module
by adding the common command line arguments found in BACpypes applications.
--buggers list the debugging logger names
--debug [DEBUG [DEBUG ...]] attach a handler to loggers
--color debug in color
"""
def __init__(self, **kwargs):
"""Follow normal initialization and add BACpypes arguments."""
if _debug: ArgumentParser._debug("__init__")
if not _argparse_success:
raise ImportError("No module named argparse, install via pip or easy_install: https://pypi.python.org/pypi/argparse\n")
_ArgumentParser.__init__(self, **kwargs)
# add a way to get a list of the debugging hooks
self.add_argument("--buggers",
help="list the debugging logger names",
action="store_true",
)
# add a way to attach debuggers
self.add_argument('--debug', nargs='*',
help="add a log handler to each debugging logger",
)
# add a way to turn on color debugging
self.add_argument("--color",
help="turn on color debugging",
action="store_true",
)
def parse_args(self, *args, **kwargs):
"""Parse the arguments as usual, then add default processing."""
if _debug: ArgumentParser._debug("parse_args")
# pass along to the parent class
result_args = _ArgumentParser.parse_args(self, *args, **kwargs)
# check to dump labels
if result_args.buggers:
loggers = sorted(logging.Logger.manager.loggerDict.keys())
for loggerName in loggers:
sys.stdout.write(loggerName + '\n')
sys.exit(0)
# check for debug
if result_args.debug is None:
# --debug not specified
result_args.debug = []
elif not result_args.debug:
# --debug, but no arguments
result_args.debug = ["__main__"]
# check for debugging from the environment
if BACPYPES_DEBUG:
result_args.debug.extend(BACPYPES_DEBUG.split())
if BACPYPES_COLOR:
result_args.color = True
# keep track of which files are going to be used
file_handlers = {}
# loop through the bug list
for i, debug_name in enumerate(result_args.debug):
color = (i % 6) + 2 if result_args.color else None
debug_specs = debug_name.split(':')
if len(debug_specs) == 1:
ConsoleLogHandler(debug_name, color=color)
else:
# the debugger name is just the first component
debug_name = debug_specs[0]
# if the file is already being used, use the already created handler
file_name = debug_specs[1]
if file_name in file_handlers:
handler = file_handlers[file_name]
else:
if len(debug_specs) >= 3:
maxBytes = int(debug_specs[2])
else:
maxBytes = BACPYPES_MAXBYTES
if len(debug_specs) >= 4:
backupCount = int(debug_specs[3])
else:
backupCount = BACPYPES_BACKUPCOUNT
# create a handler
handler = logging.handlers.RotatingFileHandler(
file_name, maxBytes=maxBytes, backupCount=backupCount,
)
handler.setLevel(logging.DEBUG)
# save it for more than one instance
file_handlers[file_name] = handler
# use this handler, no color
ConsoleLogHandler(debug_name, handler=handler)
# return what was parsed
return result_args
bacpypes_debugging(ArgumentParser)
#
# ConfigArgumentParser
#
class ConfigArgumentParser(ArgumentParser):
"""
ConfigArgumentParser extends the ArgumentParser with the functionality to
read in a configuration file.
--ini INI provide a separate INI file
"""
def __init__(self, **kwargs):
"""Follow normal initialization and add BACpypes arguments."""
if _debug: ConfigArgumentParser._debug("__init__")
ArgumentParser.__init__(self, **kwargs)
# add a way to read a configuration file
self.add_argument('--ini',
help="device object configuration file",
default=BACPYPES_INI,
)
def parse_args(self, *args, **kwargs):
"""Parse the arguments as usual, then add default processing."""
if _debug: ConfigArgumentParser._debug("parse_args")
# pass along to the parent class
result_args = ArgumentParser.parse_args(self, *args, **kwargs)
# read in the configuration file
config = _ConfigParser()
config.read(result_args.ini)
if _debug: _log.debug(" - config: %r", config)
# check for BACpypes section
if not config.has_section('BACpypes'):
raise RuntimeError("INI file with BACpypes section required")
# convert the contents to an object
ini_obj = type('ini', (object,), dict(config.items('BACpypes')))
if _debug: _log.debug(" - ini_obj: %r", ini_obj)
# add the object to the parsed arguments
setattr(result_args, 'ini', ini_obj)
# return what was parsed
return result_args
bacpypes_debugging(ConfigArgumentParser)