@@ -1694,6 +1694,9 @@ When the above script is run, it prints::
16941694Note that the order of items might be different according to the version of
16951695Python used.
16961696
1697+
1698+ .. _custom-handlers :
1699+
16971700.. currentmodule :: logging.config
16981701
16991702Customizing handlers with :func: `dictConfig `
@@ -1948,3 +1951,87 @@ handler. So the only slightly unusual thing which might trip you up is that the
19481951parentheses go around the format string and the arguments, not just the format
19491952string. That’s because the __ notation is just syntax sugar for a constructor
19501953call to one of the ``XXXMessage `` classes shown above.
1954+
1955+
1956+ .. _filters-dictconfig :
1957+
1958+ .. currentmodule :: logging.config
1959+
1960+ Configuring filters with :func: `dictConfig `
1961+ -------------------------------------------
1962+
1963+ You *can * configure filters using :func: `~logging.config.dictConfig `, though it
1964+ might not be obvious at first glance how to do it (hence this recipe). Since
1965+ :class: `~logging.Filter ` is the only filter class included in the standard
1966+ library, and it is unlikely to cater to many requirements (it's only there as a
1967+ base class), you will typically need to define your own :class: `~logging.Filter `
1968+ subclass with an overridden :meth: `~logging.Filter.filter ` method. To do this,
1969+ specify the ``() `` key in the configuration dictionary for the filter,
1970+ specifying a callable which will be used to create the filter (a class is the
1971+ most obvious, but you can provide any callable which returns a
1972+ :class: `~logging.Filter ` instance). Here is a complete example::
1973+
1974+ import logging
1975+ import logging.config
1976+ import sys
1977+
1978+ class MyFilter(logging.Filter):
1979+ def __init__(self, param=None):
1980+ self.param = param
1981+
1982+ def filter(self, record):
1983+ if self.param is None:
1984+ allow = True
1985+ else:
1986+ allow = self.param not in record.msg
1987+ if allow:
1988+ record.msg = 'changed: ' + record.msg
1989+ return allow
1990+
1991+ LOGGING = {
1992+ 'version': 1,
1993+ 'filters': {
1994+ 'myfilter': {
1995+ '()': MyFilter,
1996+ 'param': 'noshow',
1997+ }
1998+ },
1999+ 'handlers': {
2000+ 'console': {
2001+ 'class': 'logging.StreamHandler',
2002+ 'filters': ['myfilter']
2003+ }
2004+ },
2005+ 'root': {
2006+ 'level': 'DEBUG',
2007+ 'handlers': ['console']
2008+ },
2009+ }
2010+
2011+ if __name__ == '__main__':
2012+ logging.config.dictConfig(LOGGING)
2013+ logging.debug('hello')
2014+ logging.debug('hello - noshow')
2015+
2016+ This example shows how you can pass configuration data to the callable which
2017+ constructs the instance, in the form of keyword parameters. When run, the above
2018+ script will print::
2019+
2020+ changed: hello
2021+
2022+ which shows that the filter is working as configured.
2023+
2024+ A couple of extra points to note:
2025+
2026+ * If you can't refer to the callable directly in the configuration (e.g. if it
2027+ lives in a different module, and you can't import it directly where the
2028+ configuration dictionary is), you can use the form ``ext://... `` as described
2029+ in :ref: `logging-config-dict-externalobj `. For example, you could have used
2030+ the text ``'ext://__main__.MyFilter' `` instead of ``MyFilter `` in the above
2031+ example.
2032+
2033+ * As well as for filters, this technique can also be used to configure custom
2034+ handlers and formatters. See :ref: `logging-config-dict-userdef ` for more
2035+ information on how logging supports using user-defined objects in its
2036+ configuration, and see the other cookbook recipe :ref: `custom-handlers ` above.
2037+
0 commit comments