Marc Abramowitz added the comment:

Some more info on the logging example I gave.

So here is a program called `my_app.py`:

```
import os
import logging.config

logging.config.fileConfig('logging.ini', defaults=os.environ)
logger = logging.getLogger(__name__)
logger.debug('debug msg')
logger.info('info msg')
logger.warn('warn msg')
logger.error('error msg')
root_logger = logging.getLogger()
print('root_logger.level = %d; logging.WARN = %d; logging.DEBUG = %d'
      % (root_logger.level, logging.WARN, logging.DEBUG))
```

Note that it calls logging.config.fileConfig with defaults=os.environ so that 
environment variables can be used to affect the logging configuration.


And here is `logging.ini`:

```
###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
###

[loggers]
keys = root, fakeproject, sqlalchemy

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = %(logging_logger_root_level)s
handlers = console

[logger_fakeproject]
level = DEBUG
handlers =
qualname = fakeproject

[logger_sqlalchemy]
level = INFO
handlers =
qualname = sqlalchemy.engine
# "level = INFO" logs SQL queries.
# "level = DEBUG" logs SQL queries and results.
# "level = WARN" logs neither.  (Recommended for production systems.)

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] 
%(message)s
```

Note that in the `logger_root` section of `logging.ini`, the variable 
`logging_logger_root_level` is referenced but not defined. For now, we are 
going to rely on getting that from an environment variable.


If I provide an environment variable when running the program:

```
$ LOGGING_LOGGER_ROOT_LEVEL=DEBUG python my_app.py
2016-04-07 08:26:36,184 DEBUG [__main__:6][MainThread] debug msg
2016-04-07 08:26:36,184 INFO  [__main__:7][MainThread] info msg
2016-04-07 08:26:36,184 WARNI [__main__:8][MainThread] warn msg
2016-04-07 08:26:36,184 ERROR [__main__:9][MainThread] error msg
root_logger.level = 10; logging.WARN = 30; logging.DEBUG = 10
```

then it works and the root logger level is DEBUG as expected. Great!

But what happens if the user leaves out the environment variable?

```
$ python my_app.py
Traceback (most recent call last):
  File "my_app.py", line 4, in <module>
    logging.config.fileConfig('logging.ini', defaults=os.environ)
  File 
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/config.py",
 line 86, in fileConfig
    _install_loggers(cp, handlers, disable_existing_loggers)
  File 
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/config.py",
 line 196, in _install_loggers
    level = cp.get(sectname, "level")
  File 
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ConfigParser.py",
 line 623, in get
    return self._interpolate(section, option, value, d)
  File 
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ConfigParser.py",
 line 669, in _interpolate
    option, section, rawval, e.args[0])
ConfigParser.InterpolationMissingOptionError: Bad value substitution:
        section: [logger_root]
        option : level
        key    : logging_logger_root_level
        rawval : %(logging_logger_root_level)s
```

An error occurs as expected. 

But I'd like to be able to provide a default value so that user doesn't have to 
set the environment variable, so let's add this to the top of `logging.ini`:

```
[DEFAULT]
logging_logger_root_level = WARN
```

Now let's run the program again without the environment variable to see if that 
fixed the problem:

```
$ python my_app.py
2016-04-07 08:33:07,101 WARNI [__main__:8][MainThread] warn msg
2016-04-07 08:33:07,101 ERROR [__main__:9][MainThread] error msg
root_logger.level = 30; logging.WARN = 30; logging.DEBUG = 10
```

Awesome! It worked and set the root logger level to the default of WARN, as 
expected.

Now what happens if we try to override the default with an environment variable?

```
$ LOGGING_LOGGER_ROOT_LEVEL=DEBUG python my_app.py
2016-04-07 08:33:56,047 WARNI [__main__:8][MainThread] warn msg
2016-04-07 08:33:56,048 ERROR [__main__:9][MainThread] error msg
root_logger.level = 30; logging.WARN = 30; logging.DEBUG = 10
```

Doh! The root logger level is still WARN. So the default in the ini file took 
precedence over what the user provided. This is unfortunate.

So how does one provide defaults while also allowing overriding those defaults?

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue26710>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to