[chirp_devel] [PATCH 1/7] Add chirp.logger module (#2347)
Zach Welch
Thu Feb 26 00:42:14 PST 2015
# HG changeset patch
# User Zach Welch <zach at mandolincreekfarm.com>
Add chirp.logger module (#2347)
This patch adds the chirp.logger module, using it in chirpc and chirpw.
It adds a handful of optional command line arguments to control the new
logging features. In addition, CHIRP_DEBUG, CHIRP_LOG, and
CHIRP_LOG_LEVEL can be used to control the logging features from the
environment.
It also makes the version string reusable between the GUI and CLI, and
it prints that string at the start of the log file (if in use).
diff --git a/chirp/logger.py b/chirp/logger.py
new file mode 100644
index 0000000..4cf8fa2
--- /dev/null
+++ b/chirp/logger.py
@@ -0,0 +1,155 @@
+# Copyright 2015 Zachary T Welch <zach at mandolincreekfarm.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+r"""
+The chirp.logger module provides the core logging facilties for CHIRP.
+It sets up the console and (optionally) a log file. For early debugging,
+it checks the CHIRP_DEBUG, CHIRP_LOG, and CHIRP_LOG_LEVEL environment
+variables.
+"""
+
+import os
+import sys
+import logging
+import argparse
+import platform
+from chirp import CHIRP_VERSION
+
+
+def version_string():
+ args = (CHIRP_VERSION,
+ platform.get_platform().os_version_string(),
+ sys.version.split()[0])
+ return "CHIRP %s on %s (Python %s)" % args
+
+
+class VersionAction(argparse.Action):
+ def __call__(self, parser, namespace, value, option_string=None):
+ print version_string()
+ sys.exit(1)
+
+
+def add_version_argument(parser):
+ parser.add_argument("--version", action=VersionAction, nargs=0,
+ help="Print version and exit")
+
+#: Map human-readable logging levels to their internal values.
+log_level_names = {"critical": logging.CRITICAL,
+ "error": logging.ERROR,
+ "warn": logging.WARNING,
+ "info": logging.INFO,
+ "debug": logging.DEBUG,
+ }
+
+
+class Logger(object):
+ def __init__(self):
+ # create root logger
+ self.logger = logging.getLogger()
+ self.logger.setLevel(logging.DEBUG)
+
+ self.LOG = logging.getLogger(__name__)
+
+ # Set CHIRP_DEBUG in environment for early console debugging.
+ # It can be a number or a name; otherwise, level is set to 'debug'
+ # in order to maintain backward compatibility.
+ CHIRP_DEBUG = os.getenv("CHIRP_DEBUG")
+ level = logging.WARNING
+ if CHIRP_DEBUG:
+ try:
+ level = int(CHIRP_DEBUG)
+ except ValueError:
+ try:
+ level = log_level_names[CHIRP_DEBUG]
+ except KeyError:
+ level = logging.DEBUG
+
+ self.console = logging.StreamHandler()
+ self.console.setLevel(level)
+ format_str = '%(levelname)s: %(message)s'
+ self.console.setFormatter(logging.Formatter(format_str))
+ self.logger.addHandler(self.console)
+
+ # Set CHIRP_LOG in environment to the name of log file.
+ logname = os.getenv("CHIRP_LOG")
+ self.logfile = None
+ if logname is not None:
+ self.create_log_file(logname)
+ level = os.getenv("CHIRP_LOG_LEVEL")
+ if level is not None:
+ self.set_log_verbosity(level)
+ else:
+ self.set_log_level(logging.DEBUG)
+
+ def create_log_file(self, name):
+ if self.logfile is None:
+ self.logname = name
+ lf = file(name, "w")
+ print >>lf, version_string()
+ lf.close()
+ self.logfile = logging.FileHandler(name)
+ format_str = '[%(created)s] %(name)s - %(levelname)s: %(message)s'
+ self.logfile.setFormatter(logging.Formatter(format_str))
+ self.logger.addHandler(self.logfile)
+
+ else:
+ self.logger.error("already logging to " + self.logname)
+
+ def set_verbosity(self, level):
+ if level > logging.CRITICAL:
+ level = logging.CRITICAL
+ self.console.setLevel(level)
+ self.LOG.debug("verbosity=%d", level)
+
+ def set_log_level(self, level):
+ if level > logging.CRITICAL:
+ level = logging.CRITICAL
+ self.logfile.setLevel(level)
+ self.LOG.debug("log level=%d", level)
+
+ def set_log_level_by_name(self, level):
+ self.set_log_level(log_level_names[level])
+
+ instance = None
+
+Logger.instance = Logger()
+
+
+def add_arguments(parser):
+ parser.add_argument("-q", "--quiet", action="count", default=0,
+ help="Decrease verbosity")
+ parser.add_argument("-v", "--verbose", action="count", default=0,
+ help="Increase verbosity")
+ parser.add_argument("--log", dest="log_file", action="store", default=0,
+ help="Log messages to a file")
+ parser.add_argument("--log-level", action="store", default="debug",
+ help="Log file verbosity (critical, error, warn, " +
+ "info, debug). Defaults to 'debug'.")
+
+
+def handle_options(options):
+ logger = Logger.instance
+
+ if options.verbose or options.quiet:
+ logger.set_verbosity(30 + 10 * (options.quiet - options.verbose))
+
+ if options.log_file:
+ logger.create_log_file(options.log_file)
+ try:
+ level = int(options.log_level)
+ logger.set_log_level(level)
+ except ValueError:
+ logger.set_log_level_by_name(options.log_level)
diff --git a/chirpc b/chirpc
index 6a25e50..16c7006 100755
--- a/chirpc
+++ b/chirpc
@@ -19,10 +19,14 @@
import serial
import sys
import argparse
+import logging
+from chirp import logger
from chirp import *
from chirp import chirp_common, errors, idrp, directory, util
+LOG = logging.getLogger("chirpc")
+
def fail_unsupported():
print "Operation not supported by selected radio"
sys.exit(1)
@@ -62,6 +66,7 @@ class DTCSPolarityAction(argparse.Action):
if __name__ == "__main__":
parser = argparse.ArgumentParser()
+ logger.add_version_argument(parser)
parser.add_argument("-s", "--serial", dest="serial",
default="mmap",
help="Serial port (default: mmap)")
@@ -151,8 +156,10 @@ if __name__ == "__main__":
action="store_true",
default=False,
help="Upload memory map to radio")
+ logger.add_arguments(parser)
parser.add_argument("args", metavar="arg", nargs='*',
help="Some commands require additional arguments")
+
if len(sys.argv) <= 1:
parser.print_help()
sys.exit(0)
@@ -160,6 +167,8 @@ if __name__ == "__main__":
options = parser.parse_args()
args = options.args
+ logger.handle_options(options)
+
if options.list_radios:
print "Supported Radios:\n\t", "\n\t".join(sorted(RADIOS.keys()))
sys.exit(0)
diff --git a/chirpw b/chirpw
index a3a316c..b11ab0f 100755
--- a/chirpw
+++ b/chirpw
@@ -17,8 +17,9 @@
import os
+from chirp import logger
from chirp import elib_intl
-from chirp import platform, CHIRP_VERSION
+from chirp import platform
from chirpui import config
# Hack to setup environment
@@ -40,10 +41,6 @@ elif not os.isatty(0):
sys.stdout = log
sys.stderr = log
-print "CHIRP %s on %s (Python %s)" % (CHIRP_VERSION,
- platform.get_platform().os_version_string(),
- sys.version.split()[0])
-
execpath = platform.get_platform().executable_path()
localepath = os.path.abspath(os.path.join(execpath, "locale"))
if not os.path.exists(localepath):
@@ -127,10 +124,14 @@ from chirpui import mainapp, config
parser = argparse.ArgumentParser()
parser.add_argument("files", metavar="file", nargs='*', help="File to open")
+logger.add_version_argument(parser)
parser.add_argument("--profile", action="store_true",
help="Enable profiling")
+logger.add_arguments(parser)
args = parser.parse_args()
+logger.handle_options(args)
+
a = mainapp.ChirpMain()
for i in args.files:
More information about the chirp_devel
mailing list