msg171812 - (view) |
Author: Thomas Bach (thbach) |
Date: 2012-10-02 15:27 |
Currently logging.config provides a fileConfig function which reads a ini-style file via configparser.ConfigParser. I would like to have a function e.g. configParserConfig which accepts a ConfigParser instance and configures logging directly from the settings found in there. The main reasons for this are: 1) I think it is rather common for an application that provides an interface to configure its logging via an ini file to use this ini file also for further application configuration. With the current implementation the file is read twice and ConfigParser is initialized two times. 2) Currently it is not idiomatic how to alter an ini-file configuration e.g. by options passed in via command-line. The new function provides a clear solution: create a ConfigParser instance, parse the ini file, alter the configuration and pass it on to logging.config.configParserConfig. In fact, the new functionality is easy to achieve by refactoring logging.config a bit (see attached patch). |
|
|
msg171827 - (view) |
Author: Vinay Sajip (vinay.sajip) *  |
Date: 2012-10-02 19:23 |
Thanks for the suggestion - I'm sorry, but I'm not inclined to add this. My reasoning is as follows: 1. I want to encourage usage of the dictConfig() API, as fileConfig() does not cover as much of the logging API as dictConfig() does (for example, Filters). I'd like to minimise the maintenance I have to do for fileConfig()-related code, and would prefer not to add any auxiliary APIs around fileConfig(). 2. The file reading time and ConfigParser instantiation time are not likely to be a performance problem in practice, as logging configuration is an infrequent operation (a one-off operation in most cases). 3. You can also pass in a file-like object rather than a filename, and in that case, fileConfig() will use readfp() if available. While you might have to seek to the beginning of the file to pass it to another ConfigParser instance, that is likely to be just a pointer adjustment in a buffer rather than actual disk I/O (config files are usually pretty small). I hope you will agree. I'll leave the issue as pending for now, and close it in a day or two. |
|
|
msg171828 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2012-10-02 19:31 |
Vinay, you missed one use case in his request: reading the program's configuration, *modifying it* (based on command line args), and then passing it to logging. How would you suggest he handle that use case? Is there an easy way to get from a loaded configuration file to a dictionary for use in dictConfig? |
|
|
msg171996 - (view) |
Author: Thomas Bach (thbach) |
Date: 2012-10-04 21:11 |
vinay: I understand your preference of dictConfig over fileConfig as maintainer. But as an application developer I want to provide my user an easy way to adjust logging herself. In the end of the day she is the one knowing what has to be logged in which place. Therefor, having something like fileConfig is essential. david: The modified configuration can be passed to fileConfig via a StringIO instance. The downside is that ConfigParser instances with e.g. 'allow_no_value' set to True are currently difficult to handle – e.g.: >>> sys.version '3.2.3 (default, Jun 25 2012, 23:10:56) \n[GCC 4.7.1]' >>> cp = configparser.ConfigParser(allow_no_value=True) >>> cp.read_string('[foo]\nbar') >>> buf = io.StringIO() >>> cp.write(buf) >>> buf.seek(0) 0 >>> logging.config.fileConfig(buf) --------------------------------------------------------------------------- ParsingError Traceback (most recent call last) in () ----> 1 logging.config.fileConfig(buf) /usr/lib/python3.2/logging/config.py in fileConfig(fname, defaults, disable_existing_loggers) 64 cp = configparser.ConfigParser(defaults) 65 if hasattr(fname, 'readline'): ---> 66 cp.read_file(fname) 67 else: 68 cp.read(fname) /usr/lib/python3.2/configparser.py in read_file(self, f, source) 706 except AttributeError: 707 source = '' --> 708 self._read(f, source) 709 710 def read_string(self, string, source=''): /usr/lib/python3.2/configparser.py in _read(self, fp, fpname) 1079 # if any parsing errors occurred, raise an exception 1080 if e: -> 1081 raise e 1082 self._join_multiline_values() 1083 ParsingError: Source contains parsing errors: [line 2]: 'bar\n' Hence, logging.config.fileConfig should at least provide a way to pass in arguments for the ConfigParser initialization. Anyways, I think it is much cleaner to provide a function which gets the configuration directly from the ConfigParser instance. |
|
|
msg172015 - (view) |
Author: Vinay Sajip (vinay.sajip) *  |
Date: 2012-10-04 22:50 |
I could consider relaxing the parameters on fileConfig such that instead of accepting just a string or a file-like object, it additionally accepts a ConfigParser instance. More specifically: def fileConfig(file_or_fname_or_cp, defaults=None): if isinstance(file_or_fname_or_cp, RawConfigParser): cp = file_or_filename_or_cp else: cp = ConfigParser.ConfigParser(defaults) if hasattr(cp, 'readfp') and\ hasattr(file_or_fname_or_cp, 'readline'): cp.readfp(file_or_fname_or_cp) else: cp.read(file_or_fname_or_cp) formatters = _create_formatters(cp) This will only require (in addition to the above) small tweaks to docs and tests. It would appear to fit the bill for your use case. Do you agree? |
|
|
msg172193 - (view) |
Author: Thomas Bach (thbach) |
Date: 2012-10-06 12:56 |
Yeah, the change you suggest sounds reasonable. Thanks for reconsidering the case! |
|
|
msg172459 - (view) |
Author: Roundup Robot (python-dev)  |
Date: 2012-10-09 08:06 |
New changeset ce0d0d052494 by Vinay Sajip in branch 'default': Closes #16110: fileConfig now accepts a pre-initialised ConfigParser instance. http://hg.python.org/cpython/rev/ce0d0d052494 |
|
|
msg213103 - (view) |
Author: Roundup Robot (python-dev)  |
Date: 2014-03-10 22:11 |
New changeset 113341605247 by R David Murray in branch 'default': whatsnew: logging.fileConfig accepts ConfigParser instances. (#16110) http://hg.python.org/cpython/rev/113341605247 |
|
|